summaryrefslogtreecommitdiff
path: root/packages/frontend/src/utility/autocomplete.ts
diff options
context:
space:
mode:
authormisskey-release-bot[bot] <157398866+misskey-release-bot[bot]@users.noreply.github.com>2026-03-05 10:56:50 +0000
committerGitHub <noreply@github.com>2026-03-05 10:56:50 +0000
commitfe3dd8edb5f30104cd0a7ed755eb254feda2922d (patch)
treeaf6cf5fa4ca75302ac2de5db742cead00bc13d21 /packages/frontend/src/utility/autocomplete.ts
parentMerge pull request #16998 from misskey-dev/develop (diff)
parentRelease: 2026.3.0 (diff)
downloadmisskey-fe3dd8edb5f30104cd0a7ed755eb254feda2922d.tar.gz
misskey-fe3dd8edb5f30104cd0a7ed755eb254feda2922d.tar.bz2
misskey-fe3dd8edb5f30104cd0a7ed755eb254feda2922d.zip
Merge pull request #17217 from misskey-dev/develop
Release: 2026.3.0
Diffstat (limited to 'packages/frontend/src/utility/autocomplete.ts')
-rw-r--r--packages/frontend/src/utility/autocomplete.ts50
1 files changed, 30 insertions, 20 deletions
diff --git a/packages/frontend/src/utility/autocomplete.ts b/packages/frontend/src/utility/autocomplete.ts
index 82109af1a0..a44bf7c1ae 100644
--- a/packages/frontend/src/utility/autocomplete.ts
+++ b/packages/frontend/src/utility/autocomplete.ts
@@ -12,6 +12,15 @@ import { popup } from '@/os.js';
export type SuggestionType = 'user' | 'hashtag' | 'emoji' | 'mfmTag' | 'mfmParam';
+type CompleteProps<T extends keyof CompleteInfo> = {
+ type: T;
+ value: CompleteInfo[T]['payload'];
+};
+
+function isCompleteType<T extends keyof CompleteInfo>(expectedType: T, props: CompleteProps<keyof CompleteInfo>): props is CompleteProps<T> {
+ return props.type === expectedType;
+}
+
export class Autocomplete {
private suggestion: {
x: Ref<number>;
@@ -194,7 +203,7 @@ export class Autocomplete {
this.currentType = type;
//#region サジェストを表示すべき位置を計算
- const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart);
+ const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart ?? 0);
const rect = this.textarea.getBoundingClientRect();
@@ -213,10 +222,11 @@ export class Autocomplete {
const _y = ref(y);
const _q = ref(q);
- const { dispose } = await popup(defineAsyncComponent(() => import('@/components/MkAutocomplete.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAutocomplete.vue')), {
textarea: this.textarea,
close: this.close,
type: type,
+ //@ts-expect-error popupは今のところジェネリック型のコンポーネントに対応していない
q: _q,
x: _x,
y: _y,
@@ -252,19 +262,19 @@ export class Autocomplete {
/**
* オートコンプリートする
*/
- private complete<T extends keyof CompleteInfo>({ type, value }: { type: T; value: CompleteInfo[T]['payload'] }) {
+ private complete<T extends keyof CompleteInfo>(props: CompleteProps<T>) {
this.close();
const caret = Number(this.textarea.selectionStart);
- if (type === 'user') {
+ if (isCompleteType('user', props)) {
const source = this.text;
const before = source.substring(0, caret);
const trimmedBefore = before.substring(0, before.lastIndexOf('@'));
const after = source.substring(caret);
- const acct = value.host === null ? value.username : `${value.username}@${toASCII(value.host)}`;
+ const acct = props.value.host === null ? props.value.username : `${props.value.username}@${toASCII(props.value.host)}`;
// 挿入
this.text = `${trimmedBefore}@${acct} ${after}`;
@@ -275,7 +285,7 @@ export class Autocomplete {
const pos = trimmedBefore.length + (acct.length + 2);
this.textarea.setSelectionRange(pos, pos);
});
- } else if (type === 'hashtag') {
+ } else if (isCompleteType('hashtag', props)) {
const source = this.text;
const before = source.substring(0, caret);
@@ -283,15 +293,15 @@ export class Autocomplete {
const after = source.substring(caret);
// 挿入
- this.text = `${trimmedBefore}#${value} ${after}`;
+ this.text = `${trimmedBefore}#${props.value} ${after}`;
// キャレットを戻す
nextTick(() => {
this.textarea.focus();
- const pos = trimmedBefore.length + (value.length + 2);
+ const pos = trimmedBefore.length + (props.value.length + 2);
this.textarea.setSelectionRange(pos, pos);
});
- } else if (type === 'emoji') {
+ } else if (isCompleteType('emoji', props)) {
const source = this.text;
const before = source.substring(0, caret);
@@ -299,15 +309,15 @@ export class Autocomplete {
const after = source.substring(caret);
// 挿入
- this.text = trimmedBefore + value + after;
+ this.text = trimmedBefore + props.value + after;
// キャレットを戻す
nextTick(() => {
this.textarea.focus();
- const pos = trimmedBefore.length + value.length;
+ const pos = trimmedBefore.length + props.value.length;
this.textarea.setSelectionRange(pos, pos);
});
- } else if (type === 'emojiComplete') {
+ } else if (isCompleteType('emojiComplete', props)) {
const source = this.text;
const before = source.substring(0, caret);
@@ -315,15 +325,15 @@ export class Autocomplete {
const after = source.substring(caret);
// 挿入
- this.text = trimmedBefore + value + after;
+ this.text = trimmedBefore + props.value + after;
// キャレットを戻す
nextTick(() => {
this.textarea.focus();
- const pos = trimmedBefore.length + value.length;
+ const pos = trimmedBefore.length + props.value.length;
this.textarea.setSelectionRange(pos, pos);
});
- } else if (type === 'mfmTag') {
+ } else if (isCompleteType('mfmTag', props)) {
const source = this.text;
const before = source.substring(0, caret);
@@ -331,15 +341,15 @@ export class Autocomplete {
const after = source.substring(caret);
// 挿入
- this.text = `${trimmedBefore}$[${value} ]${after}`;
+ this.text = `${trimmedBefore}$[${props.value} ]${after}`;
// キャレットを戻す
nextTick(() => {
this.textarea.focus();
- const pos = trimmedBefore.length + (value.length + 3);
+ const pos = trimmedBefore.length + (props.value.length + 3);
this.textarea.setSelectionRange(pos, pos);
});
- } else if (type === 'mfmParam') {
+ } else if (isCompleteType('mfmParam', props)) {
const source = this.text;
const before = source.substring(0, caret);
@@ -347,12 +357,12 @@ export class Autocomplete {
const after = source.substring(caret);
// 挿入
- this.text = `${trimmedBefore}.${value}${after}`;
+ this.text = `${trimmedBefore}.${props.value}${after}`;
// キャレットを戻す
nextTick(() => {
this.textarea.focus();
- const pos = trimmedBefore.length + (value.length + 1);
+ const pos = trimmedBefore.length + (props.value.length + 1);
this.textarea.setSelectionRange(pos, pos);
});
}