Skip to content

Commit

Permalink
chore: add types on MkAutocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
anatawa12 committed Feb 18, 2024
1 parent b0030d1 commit e8ce14e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
55 changes: 43 additions & 12 deletions packages/frontend/src/components/MkAutocomplete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</li>
<li tabindex="-1" :class="$style.item" @click="chooseUser()" @keydown="onKeydown">{{ i18n.ts.selectUser }}</li>
</ol>
<ol v-else-if="hashtags.length > 0" ref="suggests" :class="$style.list">
<ol v-else-if="type === 'hashtag' && hashtags.length > 0" ref="suggests" :class="$style.list">
<li v-for="hashtag in hashtags" tabindex="-1" :class="$style.item" @click="complete(type, hashtag)" @keydown="onKeydown">
<span class="name">{{ hashtag }}</span>
</li>
</ol>
<ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list">
<ol v-else-if="type === 'emoji' && emojis.length > 0" ref="suggests" :class="$style.list">
<li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
<MkCustomEmoji v-if="'isCustomEmoji' in emoji && emoji.isCustomEmoji" :name="emoji.emoji" :class="$style.emoji"/>
<MkEmoji v-else :emoji="emoji.emoji" :class="$style.emoji"/>
Expand All @@ -30,12 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-if="emoji.aliasOf" :class="$style.emojiAlias">({{ emoji.aliasOf }})</span>
</li>
</ol>
<ol v-else-if="mfmTags.length > 0" ref="suggests" :class="$style.list">
<ol v-else-if="type === 'mfmTag' && mfmTags.length > 0" ref="suggests" :class="$style.list">
<li v-for="tag in mfmTags" tabindex="-1" :class="$style.item" @click="complete(type, tag)" @keydown="onKeydown">
<span>{{ tag }}</span>
</li>
</ol>
<ol v-else-if="mfmParams.length > 0" ref="suggests" :class="$style.list">
<ol v-else-if="type === 'mfmParam' && mfmParams.length > 0" ref="suggests" :class="$style.list">
<li v-for="param in mfmParams" tabindex="-1" :class="$style.item" @click="complete(type, q.params.toSpliced(-1, 1, param).join(','))" @keydown="onKeydown">
<span>{{ param }}</span>
</li>
Expand All @@ -58,6 +58,32 @@ import { miLocalStorage } from '@/local-storage.js';
import { customEmojis } from '@/custom-emojis.js';
import { MFM_TAGS, MFM_PARAMS } from '@/const.js';

export type CompleteInfo = {
user: {
payload: any;
query: string | null;
},
hashtag: {
payload: string;
query: string;
},
emoji: {
payload: string;
query: string;
},
mfmTag: {
payload: string;
query: string;
},
mfmParam: {
payload: string;
query: {
tag: string;
params: string[];
};
},
}

type EmojiDef = {
emoji: string;
name: string;
Expand Down Expand Up @@ -132,18 +158,23 @@ export default {
};
</script>

<script lang="ts" setup>
const props = defineProps<{
type: string;
q: any;
textarea: HTMLTextAreaElement;
<script lang="ts" setup generic="T extends keyof CompleteInfo">
type PropsType<T extends keyof CompleteInfo> = {
type: T;
q: CompleteInfo[T]['query'];
// なぜかわからないけど HTMLTextAreaElement | HTMLInputElement だと addEventListener/removeEventListenerがエラー
textarea: (HTMLTextAreaElement | HTMLInputElement) & HTMLElement;
close: () => void;
x: number;
y: number;
}>();
}
//const props = defineProps<PropsType<keyof CompleteInfo>>();
// ↑と同じだけど↓にしないとdiscriminated unionにならない。
// https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions
const props = defineProps<PropsType<'user'> | PropsType<'hashtag'> | PropsType<'emoji'> | PropsType<'mfmTag'> | PropsType<'mfmParam'>>();

const emit = defineEmits<{
(event: 'done', value: { type: string; value: any }): void;
<T extends keyof CompleteInfo>(event: 'done', value: { type: T; value: CompleteInfo[T]['payload'] }): void;
(event: 'closed'): void;
}>();

Expand All @@ -160,7 +191,7 @@ const mfmParams = ref<string[]>([]);
const select = ref(-1);
const zIndex = os.claimZIndex('high');

function complete(type: string, value: any) {
function complete<T extends keyof CompleteInfo>(type: T, value: CompleteInfo[T]['payload']) {
emit('done', { type, value });
emit('closed');
if (type === 'emoji') {
Expand Down
11 changes: 6 additions & 5 deletions packages/frontend/src/scripts/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { nextTick, Ref, ref, defineAsyncComponent } from 'vue';
import getCaretCoordinates from 'textarea-caret';
import { toASCII } from 'punycode/';
import type { CompleteInfo } from '@/components/MkAutocomplete.vue';
import { popup } from '@/os.js';

export type SuggestionType = 'user' | 'hashtag' | 'emoji' | 'mfmTag' | 'mfmParam';
Expand All @@ -18,7 +19,7 @@ export class Autocomplete {
close: () => void;
} | null;
private textarea: HTMLInputElement | HTMLTextAreaElement;
private currentType: string;
private currentType: keyof CompleteInfo | undefined;
private textRef: Ref<string | number | null>;
private opening: boolean;
private onlyType: SuggestionType[];
Expand Down Expand Up @@ -73,7 +74,7 @@ export class Autocomplete {
* テキスト入力時
*/
private onInput() {
const caretPos = this.textarea.selectionStart;
const caretPos = Number(this.textarea.selectionStart);
const text = this.text.substring(0, caretPos).split('\n').pop()!;

const mentionIndex = text.lastIndexOf('@');
Expand Down Expand Up @@ -155,7 +156,7 @@ export class Autocomplete {
/**
* サジェストを提示します。
*/
private async open(type: string, q: any) {
private async open<T extends keyof CompleteInfo>(type: T, q: CompleteInfo[T]['query']) {
if (type !== this.currentType) {
this.close();
}
Expand Down Expand Up @@ -222,10 +223,10 @@ export class Autocomplete {
/**
* オートコンプリートする
*/
private complete({ type, value }) {
private complete<T extends keyof CompleteInfo>({ type, value }: { type: T; value: CompleteInfo[T]['payload'] }) {
this.close();

const caret = this.textarea.selectionStart;
const caret = Number(this.textarea.selectionStart);

if (type === 'user') {
const source = this.text;
Expand Down

0 comments on commit e8ce14e

Please sign in to comment.