renamed StatusText to StatusBody for clarity, fixed chats

This commit is contained in:
Henry Jameson 2021-06-07 19:50:26 +03:00
parent 50aa379038
commit 8e9f5d7580
17 changed files with 316 additions and 225 deletions

View file

@ -1,5 +1,5 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import StatusContent from '../status_content/status_content.vue' import StatusBody from '../status_content/status_content.vue'
import fileType from 'src/services/file_type/file_type.service' import fileType from 'src/services/file_type/file_type.service'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import AvatarList from '../avatar_list/avatar_list.vue' import AvatarList from '../avatar_list/avatar_list.vue'
@ -16,7 +16,7 @@ const ChatListItem = {
AvatarList, AvatarList,
Timeago, Timeago,
ChatTitle, ChatTitle,
StatusContent StatusBody
}, },
computed: { computed: {
...mapState({ ...mapState({
@ -38,12 +38,15 @@ const ChatListItem = {
}, },
messageForStatusContent () { messageForStatusContent () {
const message = this.chat.lastMessage const message = this.chat.lastMessage
const messageEmojis = message ? message.emojis : []
const isYou = message && message.account_id === this.currentUser.id const isYou = message && message.account_id === this.currentUser.id
const content = message ? (this.attachmentInfo || message.content) : '' const content = message ? (this.attachmentInfo || message.content_raw) : ''
const messagePreview = isYou ? `<i>${this.$t('chats.you')}</i> ${content}` : content const messagePreview = isYou ? `<i>${this.$t('chats.you')}</i> ${content}` : content
return { return {
summary: '', summary: '',
emojis: messageEmojis,
statusnet_html: messagePreview, statusnet_html: messagePreview,
raw_html: messagePreview,
text: messagePreview, text: messagePreview,
attachments: [] attachments: []
} }

View file

@ -77,18 +77,15 @@
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
} }
.StatusContent { .chat-preview-body {
img.emoji { --emoji-size: 1.4em;
width: 1.4em;
height: 1.4em;
}
} }
.time-wrapper { .time-wrapper {
line-height: 1.4em; line-height: 1.4em;
} }
.single-line { .chat-preview-body {
padding-right: 1em; padding-right: 1em;
} }
} }

View file

@ -29,7 +29,8 @@
</div> </div>
</div> </div>
<div class="chat-preview"> <div class="chat-preview">
<StatusContent <StatusBody
class="chat-preview-body"
:status="messageForStatusContent" :status="messageForStatusContent"
:single-line="true" :single-line="true"
/> />

View file

@ -57,6 +57,8 @@ const ChatMessage = {
messageForStatusContent () { messageForStatusContent () {
return { return {
summary: '', summary: '',
emojis: this.message.emojis,
raw_html: this.message.content_raw,
statusnet_html: this.message.content, statusnet_html: this.message.content,
text: this.message.content, text: this.message.content,
attachments: this.message.attachments attachments: this.message.attachments

View file

@ -89,8 +89,9 @@
} }
.without-attachment { .without-attachment {
.status-content { .message-content {
&::after { // TODO figure out how to do it properly
.text::after {
margin-right: 5.4em; margin-right: 5.4em;
content: " "; content: " ";
display: inline-block; display: inline-block;
@ -162,6 +163,7 @@
.visible { .visible {
opacity: 1; opacity: 1;
} }
} }
.chat-message-date-separator { .chat-message-date-separator {

View file

@ -71,6 +71,7 @@
</Popover> </Popover>
</div> </div>
<StatusContent <StatusContent
class="message-content"
:status="messageForStatusContent" :status="messageForStatusContent"
:full-content="true" :full-content="true"
> >

View file

@ -474,7 +474,7 @@ export default {
this.loadThemeFromLocalStorage(false, true) this.loadThemeFromLocalStorage(false, true)
break break
case 'file': case 'file':
console.err('Forcing snapshout from file is not supported yet') console.error('Forcing snapshout from file is not supported yet')
break break
} }
this.dismissWarning() this.dismissWarning()

View file

@ -89,7 +89,10 @@
v-if="retweeterHtml" v-if="retweeterHtml"
:to="retweeterProfileLink" :to="retweeterProfileLink"
> >
<RichContent :html="retweeterHtml" :emoji="retweeterUser.emoji"/> <RichContent
:html="retweeterHtml"
:emoji="retweeterUser.emoji"
/>
</router-link> </router-link>
<router-link <router-link
v-else v-else
@ -146,7 +149,10 @@
class="status-username" class="status-username"
:title="status.user.name" :title="status.user.name"
> >
<RichContent :html="status.user.name" :emoji="status.user.emoji" /> <RichContent
:html="status.user.name"
:emoji="status.user.emoji"
/>
</h4> </h4>
<h4 <h4
v-else v-else

View file

@ -94,7 +94,7 @@ const StatusContent = {
return html return html
} }
} catch (e) { } catch (e) {
console.err('Failed to process status html', e) console.error('Failed to process status html', e)
return html return html
} }
} else { } else {
@ -104,13 +104,13 @@ const StatusContent = {
attachmentTypes () { attachmentTypes () {
return this.status.attachments.map(file => fileType.fileType(file.mimetype)) return this.status.attachments.map(file => fileType.fileType(file.mimetype))
}, },
...mapGetters(['mergedConfig']), ...mapGetters(['mergedConfig'])
}, },
components: { components: {
RichContent RichContent
}, },
mounted () { mounted () {
this.status.attentions.forEach(attn => { this.status.attentions && this.status.attentions.forEach(attn => {
const { id } = attn const { id } = attn
this.$store.dispatch('fetchUserIfMissing', id) this.$store.dispatch('fetchUserIfMissing', id)
}) })

View file

@ -0,0 +1,112 @@
@import '../../_variables.scss';
.StatusBody {
.emoji {
--_still_image-label-scale: 0.5;
}
.summary {
display: block;
font-style: italic;
padding-bottom: 0.5em;
}
.text {
&.-single-line {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: 1.4em;
}
}
.summary-wrapper {
margin-bottom: 0.5em;
border-style: solid;
border-width: 0 0 1px 0;
border-color: var(--border, $fallback--border);
flex-grow: 0;
&.-tall {
position: relative;
.summary {
max-height: 2em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
.text-wrapper {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
&.-tall-status {
position: relative;
height: 220px;
overflow-x: hidden;
overflow-y: hidden;
z-index: 1;
.text {
min-height: 0;
mask:
linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat,
linear-gradient(to top, white, white);
/* Autoprefixed seem to ignore this one, and also syntax is different */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
}
}
& .tall-status-hider,
& .tall-subject-hider,
& .status-unhider,
& .cw-status-hider {
display: inline-block;
word-break: break-all;
width: 100%;
text-align: center;
}
.tall-status-hider {
position: absolute;
height: 70px;
margin-top: 150px;
line-height: 110px;
z-index: 2;
}
.tall-subject-hider {
// position: absolute;
padding-bottom: 0.5em;
}
& .status-unhider,
& .cw-status-hider {
word-break: break-all;
svg {
color: inherit;
}
}
.greentext {
color: $fallback--cGreen;
color: var(--postGreentext, $fallback--cGreen);
}
/* Not sure if this is necessary */
video {
max-width: 100%;
max-height: 400px;
vertical-align: middle;
object-fit: contain;
}
}

View file

@ -0,0 +1,95 @@
<template>
<div class="StatusBody">
<div class="body">
<div
v-if="status.summary_html"
class="summary-wrapper"
:class="{ '-tall': (longSubject && !showingLongSubject) }"
>
<RichContent
class="media-body summary"
:html="status.summary_raw_html"
:emoji="status.emojis"
@click.prevent="linkClicked"
/>
<button
v-if="longSubject && showingLongSubject"
class="button-unstyled -link tall-subject-hider"
@click.prevent="showingLongSubject=false"
>
{{ $t("status.hide_full_subject") }}
</button>
<button
v-else-if="longSubject"
class="button-unstyled -link tall-subject-hider"
@click.prevent="showingLongSubject=true"
>
{{ $t("status.show_full_subject") }}
</button>
</div>
<div
:class="{'-tall-status': hideTallStatus}"
class="text-wrapper"
>
<button
v-if="hideTallStatus"
class="button-unstyled -link tall-status-hider"
:class="{ '-focused': focused }"
@click.prevent="toggleShowMore"
>
{{ $t("general.show_more") }}
</button>
<RichContent
v-if="!hideSubjectStatus && !(singleLine && status.summary_html)"
:class="{ '-single-line': singleLine }"
class="text media-body"
:html="postBodyHtml"
:emoji="status.emojis"
:handle-links="true"
@click.prevent="linkClicked"
/>
<button
v-if="hideSubjectStatus"
class="button-unstyled -link cw-status-hider"
@click.prevent="toggleShowMore"
>
{{ $t("status.show_content") }}
<FAIcon
v-if="attachmentTypes.includes('image')"
icon="image"
/>
<FAIcon
v-if="attachmentTypes.includes('video')"
icon="video"
/>
<FAIcon
v-if="attachmentTypes.includes('audio')"
icon="music"
/>
<FAIcon
v-if="attachmentTypes.includes('unknown')"
icon="file"
/>
<FAIcon
v-if="status.poll && status.poll.options"
icon="poll-h"
/>
<FAIcon
v-if="status.card"
icon="link"
/>
</button>
<button
v-if="showingMore && !fullContent"
class="button-unstyled -link status-unhider"
@click.prevent="toggleShowMore"
>
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
</button>
</div>
</div>
<slot v-if="!hideSubjectStatus" />
</div>
</template>
<script src="./status_body.js" ></script>
<style lang="scss" src="./status_body.scss" />

View file

@ -1,7 +1,7 @@
import Attachment from '../attachment/attachment.vue' import Attachment from '../attachment/attachment.vue'
import Poll from '../poll/poll.vue' import Poll from '../poll/poll.vue'
import Gallery from '../gallery/gallery.vue' import Gallery from '../gallery/gallery.vue'
import StatusText from 'src/components/status_text/status_text.vue' import StatusBody from 'src/components/status_body/status_body.vue'
import LinkPreview from '../link-preview/link-preview.vue' import LinkPreview from '../link-preview/link-preview.vue'
import fileType from 'src/services/file_type/file_type.service' import fileType from 'src/services/file_type/file_type.service'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
@ -88,7 +88,7 @@ const StatusContent = {
Poll, Poll,
Gallery, Gallery,
LinkPreview, LinkPreview,
StatusText StatusBody
}, },
methods: { methods: {
setMedia () { setMedia () {

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="StatusContent"> <div class="StatusContent">
<slot name="header" /> <slot name="header" />
<StatusText :status="status"> <StatusBody :status="status" :single-line="singleLine">
<div v-if="status.poll && status.poll.options"> <div v-if="status.poll && status.poll.options">
<poll :base-poll="status.poll" /> <poll :base-poll="status.poll" />
</div> </div>
@ -40,7 +40,7 @@
:nsfw="nsfwClickthrough" :nsfw="nsfwClickthrough"
/> />
</div> </div>
</StatusText> </StatusBody>
<slot name="footer" /> <slot name="footer" />
</div> </div>
</template> </template>
@ -54,103 +54,5 @@ $status-margin: 0.75em;
.StatusContent { .StatusContent {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
.status-content-wrapper {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
}
.tall-status {
position: relative;
height: 220px;
overflow-x: hidden;
overflow-y: hidden;
z-index: 1;
.status-content {
min-height: 0;
mask: linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat,
linear-gradient(to top, white, white);
/* Autoprefixed seem to ignore this one, and also syntax is different */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
}
.tall-status-hider {
display: inline-block;
word-break: break-all;
position: absolute;
height: 70px;
margin-top: 150px;
width: 100%;
text-align: center;
line-height: 110px;
z-index: 2;
}
.status-unhider, .cw-status-hider {
width: 100%;
text-align: center;
display: inline-block;
word-break: break-all;
svg {
color: inherit;
}
}
video {
max-width: 100%;
max-height: 400px;
vertical-align: middle;
object-fit: contain;
}
.summary-wrapper {
margin-bottom: 0.5em;
border-style: solid;
border-width: 0 0 1px 0;
border-color: var(--border, $fallback--border);
flex-grow: 0;
}
.summary {
font-style: italic;
padding-bottom: 0.5em;
}
.tall-subject {
position: relative;
.summary {
max-height: 2em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.tall-subject-hider {
display: inline-block;
word-break: break-all;
// position: absolute;
width: 100%;
text-align: center;
padding-bottom: 0.5em;
}
.status-content {
&.single-line {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: 1.4em;
}
}
}
.greentext {
color: $fallback--cGreen;
color: var(--postGreentext, $fallback--cGreen);
} }
</style> </style>

View file

@ -1,95 +0,0 @@
<template>
<div class="StatusText">
<div
v-if="status.summary_html"
class="summary-wrapper"
:class="{ 'tall-subject': (longSubject && !showingLongSubject) }"
>
<RichContent
class="media-body summary"
:html="status.summary_raw_html"
:emoji="status.emojis"
@click.prevent="linkClicked"
/>
<button
v-if="longSubject && showingLongSubject"
class="button-unstyled -link tall-subject-hider"
@click.prevent="showingLongSubject=false"
>
{{ $t("status.hide_full_subject") }}
</button>
<button
v-else-if="longSubject"
class="button-unstyled -link tall-subject-hider"
:class="{ 'tall-subject-hider_focused': focused }"
@click.prevent="showingLongSubject=true"
>
{{ $t("status.show_full_subject") }}
</button>
</div>
<div
:class="{'tall-status': hideTallStatus}"
class="status-content-wrapper"
>
<button
v-if="hideTallStatus"
class="button-unstyled -link tall-status-hider"
:class="{ 'tall-status-hider_focused': focused }"
@click.prevent="toggleShowMore"
>
{{ $t("general.show_more") }}
</button>
<RichContent
v-if="!hideSubjectStatus"
:class="{ 'single-line': singleLine }"
class="status-content media-body"
:html="postBodyHtml"
:emoji="status.emojis"
:handleLinks="true"
@click.prevent="linkClicked"
/>
<button
v-if="hideSubjectStatus"
class="button-unstyled -link cw-status-hider"
@click.prevent="toggleShowMore"
>
{{ $t("status.show_content") }}
<FAIcon
v-if="attachmentTypes.includes('image')"
icon="image"
/>
<FAIcon
v-if="attachmentTypes.includes('video')"
icon="video"
/>
<FAIcon
v-if="attachmentTypes.includes('audio')"
icon="music"
/>
<FAIcon
v-if="attachmentTypes.includes('unknown')"
icon="file"
/>
<FAIcon
v-if="status.poll && status.poll.options"
icon="poll-h"
/>
<FAIcon
v-if="status.card"
icon="link"
/>
</button>
<button
v-if="showingMore && !fullContent"
class="button-unstyled -link status-unhider"
@click.prevent="toggleShowMore"
>
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
</button>
</div>
<div v-if="!hideSubjectStatus">
<slot/>
</div>
</div>
</template>
<script src="./status_text.js" ></script>

View file

@ -448,6 +448,8 @@ export const parseChatMessage = (message) => {
output.id = message.id output.id = message.id
output.created_at = new Date(message.created_at) output.created_at = new Date(message.created_at)
output.chat_id = message.chat_id output.chat_id = message.chat_id
output.emojis = message.emojis
output.content_raw = message.content
if (message.content) { if (message.content) {
output.content = addEmojis(message.content, message.emojis) output.content = addEmojis(message.content, message.emojis)
} else { } else {

View file

@ -1,6 +1,6 @@
/** /**
* This is a not-so-tiny purpose-built HTML parser/processor. It was made for use * This is a not-so-tiny purpose-built HTML parser/processor. It was made for use
* with StatusText component for purpose of replacing tags with vue components * with StatusBody component for purpose of replacing tags with vue components
* *
* known issue: doesn't handle CDATA so nested CDATA might not work well * known issue: doesn't handle CDATA so nested CDATA might not work well
* *

View file

@ -1011,23 +1011,86 @@
resolved "https://registry.yarnpkg.com/@ungap/event-target/-/event-target-0.1.0.tgz#88d527d40de86c4b0c99a060ca241d755999915b" resolved "https://registry.yarnpkg.com/@ungap/event-target/-/event-target-0.1.0.tgz#88d527d40de86c4b0c99a060ca241d755999915b"
integrity sha512-W2oyj0Fe1w/XhPZjkI3oUcDUAmu5P4qsdT2/2S8aMhtAWM/CE/jYWtji0pKNPDfxLI75fa5gWSEmnynKMNP/oA== integrity sha512-W2oyj0Fe1w/XhPZjkI3oUcDUAmu5P4qsdT2/2S8aMhtAWM/CE/jYWtji0pKNPDfxLI75fa5gWSEmnynKMNP/oA==
"@vue/babel-helper-vue-jsx-merge-props@^1.0.0": "@vue/babel-helper-vue-jsx-merge-props@^1.2.1":
version "1.0.0" version "1.2.1"
resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040" resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz#31624a7a505fb14da1d58023725a4c5f270e6a81"
integrity sha512-6tyf5Cqm4m6v7buITuwS+jHzPlIPxbFzEhXR5JGZpbrvOcp1hiQKckd305/3C7C36wFekNTQSxAtgeM0j0yoUw== integrity sha512-QOi5OW45e2R20VygMSNhyQHvpdUwQZqGPc748JLGCYEy+yp8fNFNdbNIGAgZmi9e+2JHPd6i6idRuqivyicIkA==
"@vue/babel-plugin-transform-vue-jsx@^1.1.2": "@vue/babel-plugin-transform-vue-jsx@^1.2.1":
version "1.1.2" version "1.2.1"
resolved "https://registry.yarnpkg.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.1.2.tgz#c0a3e6efc022e75e4247b448a8fc6b86f03e91c0" resolved "https://registry.yarnpkg.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.2.1.tgz#646046c652c2f0242727f34519d917b064041ed7"
integrity sha512-YfdaoSMvD1nj7+DsrwfTvTnhDXI7bsuh+Y5qWwvQXlD24uLgnsoww3qbiZvWf/EoviZMrvqkqN4CBw0W3BWUTQ== integrity sha512-HJuqwACYehQwh1fNT8f4kyzqlNMpBuUK4rSiSES5D4QsYncv5fxFsLyrxFPG2ksO7t5WP+Vgix6tt6yKClwPzA==
dependencies: dependencies:
"@babel/helper-module-imports" "^7.0.0" "@babel/helper-module-imports" "^7.0.0"
"@babel/plugin-syntax-jsx" "^7.2.0" "@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-helper-vue-jsx-merge-props" "^1.0.0" "@vue/babel-helper-vue-jsx-merge-props" "^1.2.1"
html-tags "^2.0.0" html-tags "^2.0.0"
lodash.kebabcase "^4.1.1" lodash.kebabcase "^4.1.1"
svg-tags "^1.0.0" svg-tags "^1.0.0"
"@vue/babel-preset-jsx@^1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.2.4.tgz#92fea79db6f13b01e80d3a0099e2924bdcbe4e87"
integrity sha512-oRVnmN2a77bYDJzeGSt92AuHXbkIxbf/XXSE3klINnh9AXBmVS1DGa1f0d+dDYpLfsAKElMnqKTQfKn7obcL4w==
dependencies:
"@vue/babel-helper-vue-jsx-merge-props" "^1.2.1"
"@vue/babel-plugin-transform-vue-jsx" "^1.2.1"
"@vue/babel-sugar-composition-api-inject-h" "^1.2.1"
"@vue/babel-sugar-composition-api-render-instance" "^1.2.4"
"@vue/babel-sugar-functional-vue" "^1.2.2"
"@vue/babel-sugar-inject-h" "^1.2.2"
"@vue/babel-sugar-v-model" "^1.2.3"
"@vue/babel-sugar-v-on" "^1.2.3"
"@vue/babel-sugar-composition-api-inject-h@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.2.1.tgz#05d6e0c432710e37582b2be9a6049b689b6f03eb"
integrity sha512-4B3L5Z2G+7s+9Bwbf+zPIifkFNcKth7fQwekVbnOA3cr3Pq71q71goWr97sk4/yyzH8phfe5ODVzEjX7HU7ItQ==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-sugar-composition-api-render-instance@^1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.2.4.tgz#e4cbc6997c344fac271785ad7a29325c51d68d19"
integrity sha512-joha4PZznQMsxQYXtR3MnTgCASC9u3zt9KfBxIeuI5g2gscpTsSKRDzWQt4aqNIpx6cv8On7/m6zmmovlNsG7Q==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-sugar-functional-vue@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.2.2.tgz#267a9ac8d787c96edbf03ce3f392c49da9bd2658"
integrity sha512-JvbgGn1bjCLByIAU1VOoepHQ1vFsroSA/QkzdiSs657V79q6OwEWLCQtQnEXD/rLTA8rRit4rMOhFpbjRFm82w==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-sugar-inject-h@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.2.2.tgz#d738d3c893367ec8491dcbb669b000919293e3aa"
integrity sha512-y8vTo00oRkzQTgufeotjCLPAvlhnpSkcHFEp60+LJUwygGcd5Chrpn5480AQp/thrxVm8m2ifAk0LyFel9oCnw==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-sugar-v-model@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.2.3.tgz#fa1f29ba51ebf0aa1a6c35fa66d539bc459a18f2"
integrity sha512-A2jxx87mySr/ulAsSSyYE8un6SIH0NWHiLaCWpodPCVOlQVODCaSpiR4+IMsmBr73haG+oeCuSvMOM+ttWUqRQ==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-helper-vue-jsx-merge-props" "^1.2.1"
"@vue/babel-plugin-transform-vue-jsx" "^1.2.1"
camelcase "^5.0.0"
html-tags "^2.0.0"
svg-tags "^1.0.0"
"@vue/babel-sugar-v-on@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.2.3.tgz#342367178586a69f392f04bfba32021d02913ada"
integrity sha512-kt12VJdz/37D3N3eglBywV8GStKNUhNrsxChXIV+o0MwVXORYuhDTHJRKPgLJRb/EY3vM2aRFQdxJBp9CLikjw==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"
"@vue/babel-plugin-transform-vue-jsx" "^1.2.1"
camelcase "^5.0.0"
"@vue/test-utils@^1.0.0-beta.26": "@vue/test-utils@^1.0.0-beta.26":
version "1.0.0-beta.28" version "1.0.0-beta.28"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.28.tgz#767c43413df8cde86128735e58923803e444b9a5" resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.28.tgz#767c43413df8cde86128735e58923803e444b9a5"