diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2026-01-09 22:06:40 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-09 22:06:40 +0900 |
| commit | 41592eafb363e3c62ab2d3e5f41b38d7d083d3fb (patch) | |
| tree | 8f69243a5482ad4161eb28b69769684a221aa05c /packages/frontend/src/components | |
| parent | fix(frontend): popupのemit型が正しく利用できるように修正 (#16... (diff) | |
| download | misskey-41592eafb363e3c62ab2d3e5f41b38d7d083d3fb.tar.gz misskey-41592eafb363e3c62ab2d3e5f41b38d7d083d3fb.tar.bz2 misskey-41592eafb363e3c62ab2d3e5f41b38d7d083d3fb.zip | |
refactor: make noImplicitAny true (#17083)
* wip
* Update emojis.emoji.vue
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update manager.ts
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update analytics.ts
Diffstat (limited to 'packages/frontend/src/components')
85 files changed, 311 insertions, 284 deletions
diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue index c7252e7c98..cbc5b27fca 100644 --- a/packages/frontend/src/components/MkAbuseReport.vue +++ b/packages/frontend/src/components/MkAbuseReport.vue @@ -115,7 +115,7 @@ watch(moderationNote, async () => { }); }); -function resolve(resolvedAs) { +function resolve(resolvedAs: 'accept' | 'reject' | null) { os.apiWithDialog('admin/resolve-abuse-user-report', { reportId: props.report.id, resolvedAs, @@ -132,7 +132,7 @@ function forward() { }); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { os.popupMenu([{ icon: 'ti ti-hash', text: 'Copy ID', diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue index c786e9fe9f..d0e138c229 100644 --- a/packages/frontend/src/components/MkAchievements.vue +++ b/packages/frontend/src/components/MkAchievements.vue @@ -23,13 +23,13 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <div :class="$style.body"> <div :class="$style.header"> - <span :class="$style.title">{{ i18n.ts._achievements._types['_' + achievement.name].title }}</span> + <span :class="$style.title">{{ (i18n.ts._achievements._types as any)['_' + achievement.name].title }}</span> <span :class="$style.time"> <time v-tooltip="new Date(achievement.unlockedAt).toLocaleString()">{{ new Date(achievement.unlockedAt).getFullYear() }}/{{ new Date(achievement.unlockedAt).getMonth() + 1 }}/{{ new Date(achievement.unlockedAt).getDate() }}</time> </span> </div> - <div :class="$style.description">{{ withDescription ? i18n.ts._achievements._types['_' + achievement.name].description : '???' }}</div> - <div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor && withDescription" :class="$style.flavor">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div> + <div :class="$style.description">{{ withDescription ? (i18n.ts._achievements._types as any)['_' + achievement.name].description : '???' }}</div> + <div v-if="(i18n.ts._achievements._types as any)['_' + achievement.name].flavor && withDescription" :class="$style.flavor">{{ (i18n.ts._achievements._types as any)['_' + achievement.name].flavor }}</div> </div> </div> <template v-if="withLocked"> @@ -54,7 +54,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import * as Misskey from 'misskey-js'; import { onMounted, ref, computed } from 'vue'; -import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { i18n } from '@/i18n.js'; import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/utility/achievements.js'; diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue index a3b6112629..d44e7724b3 100644 --- a/packages/frontend/src/components/MkAsUi.vue +++ b/packages/frontend/src/components/MkAsUi.vue @@ -64,13 +64,13 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed } from 'vue'; import type { Ref } from 'vue'; +import type { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/aiscript/ui.js'; import * as os from '@/os.js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkSelect from '@/components/MkSelect.vue'; -import type { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/aiscript/ui.js'; import MkFolder from '@/components/MkFolder.vue'; import MkPostForm from '@/components/MkPostForm.vue'; import { useMkSelect } from '@/composables/use-mkselect.js'; @@ -144,7 +144,7 @@ const { initialValue: (c.type === 'select' && 'default' in c && typeof c.default !== 'boolean') ? c.default ?? null : null, }); -function onSelectUpdate(v) { +function onSelectUpdate(v: string | null) { valueForSelect.value = v; if ('onChange' in c && c.onChange) { c.onChange(v as never); diff --git a/packages/frontend/src/components/MkAuthConfirm.vue b/packages/frontend/src/components/MkAuthConfirm.vue index 8744b50926..b1a29660ad 100644 --- a/packages/frontend/src/components/MkAuthConfirm.vue +++ b/packages/frontend/src/components/MkAuthConfirm.vue @@ -183,7 +183,7 @@ async function init() { init(); -function clickAddAccount(ev: MouseEvent) { +function clickAddAccount(ev: PointerEvent) { selectedUser.value = null; os.popupMenu([{ diff --git a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts index 15aab8daed..9104650752 100644 --- a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts +++ b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts @@ -3,15 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { action } from 'storybook/actions'; import { expect, userEvent, waitFor, within } from '@storybook/test'; -import type { StoryObj } from '@storybook/vue3'; import { HttpResponse, http } from 'msw'; import { userDetailed } from '../../.storybook/fakes.js'; import { commonHandlers } from '../../.storybook/mocks.js'; import MkAutocomplete from './MkAutocomplete.vue'; import MkInput from './MkInput.vue'; +import type { StoryObj } from '@storybook/vue3'; import { tick } from '@/utility/test-utils.js'; const common = { render(args) { @@ -81,7 +80,7 @@ export const User = { ...common.args, type: 'user', }, - async play({ canvasElement }) { + async play({ canvasElement }: { canvasElement: HTMLElement }) { const canvas = within(canvasElement); const input = canvas.getByRole('combobox'); await waitFor(() => userEvent.hover(input)); @@ -114,7 +113,7 @@ export const Hashtag = { ...common.args, type: 'hashtag', }, - async play({ canvasElement }) { + async play({ canvasElement }: { canvasElement: HTMLElement }) { const canvas = within(canvasElement); const input = canvas.getByRole('combobox'); await waitFor(() => userEvent.hover(input)); diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index cf5d95e11b..5e860351af 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -50,7 +50,7 @@ import { emojilist, getEmojiName } from '@@/js/emojilist.js'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js'; import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js'; import type { EmojiDef } from '@/utility/search-emoji.js'; -import contains from '@/utility/contains.js'; +import { elementContains } from '@/utility/element-contains.js'; import { acct } from '@/filters/user.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; @@ -310,8 +310,8 @@ function exec() { } } -function onMousedown(event: Event) { - if (!contains(rootEl.value, event.target) && (rootEl.value !== event.target)) props.close(); +function onMousedown(event: MouseEvent) { + if (!elementContains(rootEl.value, event.target as Element) && (rootEl.value !== event.target)) props.close(); } function onKeydown(event: KeyboardEvent) { diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index b729128a21..854ed31ed5 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -63,7 +63,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'click', payload: MouseEvent): void; + (ev: 'click', payload: PointerEvent): void; }>(); const el = useTemplateRef('el'); @@ -77,11 +77,11 @@ onMounted(() => { } }); -function distance(p, q): number { +function distance(p: { x: number; y: number }, q: { x: number; y: number }): number { return Math.hypot(p.x - q.x, p.y - q.y); } -function calcCircleScale(boxW, boxH, circleCenterX, circleCenterY): number { +function calcCircleScale(boxW: number, boxH: number, circleCenterX: number, circleCenterY: number): number { const origin = { x: circleCenterX, y: circleCenterY }; const dist1 = distance({ x: 0, y: 0 }, origin); const dist2 = distance({ x: boxW, y: 0 }, origin); diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index 30940a34a9..6e4a8c13d2 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -84,7 +84,7 @@ const variable = computed(() => { } }); -const loaded = !!window[variable.value]; +const loaded = !!(window as any)[variable.value]; const src = computed(() => { switch (props.provider) { @@ -98,7 +98,7 @@ const src = computed(() => { const scriptId = computed(() => `script-${props.provider}`); -const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown as Captcha); +const captcha = computed<Captcha>(() => (window as any)[variable.value] ?? {} as unknown as Captcha); watch(() => [props.instanceUrl, props.sitekey, props.secretKey], async () => { // 変更があったときはリフレッシュと再レンダリングをしておかないと、変更後の値で再検証が出来ない diff --git a/packages/frontend/src/components/MkChannelList.vue b/packages/frontend/src/components/MkChannelList.vue index 23bb32c6b9..af89ec8252 100644 --- a/packages/frontend/src/components/MkChannelList.vue +++ b/packages/frontend/src/components/MkChannelList.vue @@ -24,6 +24,6 @@ const props = withDefaults(defineProps<{ noGap?: boolean; extractor?: ExtractorFunction<P, Misskey.entities.Channel>; }>(), { - extractor: (item) => item, + extractor: (item: any) => item as Misskey.entities.Channel, }); </script> diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue index c54081ad42..e418e729ca 100644 --- a/packages/frontend/src/components/MkChart.vue +++ b/packages/frontend/src/components/MkChart.vue @@ -94,8 +94,8 @@ const props = withDefaults(defineProps<{ const legendEl = useTemplateRef('legendEl'); -const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); -const negate = arr => arr.map(x => -x); +const sum = (...arr: number[][]) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); +const negate = (arr: number[]) => arr.map((x) => -x); const colors = { blue: '#008FFB', @@ -108,7 +108,7 @@ const colors = { cyan: '#00e0e0', }; const colorSets = [colors.blue, colors.green, colors.yellow, colors.red, colors.purple]; -const getColor = (i) => { +const getColor = (i: number) => { return colorSets[i % colorSets.length]; }; @@ -142,7 +142,7 @@ const getDate = (ago: number) => { return props.span === 'day' ? new Date(y, m, d - ago) : new Date(y, m, d, h - ago); }; -const format = (arr) => { +const format = (arr: number[]) => { return arr.map((v, i) => ({ x: getDate(i).getTime(), y: v, @@ -371,7 +371,7 @@ const fetchApRequestChart = async (): Promise<typeof chartData> => { }; }; -const fetchNotesChart = async (type: string): Promise<typeof chartData> => { +const fetchNotesChart = async (type: 'local' | 'remote' | 'combined'): Promise<typeof chartData> => { const raw = await misskeyApiGet('charts/notes', { limit: props.limit, span: props.span }); return { series: [{ diff --git a/packages/frontend/src/components/MkClickerGame.vue b/packages/frontend/src/components/MkClickerGame.vue index 775964af50..0c856c57eb 100644 --- a/packages/frontend/src/components/MkClickerGame.vue +++ b/packages/frontend/src/components/MkClickerGame.vue @@ -20,9 +20,9 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, onMounted, onUnmounted, ref } from 'vue'; +import { useInterval } from '@@/js/use-interval.js'; import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue'; import * as os from '@/os.js'; -import { useInterval } from '@@/js/use-interval.js'; import * as game from '@/utility/clicker-game.js'; import number from '@/filters/number.js'; import { claimAchievement } from '@/utility/achievements.js'; @@ -32,7 +32,7 @@ const cookies = computed(() => saveData.value?.cookies); const cps = ref(0); const prevCookies = ref(0); -function onClick(ev: MouseEvent) { +function onClick(ev: PointerEvent) { const x = ev.clientX; const y = ev.clientY; const { dispose } = os.popup(MkPlusOneEffect, { x, y }, { diff --git a/packages/frontend/src/components/MkCodeEditor.vue b/packages/frontend/src/components/MkCodeEditor.vue index bdb2ba6a44..dda5a14716 100644 --- a/packages/frontend/src/components/MkCodeEditor.vue +++ b/packages/frontend/src/components/MkCodeEditor.vue @@ -40,7 +40,7 @@ import XCode from '@/components/MkCode.core.vue'; const props = withDefaults(defineProps<{ modelValue: string | null; - lang: string; + lang?: string; required?: boolean; readonly?: boolean; disabled?: boolean; @@ -51,7 +51,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'change', _ev: KeyboardEvent): void; + (ev: 'change', _ev: InputEvent): void; (ev: 'keydown', _ev: KeyboardEvent): void; (ev: 'enter'): void; (ev: 'update:modelValue', value: string): void; @@ -63,15 +63,17 @@ const focused = ref(false); const changed = ref(false); const inputEl = useTemplateRef('inputEl'); -const focus = () => inputEl.value?.focus(); +function focus() { + inputEl.value?.focus(); +} -const onInput = (ev) => { - v.value = ev.target?.value ?? v.value; +function onInput(ev: InputEvent) { + v.value = (inputEl.value?.value) ?? ''; changed.value = true; emit('change', ev); -}; +} -const onKeydown = (ev: KeyboardEvent) => { +function onKeydown(ev: KeyboardEvent) { if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return; emit('keydown', ev); @@ -102,12 +104,12 @@ const onKeydown = (ev: KeyboardEvent) => { }); ev.preventDefault(); } -}; +} -const updated = () => { +function updated() { changed.value = false; emit('update:modelValue', v.value); -}; +} const debouncedUpdated = debounce(1000, updated); diff --git a/packages/frontend/src/components/MkContextMenu.stories.impl.ts b/packages/frontend/src/components/MkContextMenu.stories.impl.ts index 7a5e36131b..fc9fd9bc49 100644 --- a/packages/frontend/src/components/MkContextMenu.stories.impl.ts +++ b/packages/frontend/src/components/MkContextMenu.stories.impl.ts @@ -3,11 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -/* eslint-disable @typescript-eslint/explicit-function-return-type */ -/* eslint-disable import/no-default-export */ -import type { StoryObj } from '@storybook/vue3'; import { userEvent, within } from '@storybook/test'; import MkContextMenu from './MkContextMenu.vue'; +import type { StoryObj } from '@storybook/vue3'; import * as os from '@/os.js'; export const Empty = { render(args) { @@ -25,7 +23,7 @@ export const Empty = { }, }, methods: { - onContextmenu(ev: MouseEvent) { + onContextmenu(ev: PointerEvent) { os.contextMenu(args.items, ev); }, }, diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue index 9c6397a72c..6678c8fb91 100644 --- a/packages/frontend/src/components/MkContextMenu.vue +++ b/packages/frontend/src/components/MkContextMenu.vue @@ -21,13 +21,13 @@ SPDX-License-Identifier: AGPL-3.0-only import { onMounted, onBeforeUnmount, useTemplateRef, ref } from 'vue'; import MkMenu from './MkMenu.vue'; import type { MenuItem } from '@/types/menu.js'; -import contains from '@/utility/contains.js'; +import { elementContains } from '@/utility/element-contains.js'; import { prefer } from '@/preferences.js'; import * as os from '@/os.js'; const props = defineProps<{ items: MenuItem[]; - ev: MouseEvent; + ev: PointerEvent; }>(); const emit = defineEmits<{ @@ -75,8 +75,8 @@ onBeforeUnmount(() => { window.document.body.removeEventListener('mousedown', onMousedown); }); -function onMousedown(evt: Event) { - if (!contains(rootEl.value, evt.target) && (rootEl.value !== evt.target)) emit('closed'); +function onMousedown(evt: MouseEvent) { + if (!elementContains(rootEl.value, evt.target as Element) && (rootEl.value !== evt.target)) emit('closed'); } </script> diff --git a/packages/frontend/src/components/MkDrive.file.vue b/packages/frontend/src/components/MkDrive.file.vue index 0eca85b3a6..e2858084c0 100644 --- a/packages/frontend/src/components/MkDrive.file.vue +++ b/packages/frontend/src/components/MkDrive.file.vue @@ -64,7 +64,7 @@ const isDragging = ref(false); const title = computed(() => `${props.file.name}\n${props.file.type} ${bytes(props.file.size)}`); -function onContextmenu(ev: MouseEvent) { +function onContextmenu(ev: PointerEvent) { os.contextMenu(getDriveFileMenu(props.file, props.folder), ev); } diff --git a/packages/frontend/src/components/MkDrive.folder.vue b/packages/frontend/src/components/MkDrive.folder.vue index 8b2609852c..6d93dfc0d4 100644 --- a/packages/frontend/src/components/MkDrive.folder.vue +++ b/packages/frontend/src/components/MkDrive.folder.vue @@ -57,7 +57,7 @@ const props = withDefaults(defineProps<{ const emit = defineEmits<{ (ev: 'chosen', v: Misskey.entities.DriveFolder): void; (ev: 'unchose', v: Misskey.entities.DriveFolder): void; - (ev: 'upload', files: File[], folder: Misskey.entities.DriveFolder); + (ev: 'upload', files: File[], folder: Misskey.entities.DriveFolder): void; (ev: 'dragstart'): void; (ev: 'dragend'): void; }>(); @@ -277,7 +277,7 @@ function setAsUploadFolder() { prefer.commit('uploadFolder', props.folder.id); } -function onContextmenu(ev: MouseEvent) { +function onContextmenu(ev: PointerEvent) { let menu: MenuItem[]; menu = [{ text: i18n.ts.openInWindow, diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index 6e286f4882..2961bc5032 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -139,7 +139,9 @@ SPDX-License-Identifier: AGPL-3.0-only primary rounded @click="fetchMoreFiles" - >{{ i18n.ts.loadMore }}</MkButton> + > + {{ i18n.ts.loadMore }} + </MkButton> <div v-if="filesPaginator.items.value.length == 0 && foldersPaginator.items.value.length == 0 && !fetching" :class="$style.empty"> <div v-if="draghover">{{ i18n.ts.dropHereToUpload }}</div> @@ -491,7 +493,7 @@ function deleteFolder(folderToDelete: Misskey.entities.DriveFolder) { }); } -function onFileClick(ev: MouseEvent, file: Misskey.entities.DriveFile) { +function onFileClick(ev: PointerEvent, file: Misskey.entities.DriveFile) { if (ev.shiftKey) { isEditMode.value = true; } @@ -563,7 +565,7 @@ function cd(target?: Misskey.entities.DriveFolder | Misskey.entities.DriveFolder folder.value = folderToMove; hierarchyFolders.value = []; - const dive = folderToDive => { + const dive = (folderToDive: Misskey.entities.DriveFolder) => { hierarchyFolders.value.unshift(folderToDive); if (folderToDive.parent) dive(folderToDive.parent); }; @@ -689,11 +691,11 @@ function getMenu() { return menu; } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); } -function onContextmenu(ev: MouseEvent) { +function onContextmenu(ev: PointerEvent) { os.contextMenu(getMenu(), ev); } diff --git a/packages/frontend/src/components/MkEmojiPicker.section.vue b/packages/frontend/src/components/MkEmojiPicker.section.vue index ef515e471f..3ee32710e5 100644 --- a/packages/frontend/src/components/MkEmojiPicker.section.vue +++ b/packages/frontend/src/components/MkEmojiPicker.section.vue @@ -62,8 +62,8 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed } from 'vue'; -import type { Ref } from 'vue'; import { getEmojiName } from '@@/js/emojilist.js'; +import type { Ref } from 'vue'; import type { CustomEmojiFolderTree } from '@@/js/emojilist.js'; import { i18n } from '@/i18n.js'; import { customEmojis } from '@/custom-emojis.js'; @@ -78,7 +78,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'chosen', v: string, event: MouseEvent): void; + (ev: 'chosen', v: string, event: PointerEvent): void; }>(); const emojis = computed(() => Array.isArray(props.emojis) ? props.emojis : props.emojis.value); @@ -86,13 +86,13 @@ const emojis = computed(() => Array.isArray(props.emojis) ? props.emojis : props const shown = ref(!!props.initialShown); /** @see MkEmojiPicker.vue */ -function computeButtonTitle(ev: MouseEvent): void { +function computeButtonTitle(ev: PointerEvent): void { const elm = ev.target as HTMLElement; const emoji = elm.dataset.emoji as string; elm.title = getEmojiName(emoji); } -function nestedChosen(emoji: string, ev: MouseEvent) { +function nestedChosen(emoji: string, ev: PointerEvent) { emit('chosen', emoji, ev); } </script> diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index 33e9137c2f..bf0f9d0130 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -412,13 +412,13 @@ function getDef(emoji: string): string | Misskey.entities.EmojiSimple | UnicodeE } /** @see MkEmojiPicker.section.vue */ -function computeButtonTitle(ev: MouseEvent): void { +function computeButtonTitle(ev: PointerEvent): void { const elm = ev.target as HTMLElement; const emoji = elm.dataset.emoji as string; elm.title = getEmojiName(emoji); } -function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) { +function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: PointerEvent) { const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; if (el && prefer.s.animation) { const rect = el.getBoundingClientRect(); diff --git a/packages/frontend/src/components/MkExtensionInstaller.vue b/packages/frontend/src/components/MkExtensionInstaller.vue index c9d18ee731..9c0cce7689 100644 --- a/packages/frontend/src/components/MkExtensionInstaller.vue +++ b/packages/frontend/src/components/MkExtensionInstaller.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #key>{{ i18n.ts.permission }}</template> <template #value> <ul v-if="extension.meta.permissions && extension.meta.permissions.length > 0" :class="$style.extInstallerKVList"> - <li v-for="permission in extension.meta.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li> + <li v-for="permission in extension.meta.permissions" :key="permission">{{ (i18n.ts._permissions as any)[permission] ?? permission }}</li> </ul> <template v-else>{{ i18n.ts.none }}</template> </template> diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index 94fdf6da36..864f53d09c 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -169,7 +169,7 @@ function afterLeave(el: Element) { let pageId = pageFolderTeleportCount.value; pageFolderTeleportCount.value += 1000; -async function toggle(ev: MouseEvent) { +async function toggle(ev: PointerEvent) { if (asPage && !opened.value) { pageId++; const { dispose } = await popup(MkFolderPage, { diff --git a/packages/frontend/src/components/MkForm.file.vue b/packages/frontend/src/components/MkForm.file.vue index 182ff3ccf5..d233467e8b 100644 --- a/packages/frontend/src/components/MkForm.file.vue +++ b/packages/frontend/src/components/MkForm.file.vue @@ -50,7 +50,7 @@ if (props.fileId) { }); } -function selectButton(ev: MouseEvent) { +function selectButton(ev: PointerEvent) { selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, diff --git a/packages/frontend/src/components/MkHeatmap.vue b/packages/frontend/src/components/MkHeatmap.vue index abbf86004b..03780bf3ba 100644 --- a/packages/frontend/src/components/MkHeatmap.vue +++ b/packages/frontend/src/components/MkHeatmap.vue @@ -125,8 +125,7 @@ async function renderChart() { data: format(values) as any, borderWidth: 0, borderRadius: 3, - backgroundColor(c) { - // @ts-expect-error TS(2339) + backgroundColor(c: any) { const value = c.dataset.data[c.dataIndex].v as number; let a = (value - min) / max; if (value !== 0) { // 0でない限りは完全に不可視にはしない @@ -195,7 +194,7 @@ async function renderChart() { font: { size: 9, }, - callback: (value, index, values) => ['', 'Mon', '', 'Wed', '', 'Fri', ''][value], + callback: (value, index, values) => ['', 'Mon', '', 'Wed', '', 'Fri', ''][value as any], }, }, }, diff --git a/packages/frontend/src/components/MkImageEffectorDialog.vue b/packages/frontend/src/components/MkImageEffectorDialog.vue index 01df7d7496..f740002088 100644 --- a/packages/frontend/src/components/MkImageEffectorDialog.vue +++ b/packages/frontend/src/components/MkImageEffectorDialog.vue @@ -95,7 +95,7 @@ watch(layers, async () => { } }, { deep: true }); -function addEffect(ev: MouseEvent) { +function addEffect(ev: PointerEvent) { os.popupMenu(Object.entries(FXS).map(([id, fx]) => ({ text: fx.uiDefinition.name, action: () => { @@ -219,7 +219,7 @@ watch(enabled, () => { const penMode = ref<'fill' | 'blur' | 'pixelate' | null>(null); -function showPenMenu(ev: MouseEvent) { +function showPenMenu(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts._imageEffector._fxs.fill, action: () => { diff --git a/packages/frontend/src/components/MkInput.vue b/packages/frontend/src/components/MkInput.vue index 7f052dff94..4f6ca083a3 100644 --- a/packages/frontend/src/components/MkInput.vue +++ b/packages/frontend/src/components/MkInput.vue @@ -88,7 +88,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'change', _ev: KeyboardEvent): void; + (ev: 'change', _ev: InputEvent): void; (ev: 'keydown', _ev: KeyboardEvent): void; (ev: 'enter', _ev: KeyboardEvent): void; (ev: 'update:modelValue', value: ModelValueType<T>): void; @@ -111,10 +111,9 @@ const height = let autocompleteWorker: Autocomplete | null = null; const focus = () => inputEl.value?.focus(); -const onInput = (event: Event) => { - const ev = event as KeyboardEvent; +const onInput = (event: InputEvent) => { changed.value = true; - emit('change', ev); + emit('change', event); }; const onKeydown = (ev: KeyboardEvent) => { if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return; diff --git a/packages/frontend/src/components/MkInstanceCardMini.vue b/packages/frontend/src/components/MkInstanceCardMini.vue index 7902151921..130a0e9986 100644 --- a/packages/frontend/src/components/MkInstanceCardMini.vue +++ b/packages/frontend/src/components/MkInstanceCardMini.vue @@ -33,7 +33,7 @@ misskeyApiGet('charts/instance', { host: props.instance.host, limit: 16 + 1, spa chartValues.value = res.requests.received; }); -function getInstanceIcon(instance): string { +function getInstanceIcon(instance: Misskey.entities.FederationInstance): string { return getProxiedImageUrlNullable(instance.iconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? '/client-assets/dummy.png'; } </script> diff --git a/packages/frontend/src/components/MkInstanceStats.vue b/packages/frontend/src/components/MkInstanceStats.vue index 13048a2e1b..368fa5be27 100644 --- a/packages/frontend/src/components/MkInstanceStats.vue +++ b/packages/frontend/src/components/MkInstanceStats.vue @@ -57,10 +57,10 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, computed, useTemplateRef } from 'vue'; import { Chart } from 'chart.js'; -import MkSelect from '@/components/MkSelect.vue'; import type { MkSelectItem, ItemOption } from '@/components/MkSelect.vue'; -import MkChart from '@/components/MkChart.vue'; import type { ChartSrc } from '@/components/MkChart.vue'; +import MkSelect from '@/components/MkSelect.vue'; +import MkChart from '@/components/MkChart.vue'; import { useChartTooltip } from '@/composables/use-chart-tooltip.js'; import { $i } from '@/i.js'; import * as os from '@/os.js'; @@ -172,7 +172,14 @@ const { handler: externalTooltipHandler2 } = useChartTooltip({ position: 'middle', }); -function createDoughnut(chartEl, tooltip, data) { +type ChartData = { + name: string, + color: string, + value: number, + onClick?: () => void, +}[]; + +function createDoughnut(chartEl: HTMLCanvasElement, tooltip: ReturnType<typeof useChartTooltip>['handler'], data: ChartData) { const chartInstance = new Chart(chartEl, { type: 'doughnut', data: { @@ -198,8 +205,8 @@ function createDoughnut(chartEl, tooltip, data) { onClick: (ev) => { if (ev.native == null) return; const hit = chartInstance.getElementsAtEventForMode(ev.native, 'nearest', { intersect: true }, false)[0]; - if (hit && data[hit.index].onClick) { - data[hit.index].onClick(); + if (hit != null) { + data[hit.index].onClick?.(); } }, plugins: { @@ -223,16 +230,9 @@ function createDoughnut(chartEl, tooltip, data) { onMounted(() => { misskeyApiGet('federation/stats', { limit: 30 }).then(fedStats => { - type ChartData = { - name: string, - color: string | null, - value: number, - onClick?: () => void, - }[]; - const subs: ChartData = fedStats.topSubInstances.map(x => ({ name: x.host, - color: x.themeColor, + color: x.themeColor ?? '#888888', value: x.followersCount, onClick: () => { os.pageWindow(`/instance-info/${x.host}`); @@ -245,11 +245,11 @@ onMounted(() => { value: fedStats.otherFollowersCount, }); - createDoughnut(subDoughnutEl.value, externalTooltipHandler1, subs); + if (subDoughnutEl.value != null) createDoughnut(subDoughnutEl.value, externalTooltipHandler1, subs); const pubs: ChartData = fedStats.topPubInstances.map(x => ({ name: x.host, - color: x.themeColor, + color: x.themeColor ?? '#888888', value: x.followingCount, onClick: () => { os.pageWindow(`/instance-info/${x.host}`); @@ -262,7 +262,7 @@ onMounted(() => { value: fedStats.otherFollowingCount, }); - createDoughnut(pubDoughnutEl.value, externalTooltipHandler2, pubs); + if (pubDoughnutEl.value != null) createDoughnut(pubDoughnutEl.value, externalTooltipHandler2, pubs); }); }); </script> diff --git a/packages/frontend/src/components/MkLaunchPad.vue b/packages/frontend/src/components/MkLaunchPad.vue index d8725ade0b..0c73df4e2d 100644 --- a/packages/frontend/src/components/MkLaunchPad.vue +++ b/packages/frontend/src/components/MkLaunchPad.vue @@ -8,13 +8,13 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }"> <div class="main"> <template v-for="item in items" :key="item.text"> - <button v-if="item.action" v-click-anime class="_button item" @click="$event => { item.action($event); close(); }"> + <button v-if="item.action != null" v-click-anime class="_button item" @click="$event => { item.action!($event); close(); }"> <i class="icon" :class="item.icon"></i> <div class="text">{{ item.text }}</div> <span v-if="item.indicate && item.indicateValue" class="_indicateCounter indicatorWithValue">{{ item.indicateValue }}</span> <span v-else-if="item.indicate" class="indicator _blink"><i class="_indicatorCircle"></i></span> </button> - <MkA v-else v-click-anime :to="item.to" class="item" @click.passive="close()"> + <MkA v-else-if="item.to != null" v-click-anime :to="item.to" class="item" @click.passive="close()"> <i class="icon" :class="item.icon"></i> <div class="text">{{ item.text }}</div> <span v-if="item.indicate && item.indicateValue" class="_indicateCounter indicatorWithValue">{{ item.indicateValue }}</span> diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index 345c261776..c7d8c95b7b 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -100,7 +100,7 @@ const url = computed(() => (props.raw || prefer.s.loadRawImages) : props.image.thumbnailUrl!, ); -async function reveal(ev: MouseEvent) { +async function reveal(ev: PointerEvent) { if (!props.controls) { return; } @@ -123,7 +123,7 @@ watch(() => props.image, (newImage) => { immediate: true, }); -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { const menuItems: MenuItem[] = []; menuItems.push({ diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index 63db3c3ab5..aac52bfa26 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -190,7 +190,7 @@ async function reveal() { // Menu const menuShowing = ref(false); -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { const menu: MenuItem[] = [ // TODO: 再生キューに追加 { diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 6efaa655bc..22d5802596 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -316,7 +316,7 @@ function onItemMouseLeave() { if (childCloseTimer) window.clearTimeout(childCloseTimer); } -async function showRadioOptions(item: MenuRadio, ev: Event) { +async function showRadioOptions(item: MenuRadio, ev: MouseEvent | PointerEvent | KeyboardEvent) { const children: MenuItem[] = Object.keys(item.options).map<MenuRadioOption>(key => { const value = item.options[key]; return { @@ -341,7 +341,7 @@ async function showRadioOptions(item: MenuRadio, ev: Event) { } } -async function showChildren(item: MenuParent, ev: Event) { +async function showChildren(item: MenuParent, ev: MouseEvent | PointerEvent | KeyboardEvent) { ev.stopPropagation(); const children: MenuItem[] = await (async () => { @@ -371,7 +371,7 @@ async function showChildren(item: MenuParent, ev: Event) { } } -function clicked(fn: MenuAction, ev: MouseEvent, doClose = true) { +function clicked(fn: MenuAction, ev: PointerEvent, doClose = true) { fn(ev); if (!doClose) return; diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index 660d5a26be..92174d8ef7 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -184,8 +184,8 @@ const align = () => { const width = content.value!.offsetWidth; const height = content.value!.offsetHeight; - let left; - let top; + let left = 0; + let top = 0; const x = anchorRect.left + (fixed.value ? 0 : window.scrollX); const y = anchorRect.top + (fixed.value ? 0 : window.scrollY); diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 56def64d3d..c78cc44425 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -594,7 +594,7 @@ function toggleReact() { } } -function onContextmenu(ev: MouseEvent): void { +function onContextmenu(ev: PointerEvent): void { if (props.mock) { return; } diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index febf909f42..cfb65cd9b7 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/> </div> - <MkNoteSub v-if="appearNote.replyId" :note="appearNote.reply" :class="$style.replyTo"/> + <MkNoteSub v-if="appearNote.replyId" :note="appearNote?.reply ?? null" :class="$style.replyTo"/> <div v-if="isRenote" :class="$style.renote"> <MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/> <i class="ti ti-repeat" style="margin-right: 4px;"></i> @@ -111,7 +111,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> <div v-if="appearNote.files && appearNote.files.length > 0"> - <MkMediaList ref="galleryEl" :mediaList="appearNote.files"/> + <MkMediaList :mediaList="appearNote.files"/> </div> <MkPoll v-if="appearNote.poll" @@ -144,7 +144,6 @@ SPDX-License-Identifier: AGPL-3.0-only :myReaction="$appearNote.myReaction" :noteId="appearNote.id" :maxNumber="16" - @mockUpdateMyReaction="emitUpdReaction" /> <button class="_button" :class="$style.noteFooterButton" @click="reply()"> <i class="ti ti-arrow-back-up"></i> @@ -233,7 +232,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, inject, markRaw, onMounted, provide, ref, useTemplateRef } from 'vue'; +import { computed, inject, markRaw, provide, ref, useTemplateRef } from 'vue'; import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; import { isLink } from '@@/js/is-link.js'; @@ -324,7 +323,6 @@ const renoteButton = useTemplateRef('renoteButton'); const renoteTime = useTemplateRef('renoteTime'); const reactButton = useTemplateRef('reactButton'); const clipButton = useTemplateRef('clipButton'); -const galleryEl = useTemplateRef('galleryEl'); const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); const isDeleted = ref(false); @@ -358,7 +356,7 @@ const keymap = { if (!prefer.s.showClipButtonInNoteFooter) return; clip(); }, - 'o': () => galleryEl.value?.openGallery(), + //'o': () => galleryEl.value?.openGallery(), 'v|enter': () => { if (appearNote.cw != null) { showContent.value = !showContent.value; @@ -553,7 +551,7 @@ function toggleReact() { } } -function onContextmenu(ev: MouseEvent): void { +function onContextmenu(ev: PointerEvent): void { if (ev.target && isLink(ev.target as HTMLElement)) return; if (window.getSelection()?.toString() !== '') return; diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index 45a74e3f02..143ca7fd2f 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -121,7 +121,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ notification.invitation.room.name }} </div> <MkA v-else-if="notification.type === 'achievementEarned'" :class="$style.text" to="/my/achievements"> - {{ i18n.ts._achievements._types['_' + notification.achievement].title }} + {{ (i18n.ts._achievements._types as any)['_' + notification.achievement].title }} </MkA> <MkA v-else-if="notification.type === 'exportCompleted'" :class="$style.text" :to="`/my/drive/file/${notification.fileId}`"> {{ i18n.ts.showFile }} diff --git a/packages/frontend/src/components/MkObjectView.value.vue b/packages/frontend/src/components/MkObjectView.value.vue index 7fa8c23c6c..abc4407d2a 100644 --- a/packages/frontend/src/components/MkObjectView.value.vue +++ b/packages/frontend/src/components/MkObjectView.value.vue @@ -42,7 +42,7 @@ const props = defineProps<{ value: unknown; }>(); -const collapsed = reactive({}); +const collapsed = reactive<Record<string, boolean>>({}); if (isObject(props.value)) { for (const key in props.value) { diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index a4c8ca0095..ad8fcf283c 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -88,7 +88,7 @@ const shouldEnableInfiniteScroll = computed(() => { return prefer.r.enableInfiniteScroll.value && !props.forceDisableInfiniteScroll; }); -function onContextmenu(ev: MouseEvent) { +function onContextmenu(ev: PointerEvent) { if (ev.target && isLink(ev.target as HTMLElement)) return; if (window.getSelection()?.toString() !== '') return; diff --git a/packages/frontend/src/components/MkPollEditor.vue b/packages/frontend/src/components/MkPollEditor.vue index b7c3d1f42d..bd36a0b97a 100644 --- a/packages/frontend/src/components/MkPollEditor.vue +++ b/packages/frontend/src/components/MkPollEditor.vue @@ -110,7 +110,7 @@ if (props.modelValue.expiresAt) { expiration.value = 'infinite'; } -function onInput(i, value) { +function onInput(i: number, value: string) { choices.value[i] = value; } @@ -122,7 +122,7 @@ function add() { // }); } -function remove(i) { +function remove(i: number) { choices.value = choices.value.filter((_, _i) => _i !== i); } diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 9734b51927..c869eeb3fd 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -55,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.visibleUsers"> <span v-for="u in visibleUsers" :key="u.id" :class="$style.visibleUser"> <MkAcct :user="u"/> - <button class="_button" style="padding: 4px 8px;" @click="removeVisibleUser(u)"><i class="ti ti-x"></i></button> + <button class="_button" style="padding: 4px 8px;" @click="removeVisibleUser(u.id)"><i class="ti ti-x"></i></button> </span> <button class="_buttonPrimary" style="padding: 4px; border-radius: 8px;" @click="addVisibleUser"><i class="ti ti-plus ti-fw"></i></button> </div> @@ -476,6 +476,7 @@ function togglePoll() { } function addTag(tag: string) { + if (textareaEl.value == null) return; insertTextAtCursor(textareaEl.value, ` #${tag} `); } @@ -486,7 +487,7 @@ function focus() { } } -function chooseFileFromPc(ev: MouseEvent) { +function chooseFileFromPc(ev: PointerEvent) { if (props.mock) return; os.chooseFileFromPc({ multiple: true }).then(files => { @@ -495,7 +496,7 @@ function chooseFileFromPc(ev: MouseEvent) { }); } -function chooseFileFromDrive(ev: MouseEvent) { +function chooseFileFromDrive(ev: PointerEvent) { if (props.mock) return; chooseDriveFile({ multiple: true }).then(driveFiles => { @@ -503,18 +504,18 @@ function chooseFileFromDrive(ev: MouseEvent) { }); } -function detachFile(id) { +function detachFile(id: Misskey.entities.DriveFile['id']) { files.value = files.value.filter(x => x.id !== id); } -function updateFileSensitive(file, sensitive) { +function updateFileSensitive(file: Misskey.entities.DriveFile, isSensitive: boolean) { if (props.mock) { - emit('fileChangeSensitive', file.id, sensitive); + emit('fileChangeSensitive', file.id, isSensitive); } - files.value[files.value.findIndex(x => x.id === file.id)].isSensitive = sensitive; + files.value[files.value.findIndex(x => x.id === file.id)].isSensitive = isSensitive; } -function updateFileName(file, name) { +function updateFileName(file: Misskey.entities.DriveFile, name: Misskey.entities.DriveFile['name']) { files.value[files.value.findIndex(x => x.id === file.id)].name = name; } @@ -704,8 +705,8 @@ function addVisibleUser() { }); } -function removeVisibleUser(user) { - visibleUsers.value = erase(user, visibleUsers.value); +function removeVisibleUser(id: string) { + visibleUsers.value = visibleUsers.value.filter(u => u.id !== id); } function clear() { @@ -742,7 +743,8 @@ const pastedFileName = 'yyyy-MM-dd HH-mm-ss [{{number}}]'; async function onPaste(ev: ClipboardEvent) { if (props.mock) return; - if (!ev.clipboardData) return; + if (ev.clipboardData == null) return; + if (textareaEl.value == null) return; let pastedFiles: File[] = []; for (const { item, i } of Array.from(ev.clipboardData.items, (data, x) => ({ item: data, i: x }))) { @@ -767,39 +769,42 @@ async function onPaste(ev: ClipboardEvent) { if (!renoteTargetNote.value && !quoteId.value && paste.startsWith(url + '/notes/')) { ev.preventDefault(); - os.confirm({ + const { canceled } = await os.confirm({ type: 'info', text: i18n.ts.quoteQuestion, - }).then(({ canceled }) => { - if (canceled) { - insertTextAtCursor(textareaEl.value, paste); - return; - } - - quoteId.value = paste.substring(url.length).match(/^\/notes\/(.+?)\/?$/)?.[1] ?? null; }); + + if (canceled) { + insertTextAtCursor(textareaEl.value, paste); + return; + } + + quoteId.value = paste.substring(url.length).match(/^\/notes\/(.+?)\/?$/)?.[1] ?? null; } if (paste.length > 1000) { ev.preventDefault(); - os.confirm({ + + const { canceled } = await os.confirm({ type: 'info', text: i18n.ts.attachAsFileQuestion, - }).then(({ canceled }) => { - if (canceled) { - insertTextAtCursor(textareaEl.value, paste); - return; - } - - const fileName = formatTimeString(new Date(), pastedFileName).replace(/{{number}}/g, '0'); - const file = new File([paste], `${fileName}.txt`, { type: 'text/plain' }); - uploader.addFiles([file]); }); + + if (canceled) { + insertTextAtCursor(textareaEl.value, paste); + return; + } + + const fileName = formatTimeString(new Date(), pastedFileName).replace(/{{number}}/g, '0'); + const file = new File([paste], `${fileName}.txt`, { type: 'text/plain' }); + uploader.addFiles([file]); } } -function onDragover(ev) { - if (!ev.dataTransfer.items[0]) return; +function onDragover(ev: DragEvent) { + if (ev.dataTransfer == null) return; + if (ev.dataTransfer.items[0] == null) return; + const isFile = ev.dataTransfer.items[0].kind === 'file'; if (isFile || checkDragDataType(ev, ['driveFiles'])) { ev.preventDefault(); @@ -852,13 +857,32 @@ function onDrop(ev: DragEvent): void { //#endregion } +type StoredDrafts = { + [key: string]: { + updatedAt: string; + data: { + text: string; + useCw: boolean; + cw: string | null; + visibility: 'public' | 'home' | 'followers' | 'specified'; + localOnly: boolean; + files: Misskey.entities.DriveFile[]; + poll: PollEditorModelValue | null; + visibleUserIds?: string[]; + quoteId: string | null; + reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null; + scheduledAt: number | null; + }; + }; +}; + function saveDraft() { if (props.instant || props.mock) return; - const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}'); + const draftsData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}') as StoredDrafts; - draftData[draftKey.value] = { - updatedAt: new Date(), + draftsData[draftKey.value] = { + updatedAt: new Date().toISOString(), data: { text: text.value, useCw: useCw.value, @@ -874,15 +898,15 @@ function saveDraft() { }, }; - miLocalStorage.setItem('drafts', JSON.stringify(draftData)); + miLocalStorage.setItem('drafts', JSON.stringify(draftsData)); } function deleteDraft() { - const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}'); + const draftsData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}') as StoredDrafts; - delete draftData[draftKey.value]; + delete draftsData[draftKey.value]; - miLocalStorage.setItem('drafts', JSON.stringify(draftData)); + miLocalStorage.setItem('drafts', JSON.stringify(draftsData)); } async function saveServerDraft(options: { @@ -924,8 +948,8 @@ async function uploadFiles() { } } -async function post(ev?: MouseEvent) { - if (ev) { +async function post(ev?: PointerEvent) { + if (ev != null) { const el = (ev.currentTarget ?? ev.target) as HTMLElement | null; if (el && prefer.s.animation) { @@ -1138,11 +1162,12 @@ function cancel() { function insertMention() { os.selectUser({ localOnly: localOnly.value, includeSelf: true }).then(user => { + if (textareaEl.value == null) return; insertTextAtCursor(textareaEl.value, '@' + Misskey.acct.toString(user) + ' '); }); } -async function insertEmoji(ev: MouseEvent) { +async function insertEmoji(ev: PointerEvent) { textAreaReadOnly.value = true; const target = ev.currentTarget ?? ev.target; if (target == null) return; @@ -1176,7 +1201,7 @@ async function insertEmoji(ev: MouseEvent) { ); } -async function insertMfmFunction(ev: MouseEvent) { +async function insertMfmFunction(ev: PointerEvent) { if (textareaEl.value == null) return; let pos = textareaEl.value.selectionStart ?? 0; let posEnd = textareaEl.value.selectionEnd ?? text.value.length; @@ -1204,7 +1229,7 @@ async function insertMfmFunction(ev: MouseEvent) { ); } -function showActions(ev: MouseEvent) { +function showActions(ev: PointerEvent) { os.popupMenu(postFormActions.map(action => ({ text: action.title, action: () => { @@ -1222,7 +1247,7 @@ function showActions(ev: MouseEvent) { const postAccount = ref<Misskey.entities.UserDetailed | null>(null); -async function openAccountMenu(ev: MouseEvent) { +async function openAccountMenu(ev: PointerEvent) { if (props.mock) return; function showDraftsDialog(scheduled: boolean) { @@ -1312,12 +1337,12 @@ async function openAccountMenu(ev: MouseEvent) { }, { type: 'divider' }, ...items], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); } -function showPerUploadItemMenu(item: UploaderItem, ev: MouseEvent) { +function showPerUploadItemMenu(item: UploaderItem, ev: PointerEvent) { const menu = uploader.getMenu(item); os.popupMenu(menu, ev.currentTarget ?? ev.target); } -function showPerUploadItemMenuViaContextmenu(item: UploaderItem, ev: MouseEvent) { +function showPerUploadItemMenuViaContextmenu(item: UploaderItem, ev: PointerEvent) { const menu = uploader.getMenu(item); os.contextMenu(menu, ev); } @@ -1392,8 +1417,8 @@ onMounted(() => { nextTick(() => { // 書きかけの投稿を復元 if (!props.instant && !props.mention && !props.specified && !props.mock) { - const draft = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}')[draftKey.value]; - if (draft) { + const draft = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}')[draftKey.value] as StoredDrafts[string] | undefined; + if (draft != null) { text.value = draft.data.text; useCw.value = draft.data.useCw; cw.value = draft.data.cw; diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue index d198c98404..2d6e7ec6b3 100644 --- a/packages/frontend/src/components/MkPostFormAttaches.vue +++ b/packages/frontend/src/components/MkPostFormAttaches.vue @@ -97,7 +97,7 @@ async function detachAndDeleteMedia(file: Misskey.entities.DriveFile) { globalEvents.emit('driveFilesDeleted', [file]); } -function toggleSensitive(file) { +function toggleSensitive(file: Misskey.entities.DriveFile) { if (mock) { emit('changeSensitive', file, !file.isSensitive); return; @@ -111,7 +111,7 @@ function toggleSensitive(file) { }); } -async function rename(file) { +async function rename(file: Misskey.entities.DriveFile) { if (mock) return; const { canceled, result } = await os.inputText({ @@ -149,7 +149,7 @@ async function describe(file: Misskey.entities.DriveFile) { }); } -function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | KeyboardEvent): void { +function showFileMenu(file: Misskey.entities.DriveFile, ev: PointerEvent | KeyboardEvent): void { if (menuShowing) return; const isImage = file.type.startsWith('image/'); diff --git a/packages/frontend/src/components/MkPreferenceContainer.vue b/packages/frontend/src/components/MkPreferenceContainer.vue index 70b111513c..1ce608dda9 100644 --- a/packages/frontend/src/components/MkPreferenceContainer.vue +++ b/packages/frontend/src/components/MkPreferenceContainer.vue @@ -32,7 +32,7 @@ const props = withDefaults(defineProps<{ const isAccountOverrided = ref(prefer.isAccountOverrided(props.k)); const isSyncEnabled = ref(prefer.isSyncEnabled(props.k)); -function showMenu(ev: MouseEvent, contextmenu?: boolean) { +function showMenu(ev: PointerEvent, contextmenu?: boolean) { const i = window.setInterval(() => { isAccountOverrided.value = prefer.isAccountOverrided(props.k); isSyncEnabled.value = prefer.isSyncEnabled(props.k); diff --git a/packages/frontend/src/components/MkPreview.vue b/packages/frontend/src/components/MkPreview.vue index 6c7bf6be6b..c25f9ab0a9 100644 --- a/packages/frontend/src/components/MkPreview.vue +++ b/packages/frontend/src/components/MkPreview.vue @@ -89,7 +89,7 @@ const selectUser = async () => { await os.selectUser(); }; -const openMenu = async (ev: Event) => { +const openMenu = async (ev: PointerEvent) => { os.popupMenu([{ type: 'label', text: 'Fruits', diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 7c60288883..a89f947fa7 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -153,7 +153,7 @@ async function toggleReaction() { } } -async function menu(ev) { +async function menu(ev: PointerEvent) { let menuItems: MenuItem[] = []; if (canGetInfo.value) { diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue index bd9ef50157..ab7f86842c 100644 --- a/packages/frontend/src/components/MkReactionsViewer.vue +++ b/packages/frontend/src/components/MkReactionsViewer.vue @@ -32,11 +32,11 @@ SPDX-License-Identifier: AGPL-3.0-only import * as Misskey from 'misskey-js'; import { inject, watch, ref } from 'vue'; import { TransitionGroup } from 'vue'; +import { isSupportedEmoji } from '@@/js/emojilist.js'; import XReaction from '@/components/MkReactionsViewer.reaction.vue'; import { $i } from '@/i.js'; import { prefer } from '@/preferences.js'; import { customEmojisMap } from '@/custom-emojis.js'; -import { isSupportedEmoji } from '@@/js/emojilist.js'; import { DI } from '@/di.js'; const props = withDefaults(defineProps<{ @@ -60,8 +60,8 @@ const initialReactions = new Set(Object.keys(props.reactions)); const _reactions = ref<[string, number][]>([]); const hasMoreReactions = ref(false); -if (props.myReaction && !Object.keys(_reactions.value).includes(props.myReaction)) { - _reactions.value[props.myReaction] = props.reactions[props.myReaction]; +if (props.myReaction != null && !(props.myReaction in props.reactions)) { + _reactions.value.push([props.myReaction, props.reactions[props.myReaction]]); } function onMockToggleReaction(emoji: string, count: number) { diff --git a/packages/frontend/src/components/MkRetentionHeatmap.vue b/packages/frontend/src/components/MkRetentionHeatmap.vue index a204bc3bf1..6ab7a01ce7 100644 --- a/packages/frontend/src/components/MkRetentionHeatmap.vue +++ b/packages/frontend/src/components/MkRetentionHeatmap.vue @@ -98,7 +98,7 @@ async function renderChart() { data: data as any, borderWidth: 0, borderRadius: 3, - backgroundColor(c) { + backgroundColor(c: any) { const v = c.dataset.data[c.dataIndex] as unknown as typeof data[0]; const value = v.v; const m = max(v.y); @@ -179,7 +179,7 @@ async function renderChart() { enabled: false, callbacks: { title(context) { - const v = context[0].dataset.data[context[0].dataIndex]; + const v = context[0].dataset.data[context[0].dataIndex] as unknown as typeof data[0]; return getYYYYMMDD(new Date(new Date(v.y).getTime() + (v.x * 86400000))); }, label(context) { diff --git a/packages/frontend/src/components/MkRoleSelectDialog.vue b/packages/frontend/src/components/MkRoleSelectDialog.vue index 937804703d..651165136a 100644 --- a/packages/frontend/src/components/MkRoleSelectDialog.vue +++ b/packages/frontend/src/components/MkRoleSelectDialog.vue @@ -55,9 +55,9 @@ import MkModalWindow from '@/components/MkModalWindow.vue'; import MkLoading from '@/components/global/MkLoading.vue'; const emit = defineEmits<{ - (ev: 'done', value: Misskey.entities.Role[]), - (ev: 'close'), - (ev: 'closed'), + (ev: 'done', value: Misskey.entities.Role[]): void; + (ev: 'close'): void; + (ev: 'closed'): void; }>(); const props = withDefaults(defineProps<{ diff --git a/packages/frontend/src/components/MkServerSetupWizardDialog.vue b/packages/frontend/src/components/MkServerSetupWizardDialog.vue index ea2c5dd47f..1d03438f83 100644 --- a/packages/frontend/src/components/MkServerSetupWizardDialog.vue +++ b/packages/frontend/src/components/MkServerSetupWizardDialog.vue @@ -33,7 +33,7 @@ import MkModalWindow from '@/components/MkModalWindow.vue'; import MkServerSetupWizard from '@/components/MkServerSetupWizard.vue'; const emit = defineEmits<{ - (ev: 'closed'), + (ev: 'closed'): void; }>(); const windowEl = useTemplateRef('windowEl'); diff --git a/packages/frontend/src/components/MkSignin.input.vue b/packages/frontend/src/components/MkSignin.input.vue index 4c73eab3f5..89ec6373cf 100644 --- a/packages/frontend/src/components/MkSignin.input.vue +++ b/packages/frontend/src/components/MkSignin.input.vue @@ -78,7 +78,7 @@ const props = withDefaults(defineProps<{ const emit = defineEmits<{ (ev: 'usernameSubmitted', v: string): void; - (ev: 'passkeyClick', v: MouseEvent): void; + (ev: 'passkeyClick', v: PointerEvent): void; }>(); const host = toUnicode(configHost); diff --git a/packages/frontend/src/components/MkSortOrderEditor.vue b/packages/frontend/src/components/MkSortOrderEditor.vue index 27ffc724ae..3ac809cdbf 100644 --- a/packages/frontend/src/components/MkSortOrderEditor.vue +++ b/packages/frontend/src/components/MkSortOrderEditor.vue @@ -25,11 +25,11 @@ SPDX-License-Identifier: AGPL-3.0-only <script setup lang="ts" generic="T extends string"> import { toRefs } from 'vue'; +import type { MenuItem } from '@/types/menu.js'; +import type { SortOrder } from '@/components/MkSortOrderEditor.define.js'; import MkTagItem from '@/components/MkTagItem.vue'; import MkButton from '@/components/MkButton.vue'; -import type { MenuItem } from '@/types/menu.js'; import * as os from '@/os.js'; -import type { SortOrder } from '@/components/MkSortOrderEditor.define.js'; const emit = defineEmits<{ (ev: 'update', sortOrders: SortOrder<T>[]): void; @@ -55,7 +55,7 @@ function onToggleSortOrderButtonClicked(order: SortOrder<T>) { emitOrder(currentOrders.value); } -function onAddSortOrderButtonClicked(ev: MouseEvent) { +function onAddSortOrderButtonClicked(ev: PointerEvent) { const menuItems: MenuItem[] = props.baseOrderKeyNames .filter(baseKey => !currentOrders.value.map(it => it.key).includes(baseKey)) .map(it => { diff --git a/packages/frontend/src/components/MkSpot.vue b/packages/frontend/src/components/MkSpot.vue index 4a8ebb5f94..4bd11fe938 100644 --- a/packages/frontend/src/components/MkSpot.vue +++ b/packages/frontend/src/components/MkSpot.vue @@ -88,7 +88,7 @@ function setPosition() { bodyEl.value.style.top = data.top + 'px'; } -let loopHandler; +let loopHandler: number | null = null; onMounted(() => { nextTick(() => { @@ -104,7 +104,7 @@ onMounted(() => { }); onUnmounted(() => { - window.cancelAnimationFrame(loopHandler); + if (loopHandler != null) window.cancelAnimationFrame(loopHandler); }); </script> diff --git a/packages/frontend/src/components/MkStreamingNotesTimeline.vue b/packages/frontend/src/components/MkStreamingNotesTimeline.vue index bc6ebf0918..9784d8e017 100644 --- a/packages/frontend/src/components/MkStreamingNotesTimeline.vue +++ b/packages/frontend/src/components/MkStreamingNotesTimeline.vue @@ -350,13 +350,12 @@ function connectChannel() { connections.main = stream.useChannel('main'); connections.main.on('mention', prepend); } else if (props.src === 'directs') { - const onNote = note => { + connections.main = stream.useChannel('main'); + connections.main.on('mention', note => { if (note.visibility === 'specified') { prepend(note); } - }; - connections.main = stream.useChannel('main'); - connections.main.on('mention', onNote); + }); } else if (props.src === 'list') { if (props.list == null) return; connections.userList = stream.useChannel('userList', { diff --git a/packages/frontend/src/components/MkStreamingNotificationsTimeline.vue b/packages/frontend/src/components/MkStreamingNotificationsTimeline.vue index 6ee2e347a5..91f071fe63 100644 --- a/packages/frontend/src/components/MkStreamingNotificationsTimeline.vue +++ b/packages/frontend/src/components/MkStreamingNotificationsTimeline.vue @@ -137,8 +137,8 @@ watch(visibility, () => { } }); -function onNotification(notification) { - const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type) : false; +function onNotification(notification: Misskey.entities.Notification) { + const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type as typeof notificationTypes[number]) : false; if (isMuted || window.document.visibilityState === 'visible') { if (store.s.realtimeMode) { useStream().send('readNotification'); diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue index 236afa127c..585a628a96 100644 --- a/packages/frontend/src/components/MkSuperMenu.vue +++ b/packages/frontend/src/components/MkSuperMenu.vue @@ -82,7 +82,7 @@ export type SuperMenuDef = { text: string; danger?: boolean; active?: boolean; - action: (ev: MouseEvent) => Awaitable<void>; + action: (ev: PointerEvent) => Awaitable<void>; } | { type?: 'link'; to: string; diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.vue b/packages/frontend/src/components/MkSystemWebhookEditor.vue index cd72204fce..1536b14455 100644 --- a/packages/frontend/src/components/MkSystemWebhookEditor.vue +++ b/packages/frontend/src/components/MkSystemWebhookEditor.vue @@ -245,7 +245,7 @@ onMounted(async () => { secret.value = res.secret; isActive.value = res.isActive; for (const ev of Object.keys(events.value)) { - events.value[ev] = res.on.includes(ev as SystemWebhookEventType); + events.value[ev as SystemWebhookEventType] = res.on.includes(ev as SystemWebhookEventType); } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (ex: any) { diff --git a/packages/frontend/src/components/MkTabs.vue b/packages/frontend/src/components/MkTabs.vue index 9798e2c3b3..a6342ec2e1 100644 --- a/packages/frontend/src/components/MkTabs.vue +++ b/packages/frontend/src/components/MkTabs.vue @@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts"> export type Tab<K = string> = { key: K; - onClick?: (ev: MouseEvent) => void; + onClick?: (ev: PointerEvent) => void; iconOnly?: boolean; title: string; icon?: string; @@ -74,7 +74,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'tabClick', key: string); + (ev: 'tabClick', key: string): void; }>(); const tab = defineModel<T['key']>('tab'); @@ -100,7 +100,7 @@ function onTabMousedown(selectedTab: Tab, ev: MouseEvent): void { } } -function onTabClick(t: Tab, ev: MouseEvent): void { +function onTabClick(t: Tab, ev: PointerEvent): void { emit('tabClick', t.key); if (t.onClick) { diff --git a/packages/frontend/src/components/MkTagItem.vue b/packages/frontend/src/components/MkTagItem.vue index be735e6407..5cd2113e59 100644 --- a/packages/frontend/src/components/MkTagItem.vue +++ b/packages/frontend/src/components/MkTagItem.vue @@ -17,8 +17,8 @@ SPDX-License-Identifier: AGPL-3.0-only import MkButton from '@/components/MkButton.vue'; const emit = defineEmits<{ - (ev: 'click', payload: MouseEvent): void; - (ev: 'exButtonClick', payload: MouseEvent): void; + (ev: 'click', payload: PointerEvent): void; + (ev: 'exButtonClick', payload: PointerEvent): void; }>(); defineProps<{ diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue index 407ac33add..d53d4ec018 100644 --- a/packages/frontend/src/components/MkTextarea.vue +++ b/packages/frontend/src/components/MkTextarea.vue @@ -63,7 +63,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'change', _ev: KeyboardEvent): void; + (ev: 'change', _ev: InputEvent): void; (ev: 'keydown', _ev: KeyboardEvent): void; (ev: 'enter'): void; (ev: 'update:modelValue', value: string): void; @@ -79,12 +79,16 @@ const inputEl = useTemplateRef('inputEl'); const preview = ref(false); let autocompleteWorker: Autocomplete | null = null; -const focus = () => inputEl.value?.focus(); -const onInput = (ev) => { +function focus() { + inputEl.value?.focus(); +} + +function onInput(ev: InputEvent) { changed.value = true; emit('change', ev); -}; -const onKeydown = (ev: KeyboardEvent) => { +} + +function onKeydown(ev: KeyboardEvent) { if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return; emit('keydown', ev); @@ -102,12 +106,12 @@ const onKeydown = (ev: KeyboardEvent) => { }); ev.preventDefault(); } -}; +} -const updated = () => { +function updated() { changed.value = false; emit('update:modelValue', v.value ?? ''); -}; +} const debouncedUpdated = debounce(1000, updated); diff --git a/packages/frontend/src/components/MkTokenGenerateWindow.vue b/packages/frontend/src/components/MkTokenGenerateWindow.vue index 42cb6f1e82..8d51e1fa87 100644 --- a/packages/frontend/src/components/MkTokenGenerateWindow.vue +++ b/packages/frontend/src/components/MkTokenGenerateWindow.vue @@ -33,12 +33,12 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton inline @click="enableAll">{{ i18n.ts.enableAll }}</MkButton> </div> <div class="_gaps_s"> - <MkSwitch v-for="kind in Object.keys(permissionSwitches)" :key="kind" v-model="permissionSwitches[kind]">{{ i18n.ts._permissions[kind] }}</MkSwitch> + <MkSwitch v-for="kind in Object.keys(permissionSwitches)" :key="kind" v-model="permissionSwitches[kind as keyof typeof permissionSwitches]">{{ i18n.ts._permissions[kind as keyof typeof permissionSwitches] }}</MkSwitch> </div> <div v-if="iAmAdmin" :class="$style.adminPermissions"> <div :class="$style.adminPermissionsHeader"><b>{{ i18n.ts.adminPermission }}</b></div> <div class="_gaps_s"> - <MkSwitch v-for="kind in Object.keys(permissionSwitchesForAdmin)" :key="kind" v-model="permissionSwitchesForAdmin[kind]">{{ i18n.ts._permissions[kind] }}</MkSwitch> + <MkSwitch v-for="kind in Object.keys(permissionSwitchesForAdmin)" :key="kind" v-model="permissionSwitchesForAdmin[kind as keyof typeof permissionSwitchesForAdmin]">{{ i18n.ts._permissions[kind as keyof typeof permissionSwitchesForAdmin] }}</MkSwitch> </div> </div> </div> @@ -102,8 +102,8 @@ function ok(): void { emit('done', { name: name.value, permissions: [ - ...Object.keys(permissionSwitches.value).filter(p => permissionSwitches.value[p]), - ...(iAmAdmin ? Object.keys(permissionSwitchesForAdmin.value).filter(p => permissionSwitchesForAdmin.value[p]) : []), + ...Object.keys(permissionSwitches.value).filter(p => permissionSwitches.value[p as (typeof Misskey.permissions)[number]]), + ...(iAmAdmin ? Object.keys(permissionSwitchesForAdmin.value).filter(p => permissionSwitchesForAdmin.value[p as (typeof Misskey.permissions)[number]]) : []), ], }); dialog.value?.close(); @@ -111,22 +111,22 @@ function ok(): void { function disableAll(): void { for (const p in permissionSwitches.value) { - permissionSwitches.value[p] = false; + permissionSwitches.value[p as (typeof Misskey.permissions)[number]] = false; } if (iAmAdmin) { for (const p in permissionSwitchesForAdmin.value) { - permissionSwitchesForAdmin.value[p] = false; + permissionSwitchesForAdmin.value[p as (typeof Misskey.permissions)[number]] = false; } } } function enableAll(): void { for (const p in permissionSwitches.value) { - permissionSwitches.value[p] = true; + permissionSwitches.value[p as (typeof Misskey.permissions)[number]] = true; } if (iAmAdmin) { for (const p in permissionSwitchesForAdmin.value) { - permissionSwitchesForAdmin.value[p] = true; + permissionSwitchesForAdmin.value[p as (typeof Misskey.permissions)[number]] = true; } } } diff --git a/packages/frontend/src/components/MkTooltip.vue b/packages/frontend/src/components/MkTooltip.vue index aa041c88e5..08a3f02f65 100644 --- a/packages/frontend/src/components/MkTooltip.vue +++ b/packages/frontend/src/components/MkTooltip.vue @@ -71,7 +71,7 @@ function setPosition() { el.value.style.top = data.top + 'px'; } -let loopHandler; +let loopHandler: number | null = null; onMounted(() => { nextTick(() => { @@ -87,7 +87,7 @@ onMounted(() => { }); onUnmounted(() => { - window.cancelAnimationFrame(loopHandler); + if (loopHandler != null) window.cancelAnimationFrame(loopHandler); }); </script> diff --git a/packages/frontend/src/components/MkTutorialDialog.Note.vue b/packages/frontend/src/components/MkTutorialDialog.Note.vue index b77e67e9c6..3ab2c5f0d4 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Note.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Note.vue @@ -74,7 +74,7 @@ const exampleNote = reactive<Misskey.entities.Note>({ }); const onceReacted = ref<boolean>(false); -function addReaction(emoji) { +function addReaction(emoji: string) { onceReacted.value = true; emit('reacted'); doNotification(emoji); @@ -96,7 +96,7 @@ function doNotification(emoji: string): void { globalEvents.emit('clientNotification', notification); } -function removeReaction(emoji) { +function removeReaction(emoji: string) { delete exampleNote.reactions[emoji]; exampleNote.myReaction = undefined; } diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index 8849fa447d..69de56d45c 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -166,17 +166,17 @@ async function done() { dialog.value?.close(); } -async function chooseFile(ev: MouseEvent) { +async function chooseFile(ev: PointerEvent) { const newFiles = await os.chooseFileFromPc({ multiple: true }); uploader.addFiles(newFiles); } -function showPerItemMenu(item: UploaderItem, ev: MouseEvent) { +function showPerItemMenu(item: UploaderItem, ev: PointerEvent) { const menu = uploader.getMenu(item); os.popupMenu(menu, ev.currentTarget ?? ev.target); } -function showPerItemMenuViaContextmenu(item: UploaderItem, ev: MouseEvent) { +function showPerItemMenuViaContextmenu(item: UploaderItem, ev: PointerEvent) { const menu = uploader.getMenu(item); os.contextMenu(menu, ev); } diff --git a/packages/frontend/src/components/MkUploaderItems.vue b/packages/frontend/src/components/MkUploaderItems.vue index f31c717ad5..51f7ac2d09 100644 --- a/packages/frontend/src/components/MkUploaderItems.vue +++ b/packages/frontend/src/components/MkUploaderItems.vue @@ -57,18 +57,18 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'showMenu', item: UploaderItem, event: MouseEvent): void; - (ev: 'showMenuViaContextmenu', item: UploaderItem, event: MouseEvent): void; + (ev: 'showMenu', item: UploaderItem, event: PointerEvent): void; + (ev: 'showMenuViaContextmenu', item: UploaderItem, event: PointerEvent): void; }>(); -function onContextmenu(item: UploaderItem, ev: MouseEvent) { +function onContextmenu(item: UploaderItem, ev: PointerEvent) { if (ev.target && isLink(ev.target as HTMLElement)) return; if (window.getSelection()?.toString() !== '') return; emit('showMenuViaContextmenu', item, ev); } -function onThumbnailClick(item: UploaderItem, ev: MouseEvent) { +function onThumbnailClick(item: UploaderItem, ev: PointerEvent) { // TODO: preview when item is image } </script> diff --git a/packages/frontend/src/components/MkUserList.vue b/packages/frontend/src/components/MkUserList.vue index f47d9b56dc..8ce929fff3 100644 --- a/packages/frontend/src/components/MkUserList.vue +++ b/packages/frontend/src/components/MkUserList.vue @@ -27,7 +27,7 @@ const props = withDefaults(defineProps<{ noGap?: boolean; extractor?: ExtractorFunction<P, Misskey.entities.UserDetailed>; }>(), { - extractor: (item) => item, + extractor: (item: any) => item as Misskey.entities.UserDetailed, }); </script> diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index f794899281..9f196ac2c1 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -90,7 +90,7 @@ const top = ref(0); const left = ref(0); const error = ref(false); -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { if (user.value == null) return; const { menu, cleanup } = getUserMenu(user.value); os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup); diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue index 4e96eff82e..95449dd0eb 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue @@ -66,7 +66,7 @@ watch(description, () => { }); }); -async function setAvatar(ev) { +async function setAvatar(ev: PointerEvent) { const files = await os.chooseFileFromPc({ multiple: false }); const file = files[0]; diff --git a/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue b/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue index 6aaee76565..6513ca385d 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue @@ -46,7 +46,7 @@ async function renderChart() { return new Date(y, m, d - ago); }; - const format = (arr) => { + const format = (arr: number[]) => { return arr.map((v, i) => ({ x: getDate(i).getTime(), y: v, diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue index 8bef225de5..2ce1912b86 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.vue @@ -94,7 +94,7 @@ function signup() { }); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { openInstanceMenu(ev); } </script> diff --git a/packages/frontend/src/components/MkWaitingDialog.vue b/packages/frontend/src/components/MkWaitingDialog.vue index 820cf05e1f..18f2b3e189 100644 --- a/packages/frontend/src/components/MkWaitingDialog.vue +++ b/packages/frontend/src/components/MkWaitingDialog.vue @@ -26,8 +26,8 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'done'); - (ev: 'closed'); + (ev: 'done'): void; + (ev: 'closed'): void; }>(); function done() { diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue index 154b3ffc27..8e5bb6221d 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue @@ -387,7 +387,7 @@ onMounted(async () => { } }); -function chooseFile(ev: MouseEvent) { +function chooseFile(ev: PointerEvent) { selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index 7fe497e455..cadf9ba522 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -350,7 +350,7 @@ async function save() { } } -function addLayer(ev: MouseEvent) { +function addLayer(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts._watermarkEditor.text, action: () => { diff --git a/packages/frontend/src/components/MkWidgetSettingsDialog.vue b/packages/frontend/src/components/MkWidgetSettingsDialog.vue index 951ac88465..63f294770c 100644 --- a/packages/frontend/src/components/MkWidgetSettingsDialog.vue +++ b/packages/frontend/src/components/MkWidgetSettingsDialog.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only @ok="save()" @closed="emit('closed')" > - <template #header><i class="ti ti-icons"></i> {{ i18n.ts._widgets[widgetName] ?? widgetName }}</template> + <template #header><i class="ti ti-icons"></i> {{ (i18n.ts._widgets as any)[widgetName] ?? widgetName }}</template> <MkPreviewWithControls> <template #preview> diff --git a/packages/frontend/src/components/MkWidgets.vue b/packages/frontend/src/components/MkWidgets.vue index e7712e8aae..a27613c24c 100644 --- a/packages/frontend/src/components/MkWidgets.vue +++ b/packages/frontend/src/components/MkWidgets.vue @@ -24,12 +24,12 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="[$style.widget, $style.customizeContainer]" data-cy-customize-container> <button :class="$style.customizeContainerConfig" class="_button" @click.prevent.stop="configWidget(item.id)"><i class="ti ti-settings"></i></button> <button :class="$style.customizeContainerRemove" data-cy-customize-container-remove class="_button" @click.prevent.stop="removeWidget(item)"><i class="ti ti-x"></i></button> - <component :is="`widget-${item.name}`" :ref="el => widgetRefs[item.id] = el" :class="$style.customizeContainerHandleWidget" :widget="item" @updateProps="updateWidget(item.id, $event)"/> + <component :is="`widget-${item.name}`" :ref="(el: any) => widgetRefs[item.id] = el" :class="$style.customizeContainerHandleWidget" :widget="item" @updateProps="updateWidget(item.id, $event)"/> </div> </template> </MkDraggable> </template> - <component :is="`widget-${widget.name}`" v-for="widget in _widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/> + <component :is="`widget-${widget.name}`" v-for="widget in _widgets" v-else :key="widget.id" :ref="(el: any) => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/> </div> </template> @@ -47,6 +47,7 @@ export type DefaultStoredWidget = { <script lang="ts" setup> import { computed } from 'vue'; import { isLink } from '@@/js/is-link.js'; +import type { Component } from 'vue'; import { genId } from '@/utility/id.js'; import MkSelect from '@/components/MkSelect.vue'; import MkButton from '@/components/MkButton.vue'; @@ -64,13 +65,13 @@ const props = defineProps<{ const _widgetDefs = computed(() => { if (instance.federation === 'none') { - return widgetDefs.filter(x => !federationWidgets.includes(x)); + return widgetDefs.filter(x => !federationWidgets.includes(x as any)); } else { return widgetDefs; } }); -const _widgets = computed(() => props.widgets.filter(x => _widgetDefs.value.includes(x.name))); +const _widgets = computed(() => props.widgets.filter(x => _widgetDefs.value.includes(x.name as any))); const emit = defineEmits<{ (ev: 'updateWidgets', widgets: Widget[]): void; @@ -80,10 +81,11 @@ const emit = defineEmits<{ (ev: 'exit'): void; }>(); -const widgetRefs = {}; -const configWidget = (id: string) => { +const widgetRefs = {} as Record<string, Component & { configure: () => void }>; + +function configWidget(id: string) { widgetRefs[id].configure(); -}; +} const { model: widgetAdderSelected, @@ -93,7 +95,7 @@ const { initialValue: null, }); -const addWidget = () => { +function addWidget() { if (widgetAdderSelected.value == null) return; emit('addWidget', { @@ -103,23 +105,25 @@ const addWidget = () => { }); widgetAdderSelected.value = null; -}; -const removeWidget = (widget) => { +} + +function removeWidget(widget: Widget) { emit('removeWidget', widget); -}; -const updateWidget = (id: Widget['id'], data: Widget['data']) => { +} + +function updateWidget(id: Widget['id'], data: Widget['data']) { emit('updateWidget', { id, data }); -}; +} -function onContextmenu(widget: Widget, ev: MouseEvent) { +function onContextmenu(widget: Widget, ev: PointerEvent) { const element = ev.target as HTMLElement | null; if (element && isLink(element)) return; - if (element && (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(element.tagName) || element.attributes['contenteditable'])) return; + if (element && (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(element.tagName) || element.attributes.getNamedItem('contenteditable') != null)) return; if (window.getSelection()?.toString() !== '') return; os.contextMenu([{ type: 'label', - text: i18n.ts._widgets[widget.name], + text: i18n.ts._widgets[widget.name as typeof widgetDefs[number]], }, { icon: 'ti ti-settings', text: i18n.ts.settings, diff --git a/packages/frontend/src/components/MkWindow.vue b/packages/frontend/src/components/MkWindow.vue index e5ac791d0b..7fb77da476 100644 --- a/packages/frontend/src/components/MkWindow.vue +++ b/packages/frontend/src/components/MkWindow.vue @@ -55,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onBeforeUnmount, onMounted, provide, useTemplateRef, ref } from 'vue'; import type { MenuItem } from '@/types/menu.js'; -import contains from '@/utility/contains.js'; +import { elementContains } from '@/utility/element-contains.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { prefer } from '@/preferences.js'; @@ -78,12 +78,12 @@ function dragListen(fn: (ev: MouseEvent | TouchEvent) => void) { window.addEventListener('touchend', dragClear.bind(null, fn)); } -function dragClear(fn) { +function dragClear(fn: (ev: MouseEvent | TouchEvent) => void) { window.removeEventListener('mousemove', fn); window.removeEventListener('touchmove', fn); - window.removeEventListener('mouseleave', dragClear); - window.removeEventListener('mouseup', dragClear); - window.removeEventListener('touchend', dragClear); + window.removeEventListener('mouseleave', dragClear as any); + window.removeEventListener('mouseup', dragClear as any); + window.removeEventListener('touchend', dragClear as any); } const props = withDefaults(defineProps<{ @@ -128,7 +128,7 @@ function close() { showing.value = false; } -function onKeydown(evt) { +function onKeydown(evt: KeyboardEvent) { if (evt.which === 27) { // Esc evt.preventDefault(); evt.stopPropagation(); @@ -136,7 +136,7 @@ function onKeydown(evt) { } } -function onContextmenu(ev: MouseEvent) { +function onContextmenu(ev: PointerEvent) { if (props.contextmenu) { os.contextMenu(props.contextmenu, ev); } @@ -240,7 +240,7 @@ function onHeaderMousedown(evt: MouseEvent | TouchEvent) { const main = rootEl.value; if (main == null) return; - if (!contains(main, window.document.activeElement)) main.focus(); + if (!elementContains(main, window.document.activeElement)) main.focus(); const position = main.getBoundingClientRect(); @@ -418,24 +418,24 @@ function onBottomLeftHandleMousedown(evt: MouseEvent | TouchEvent) { } // 高さを適用 -function applyTransformHeight(height) { +function applyTransformHeight(height: number) { if (height > window.innerHeight) height = window.innerHeight; if (rootEl.value) rootEl.value.style.height = height + 'px'; } // 幅を適用 -function applyTransformWidth(width) { +function applyTransformWidth(width: number) { if (width > window.innerWidth) width = window.innerWidth; if (rootEl.value) rootEl.value.style.width = width + 'px'; } // Y座標を適用 -function applyTransformTop(top) { +function applyTransformTop(top: number) { if (rootEl.value) rootEl.value.style.top = top + 'px'; } // X座標を適用 -function applyTransformLeft(left) { +function applyTransformLeft(left: number) { if (rootEl.value) rootEl.value.style.left = left + 'px'; } diff --git a/packages/frontend/src/components/global/I18n.vue b/packages/frontend/src/components/global/I18n.vue index 9866e50958..1fad1ee9e6 100644 --- a/packages/frontend/src/components/global/I18n.vue +++ b/packages/frontend/src/components/global/I18n.vue @@ -46,6 +46,6 @@ const parsed = computed(() => { }); const render = () => { - return h(props.tag, parsed.value.map(x => typeof x === 'string' ? (props.textTag ? h(props.textTag, x) : x) : slots[x.arg]())); + return h(props.tag, parsed.value.map(x => typeof x === 'string' ? (props.textTag ? h(props.textTag, x) : x) : (slots as any)[x.arg]())); }; </script> diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue index 99693a4c00..7d2908d4be 100644 --- a/packages/frontend/src/components/global/MkA.vue +++ b/packages/frontend/src/components/global/MkA.vue @@ -48,7 +48,7 @@ const active = computed(() => { return resolved.route.name === router.currentRoute.value.name; }); -function onContextmenu(ev) { +function onContextmenu(ev: PointerEvent) { const selection = window.getSelection(); if (selection && selection.toString() !== '') return; os.contextMenu([{ @@ -85,7 +85,7 @@ function openWindow() { os.pageWindow(props.to); } -function nav(ev: MouseEvent) { +function nav(ev: PointerEvent) { // 制御キーとの組み合わせは無視(shiftを除く) if (ev.metaKey || ev.altKey || ev.ctrlKey) return; diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index e7208ed574..fd1d0c2b63 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -77,7 +77,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'click', v: MouseEvent): void; + (ev: 'click', v: PointerEvent): void; }>(); const showDecoration = props.forceShowDecoration || prefer.s.showAvatarDecorations; @@ -91,7 +91,7 @@ const url = computed(() => { return props.user.avatarUrl; }); -function onClick(ev: MouseEvent): void { +function onClick(ev: PointerEvent): void { if (props.link) return; emit('click', ev); } diff --git a/packages/frontend/src/components/global/MkCondensedLine.vue b/packages/frontend/src/components/global/MkCondensedLine.vue index 473d444c16..e1fbec4b6f 100644 --- a/packages/frontend/src/components/global/MkCondensedLine.vue +++ b/packages/frontend/src/components/global/MkCondensedLine.vue @@ -23,8 +23,8 @@ const observer = new ResizeObserver((entries) => { transform: string; }[] = []; for (const entry of entries) { - const content = (entry.target[contentSymbol] ? entry.target : entry.target.firstElementChild) as HTMLSpanElement; - const props: Required<Props> = content[contentSymbol]; + const content = ((entry.target as any)[contentSymbol] ? entry.target : entry.target.firstElementChild) as HTMLSpanElement; + const props: Required<Props> = (content as any)[contentSymbol]; const container = content.parentElement as HTMLSpanElement; const contentWidth = content.getBoundingClientRect().width; const containerWidth = container.getBoundingClientRect().width; @@ -46,15 +46,15 @@ const props = withDefaults(defineProps<Props>(), { const content = ref<HTMLSpanElement>(); watch(content, (value, oldValue) => { - if (oldValue) { - delete oldValue[contentSymbol]; + if (oldValue != null) { + delete (oldValue as any)[contentSymbol]; observer.unobserve(oldValue); if (oldValue.parentElement) { observer.unobserve(oldValue.parentElement); } } - if (value) { - value[contentSymbol] = props; + if (value != null) { + (value as any)[contentSymbol] = props; observer.observe(value); if (value.parentElement) { observer.observe(value.parentElement); diff --git a/packages/frontend/src/components/global/MkCustomEmoji.vue b/packages/frontend/src/components/global/MkCustomEmoji.vue index 31c358eee7..9a171876a0 100644 --- a/packages/frontend/src/components/global/MkCustomEmoji.vue +++ b/packages/frontend/src/components/global/MkCustomEmoji.vue @@ -102,7 +102,7 @@ const url = computed(() => { const alt = computed(() => `:${customEmojiName.value}:`); const errored = ref(url.value == null); -function onClick(ev: MouseEvent) { +function onClick(ev: PointerEvent) { if (props.menu) { const menuItems: MenuItem[] = []; diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue index 792f9c7d6f..686720cec2 100644 --- a/packages/frontend/src/components/global/MkEmoji.vue +++ b/packages/frontend/src/components/global/MkEmoji.vue @@ -67,7 +67,7 @@ function unmute() { }); } -function onClick(ev: MouseEvent) { +function onClick(ev: PointerEvent) { if (props.menu) { const menuItems: MenuItem[] = []; diff --git a/packages/frontend/src/components/global/MkMfm.ts b/packages/frontend/src/components/global/MkMfm.ts index 3ad2fda0ee..d270571d4a 100644 --- a/packages/frontend/src/components/global/MkMfm.ts +++ b/packages/frontend/src/components/global/MkMfm.ts @@ -319,7 +319,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven ]); } case 'clickable': { - return h('span', { onClick(ev: MouseEvent): void { + return h('span', { onClick(ev: PointerEvent): void { ev.stopPropagation(); ev.preventDefault(); const clickEv = typeof token.props.args.ev === 'string' ? token.props.args.ev : ''; diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.vue b/packages/frontend/src/components/global/MkPageHeader.tabs.vue index 1ef75281fd..857fd3d8b4 100644 --- a/packages/frontend/src/components/global/MkPageHeader.tabs.vue +++ b/packages/frontend/src/components/global/MkPageHeader.tabs.vue @@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts"> export type Tab = { key: string; - onClick?: (ev: MouseEvent) => void; + onClick?: (ev: PointerEvent) => void; iconOnly?: boolean; title: string; icon?: string; @@ -70,8 +70,8 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'update:tab', key: string); - (ev: 'tabClick', key: string); + (ev: 'update:tab', key: string): void; + (ev: 'tabClick', key: string): void; }>(); const el = useTemplateRef('el'); @@ -96,7 +96,7 @@ function onTabMousedown(tab: Tab, ev: MouseEvent): void { } } -function onTabClick(t: Tab, ev: MouseEvent): void { +function onTabClick(t: Tab, ev: PointerEvent): void { emit('tabClick', t.key); if (t.onClick) { diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 2445f8e0ef..e8c93b7092 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -61,7 +61,6 @@ export type PageHeaderProps = { import { onMounted, onUnmounted, ref, inject, useTemplateRef, computed } from 'vue'; import { scrollToTop } from '@@/js/scroll.js'; import XTabs from './MkPageHeader.tabs.vue'; -import { globalEvents } from '@/events.js'; import { getAccountMenu } from '@/accounts.js'; import { $i } from '@/i.js'; import { DI } from '@/di.js'; @@ -72,7 +71,7 @@ const props = withDefaults(defineProps<PageHeaderProps>(), { }); const emit = defineEmits<{ - (ev: 'update:tab', key: string); + (ev: 'update:tab', key: string): void; }>(); //const viewId = inject(DI.viewId); @@ -100,7 +99,7 @@ const top = () => { } }; -async function openAccountMenu(ev: MouseEvent) { +async function openAccountMenu(ev: PointerEvent) { const menuItems = await getAccountMenu({ withExtraOperation: true, }); diff --git a/packages/frontend/src/components/global/MkTip.vue b/packages/frontend/src/components/global/MkTip.vue index 231957a232..1827c16c89 100644 --- a/packages/frontend/src/components/global/MkTip.vue +++ b/packages/frontend/src/components/global/MkTip.vue @@ -32,7 +32,7 @@ function _closeTip() { closeTip(props.k); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { os.popupMenu([{ icon: 'ti ti-bulb-off', text: i18n.ts.hideAllTips, diff --git a/packages/frontend/src/components/grid/MkDataCell.vue b/packages/frontend/src/components/grid/MkDataCell.vue index 6f1dae8398..8745146ccf 100644 --- a/packages/frontend/src/components/grid/MkDataCell.vue +++ b/packages/frontend/src/components/grid/MkDataCell.vue @@ -188,7 +188,7 @@ function onCellKeyDown(ev: KeyboardEvent) { } } -function onInputText(ev: Event) { +function onInputText(ev: InputEvent) { editingValue.value = (ev.target as HTMLInputElement).value; } diff --git a/packages/frontend/src/components/grid/MkGrid.vue b/packages/frontend/src/components/grid/MkGrid.vue index 96d9e35773..097a91bad5 100644 --- a/packages/frontend/src/components/grid/MkGrid.vue +++ b/packages/frontend/src/components/grid/MkGrid.vue @@ -715,7 +715,7 @@ function onMouseUp(ev: MouseEvent) { } } -function onContextMenu(ev: MouseEvent) { +function onContextMenu(ev: PointerEvent) { const cellAddress = getCellAddress(ev.target as HTMLElement); if (_DEV_) { console.log(`[grid][context-menu] button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`); |