summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components/MkPostForm.vue
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/components/MkPostForm.vue')
-rw-r--r--packages/frontend/src/components/MkPostForm.vue40
1 files changed, 18 insertions, 22 deletions
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 689884f653..ea7072df4d 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -66,12 +66,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
<div v-show="useCw" :class="$style.cwFrame">
- <input ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown">
+ <input ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown" @keyup="onKeyUp" @compositionend="onCompositionEnd">
<div v-if="maxCwLength - cwLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: cwLength > maxCwLength }]">{{ maxCwLength - cwLength }}</div>
</div>
<div :class="[$style.textOuter, { [$style.withCw]: useCw }]">
<div v-if="channel" :class="$style.colorBar" :style="{ background: channel.color }"></div>
- <textarea ref="textareaEl" v-model="text" :class="[$style.text]" :disabled="posting || posted" :readonly="textAreaReadOnly" :placeholder="placeholder" data-cy-post-form-text dir="auto" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
+ <textarea ref="textareaEl" v-model="text" :class="[$style.text]" :disabled="posting || posted" :readonly="textAreaReadOnly" :placeholder="placeholder" data-cy-post-form-text dir="auto" @keydown="onKeydown" @keyup="onKeyUp" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
<div v-if="maxTextLength - textLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: textLength > maxTextLength }]">{{ maxTextLength - textLength }}</div>
</div>
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
@@ -133,25 +133,13 @@ import { miLocalStorage } from '@/local-storage.js';
import { claimAchievement } from '@/scripts/achievements.js';
import { emojiPicker } from '@/scripts/emoji-picker.js';
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
+import type { PostFormProps } from '@/types/post-form.js';
const $i = signinRequired();
const modal = inject('modal');
-const props = withDefaults(defineProps<{
- reply?: Misskey.entities.Note;
- renote?: Misskey.entities.Note;
- channel?: Misskey.entities.Channel; // TODO
- mention?: Misskey.entities.User;
- specified?: Misskey.entities.UserDetailed;
- initialText?: string;
- initialCw?: string;
- initialVisibility?: (typeof Misskey.noteVisibilities)[number];
- initialFiles?: Misskey.entities.DriveFile[];
- initialLocalOnly?: boolean;
- initialVisibleUsers?: Misskey.entities.UserDetailed[];
- initialNote?: Misskey.entities.Note;
- instant?: boolean;
+const props = withDefaults(defineProps<PostFormProps & {
fixed?: boolean;
autofocus?: boolean;
freezeAfterPosted?: boolean;
@@ -206,6 +194,7 @@ const recentHashtags = ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'
const imeText = ref('');
const showingOptions = ref(false);
const textAreaReadOnly = ref(false);
+const justEndedComposition = ref(false);
const draftKey = computed((): string => {
let key = props.channel ? `channel:${props.channel.id}` : '';
@@ -591,7 +580,13 @@ function clear() {
function onKeydown(ev: KeyboardEvent) {
if (ev.key === 'Enter' && (ev.ctrlKey || ev.metaKey) && canPost.value) post();
- if (ev.key === 'Escape') emit('esc');
+ // justEndedComposition.value is for Safari, which keyDown occurs after compositionend.
+ // ev.isComposing is for another browsers.
+ if (ev.key === 'Escape' && !justEndedComposition.value && !ev.isComposing) emit('esc');
+}
+
+function onKeyup(ev: KeyboardEvent) {
+ justEndedComposition.value = false;
}
function onCompositionUpdate(ev: CompositionEvent) {
@@ -600,6 +595,7 @@ function onCompositionUpdate(ev: CompositionEvent) {
function onCompositionEnd(ev: CompositionEvent) {
imeText.value = '';
+ justEndedComposition.value = true;
}
async function onPaste(ev: ClipboardEvent) {
@@ -1002,8 +998,8 @@ function showActions(ev: MouseEvent) {
action.handler({
text: text.value,
cw: cw.value,
- }, (key, value: any) => {
- if (typeof key !== 'string') return;
+ }, (key, value) => {
+ if (typeof key !== 'string' || typeof value !== 'string') return;
if (key === 'text') { text.value = value; }
if (key === 'cw') { useCw.value = value !== null; cw.value = value; }
});
@@ -1174,7 +1170,7 @@ defineExpose({
&:focus-visible {
outline: none;
- .submitInner {
+ > .submitInner {
outline: 2px solid var(--MI_THEME-fgOnAccent);
outline-offset: -4px;
}
@@ -1189,13 +1185,13 @@ defineExpose({
}
&:not(:disabled):hover {
- > .inner {
+ > .submitInner {
background: linear-gradient(90deg, hsl(from var(--MI_THEME-accent) h s calc(l + 5)), hsl(from var(--MI_THEME-accent) h s calc(l + 5)));
}
}
&:not(:disabled):active {
- > .inner {
+ > .submitInner {
background: linear-gradient(90deg, hsl(from var(--MI_THEME-accent) h s calc(l + 5)), hsl(from var(--MI_THEME-accent) h s calc(l + 5)));
}
}