fix type errors of components

This commit is contained in:
Lhcfl 2024-04-12 22:02:03 +08:00
parent f422842aef
commit 393ab2590d
20 changed files with 170 additions and 112 deletions

View File

@ -16,7 +16,7 @@
v-else
class="bghgjjyj _button"
:class="{ inline, primary, gradate, danger, rounded, full, mini }"
:to="to"
:to="to!"
@mousedown="onMousedown"
>
<div ref="ripples" class="ripples"></div>
@ -36,6 +36,7 @@ const props = defineProps<{
gradate?: boolean;
rounded?: boolean;
inline?: boolean;
// FIXME: if `link`, `to` is necessary
link?: boolean;
to?: string;
autofocus?: boolean;

View File

@ -28,11 +28,11 @@
</template>
<script lang="ts" setup>
import {} from "vue";
import type { Ref } from "vue";
import MkTooltip from "./MkTooltip.vue";
const props = defineProps<{
showing: boolean;
showing: Ref<boolean>;
x: number;
y: number;
title?: string;

View File

@ -104,7 +104,7 @@
</MkInput>
<MkTextarea
v-if="input && input.type === 'paragraph'"
v-model="inputValue"
v-model="(inputValue as string)"
autofocus
type="paragraph"
:placeholder="input.placeholder || undefined"
@ -204,7 +204,16 @@ import { i18n } from "@/i18n";
import iconify from "@/scripts/icon";
interface Input {
type: HTMLInputElement["type"];
type?:
| "text"
| "number"
| "password"
| "email"
| "url"
| "date"
| "time"
| "search"
| "paragraph";
placeholder?: string | null;
autocomplete?: string;
default: string | number | null;
@ -237,8 +246,8 @@ const props = withDefaults(
| "question"
| "waiting"
| "search";
title: string;
text?: string;
title?: string | null;
text?: string | null;
isPlaintext?: boolean;
input?: Input;
select?: Select;
@ -246,7 +255,7 @@ const props = withDefaults(
actions?: {
text: string;
primary?: boolean;
callback: (...args: any[]) => void;
callback: () => void;
}[];
showOkButton?: boolean;
showCancelButton?: boolean;
@ -268,7 +277,10 @@ const props = withDefaults(
);
const emit = defineEmits<{
(ev: "done", v: { canceled: boolean; result: any }): void;
(
ev: "done",
v: { canceled: boolean; result?: string | number | boolean | null },
): void;
(ev: "closed"): void;
}>();
@ -306,7 +318,7 @@ const okButtonDisabled = computed<boolean>(() => {
const inputEl = ref<typeof MkInput>();
function done(canceled: boolean, result?) {
function done(canceled: boolean, result?: string | number | boolean | null) {
emit("done", { canceled, result });
modal.value?.close(null);
}
@ -342,12 +354,12 @@ function onInputKeydown(evt: KeyboardEvent) {
}
}
function formatDateToYYYYMMDD(date) {
const year = date.getFullYear();
const month = ("0" + (date.getMonth() + 1)).slice(-2);
const day = ("0" + (date.getDate() + 1)).slice(-2);
return `${year}-${month}-${day}`;
}
// function formatDateToYYYYMMDD(date) {
// const year = date.getFullYear();
// const month = ("0" + (date.getMonth() + 1)).slice(-2);
// const day = ("0" + (date.getDate() + 1)).slice(-2);
// return `${year}-${month}-${day}`;
// }
/**
* Appends a new search parameter to the value in the input field.
@ -355,18 +367,18 @@ function formatDateToYYYYMMDD(date) {
* begin typing a new criteria.
* @param value The value to append.
*/
function appendFilter(value: string) {
return (
[
typeof inputValue.value === "string"
? inputValue.value.trim()
: inputValue.value,
value,
]
.join(" ")
.trim() + " "
);
}
// function appendFilter(value: string) {
// return (
// [
// typeof inputValue.value === "string"
// ? inputValue.value.trim()
// : inputValue.value,
// value,
// ]
// .join(" ")
// .trim() + " "
// );
// }
onMounted(() => {
document.addEventListener("keydown", onKeydown);

View File

@ -253,7 +253,7 @@ function onStreamDriveFolderDeleted(folderId: string) {
removeFolder(folderId);
}
function onDragover(ev: DragEvent): any {
function onDragover(ev: DragEvent) {
if (!ev.dataTransfer) return;
//
@ -285,7 +285,7 @@ function onDragleave() {
draghover.value = false;
}
function onDrop(ev: DragEvent): any {
function onDrop(ev: DragEvent) {
draghover.value = false;
if (!ev.dataTransfer) return;
@ -493,14 +493,12 @@ function move(target?: entities.DriveFolder) {
if (!target) {
goRoot();
return;
} else if (typeof target === "object") {
target = target.id;
}
fetching.value = true;
os.api("drive/folders/show", {
folderId: target,
folderId: target.id,
}).then((folderToMove) => {
folder.value = folderToMove;
hierarchyFolders.value = [];

View File

@ -12,12 +12,12 @@
:user="notification.note.user"
/>
<MkAvatar
v-else-if="notification.user"
v-else-if="'user' in notification"
class="icon"
:user="notification.user"
/>
<img
v-else-if="notification.icon"
v-else-if="'icon' in notification && notification.icon"
class="icon"
:src="notification.icon"
alt=""
@ -95,7 +95,7 @@
i18n.ts._notification.pollEnded
}}</span>
<MkA
v-else-if="notification.user"
v-else-if="'user' in notification"
v-user-preview="notification.user.id"
class="name"
:to="userPage(notification.user)"
@ -133,7 +133,7 @@
:plain="true"
:nowrap="!full"
:lang="notification.note.lang"
:custom-emojis="notification.note.renote.emojis"
:custom-emojis="notification.note.renote!.emojis"
/>
</MkA>
<MkA
@ -212,6 +212,7 @@
style="opacity: 0.7"
>{{ i18n.ts.youGotNewFollower }}
<div v-if="full && !hideFollowButton">
<!-- FIXME: Provide a UserDetailed here -->
<MkFollowButton
:user="notification.user"
:full="true"
@ -269,7 +270,7 @@
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from "vue";
import { onMounted, onUnmounted, ref, toRef, watch } from "vue";
import type { entities } from "firefish-js";
import XReactionIcon from "@/components/MkReactionIcon.vue";
import MkFollowButton from "@/components/MkFollowButton.vue";
@ -284,6 +285,8 @@ import { useTooltip } from "@/scripts/use-tooltip";
import { defaultStore } from "@/store";
import { instance } from "@/instance";
import icon from "@/scripts/icon";
import type { Connection } from "firefish-js/src/streaming";
import type { Channels } from "firefish-js/src/streaming.types";
const props = withDefaults(
defineProps<{
@ -299,8 +302,8 @@ const props = withDefaults(
const stream = useStream();
const elRef = ref<HTMLElement>(null);
const reactionRef = ref(null);
const elRef = ref<HTMLElement | null>(null);
const reactionRef = ref<InstanceType<typeof XReactionIcon> | null>(null);
const hideFollowButton = defaultStore.state.hideFollowButtons;
const showEmojiReactions =
@ -311,7 +314,7 @@ const defaultReaction = ["⭐", "👍", "❤️"].includes(instance.defaultReact
: "⭐";
let readObserver: IntersectionObserver | undefined;
let connection;
let connection: Connection<Channels["main"]> | null = null;
onMounted(() => {
if (!props.notification.isRead) {
@ -323,13 +326,13 @@ onMounted(() => {
observer.disconnect();
});
readObserver.observe(elRef.value);
readObserver.observe(elRef.value!);
connection = stream.useChannel("main");
connection.on("readAllNotifications", () => readObserver.disconnect());
connection.on("readAllNotifications", () => readObserver!.disconnect());
watch(props.notification.isRead, () => {
readObserver.disconnect();
watch(toRef(props.notification.isRead), () => {
readObserver!.disconnect();
});
}
});
@ -344,38 +347,47 @@ const groupInviteDone = ref(false);
const acceptFollowRequest = () => {
followRequestDone.value = true;
os.api("following/requests/accept", { userId: props.notification.user.id });
os.api("following/requests/accept", {
userId: (props.notification as entities.ReceiveFollowRequestNotification)
.user.id,
});
};
const rejectFollowRequest = () => {
followRequestDone.value = true;
os.api("following/requests/reject", { userId: props.notification.user.id });
os.api("following/requests/reject", {
userId: (props.notification as entities.ReceiveFollowRequestNotification)
.user.id,
});
};
const acceptGroupInvitation = () => {
groupInviteDone.value = true;
os.apiWithDialog("users/groups/invitations/accept", {
invitationId: props.notification.invitation.id,
invitationId: (props.notification as entities.GroupInvitedNotification)
.invitation.id,
});
};
const rejectGroupInvitation = () => {
groupInviteDone.value = true;
os.api("users/groups/invitations/reject", {
invitationId: props.notification.invitation.id,
invitationId: (props.notification as entities.GroupInvitedNotification)
.invitation.id,
});
};
useTooltip(reactionRef, (showing) => {
const n = props.notification as entities.ReactionNotification;
os.popup(
XReactionTooltip,
{
showing,
reaction: props.notification.reaction
? props.notification.reaction.replace(/^:(\w+):$/, ":$1@.:")
: props.notification.reaction,
emojis: props.notification.note.emojis,
targetElement: reactionRef.value.$el,
reaction: n.reaction
? n.reaction.replace(/^:(\w+):$/, ":$1@.:")
: n.reaction,
emojis: n.note.emojis,
targetElement: reactionRef.value!.$el,
},
{},
"closed",

View File

@ -3,7 +3,7 @@
:to="`/@${page.user.username}/pages/${page.name}`"
class="vhpxefrj _block"
tabindex="-1"
:behavior="`${ui === 'deck' ? 'window' : null}`"
:behavior="ui === 'deck' ? 'window' : null"
>
<div
v-if="page.eyeCatchingImage"
@ -36,9 +36,10 @@
<script lang="ts" setup>
import { userName } from "@/filters/user";
import { ui } from "@/config";
import type { entities } from "firefish-js";
defineProps<{
page: any;
page: entities.Page;
}>();
</script>

View File

@ -56,23 +56,22 @@ const router = new Router(routes, props.initialPath);
const pageMetadata = ref<null | ComputedRef<PageMetadata>>();
const windowEl = ref<InstanceType<typeof XWindow>>();
const history = ref<{ path: string; key: any }[]>([
const history = ref<{ path: string; key: string }[]>([
{
path: router.getCurrentPath(),
key: router.getCurrentKey(),
},
]);
const buttonsLeft = computed(() => {
const buttons = [];
if (history.value.length > 1) {
buttons.push({
icon: `${icon("ph-caret-left")}`,
onClick: back,
});
return [
{
icon: `${icon("ph-caret-left")}`,
onClick: back,
},
];
}
return buttons;
return [];
});
const buttonsRight = computed(() => {
const buttons = [
@ -114,7 +113,7 @@ const contextmenu = computed(() => [
text: i18n.ts.openInNewTab,
action: () => {
window.open(url + router.getCurrentPath(), "_blank");
windowEl.value.close();
windowEl.value!.close();
},
},
{
@ -135,17 +134,17 @@ function back() {
}
function close() {
windowEl.value.close();
windowEl.value!.close();
}
function expand() {
mainRouter.push(router.getCurrentPath(), "forcePage");
windowEl.value.close();
windowEl.value!.close();
}
function popout() {
_popout(router.getCurrentPath(), windowEl.value.$el);
windowEl.value.close();
_popout(router.getCurrentPath(), windowEl.value!.$el);
windowEl.value!.close();
}
defineExpose({

View File

@ -94,15 +94,14 @@ const props = defineProps<{
};
}>();
const emit = defineEmits<{
(
ev: "update:modelValue",
"update:modelValue": [
v: {
expiresAt: string;
expiredAfter: number;
expiresAt?: number;
expiredAfter?: number | null;
choices: string[];
multiple: boolean;
},
): void;
];
}>();
const choices = ref(props.modelValue.choices);
@ -147,19 +146,19 @@ function get() {
};
const calcAfter = () => {
let base = Number.parseInt(after.value);
let base = Number.parseInt(after.value.toString());
switch (unit.value) {
// biome-ignore lint/suspicious/noFallthroughSwitchClause: Fallthrough intentially
case "day":
base *= 24;
// fallthrough
// biome-ignore lint/suspicious/noFallthroughSwitchClause: Fallthrough intentially
case "hour":
base *= 60;
// fallthrough
// biome-ignore lint/suspicious/noFallthroughSwitchClause: Fallthrough intentially
case "minute":
base *= 60;
// fallthrough
case "second":
return (base *= 1000);
return base * 1000;
default:
return null;
}

View File

@ -1136,11 +1136,11 @@ async function post() {
nextTick(() => autosize.update(textareaEl.value));
});
})
.catch((err) => {
.catch((err: { message: string; id: string }) => {
posting.value = false;
os.alert({
type: "error",
text: err.message + "\n" + (err as any).id,
text: `${err.message}\n${err.id}`,
});
});
vibrate([10, 20, 10, 20, 10, 20, 60]);

View File

@ -9,9 +9,11 @@
</template>
<script lang="ts" setup>
import type { entities } from "firefish-js";
defineProps<{
reaction: string;
customEmojis?: any[]; // TODO
customEmojis?: entities.EmojiLite[];
noStyle?: boolean;
}>();
</script>

View File

@ -3,6 +3,7 @@
ref="tooltip"
:target-element="targetElement"
:max-width="340"
:showing="showing"
@closed="emit('closed')"
>
<div class="beeadbfb">
@ -18,12 +19,15 @@
</template>
<script lang="ts" setup>
import type { Ref } from "vue";
import MkTooltip from "./MkTooltip.vue";
import XReactionIcon from "@/components/MkReactionIcon.vue";
import type { entities } from "firefish-js";
defineProps<{
showing: Ref<boolean>;
reaction: string;
emojis: any[]; // TODO
emojis: entities.EmojiLite[];
targetElement: HTMLElement;
}>();

View File

@ -4,6 +4,7 @@
:target-element="targetElement"
:max-width="340"
@closed="emit('closed')"
:showing="showing"
>
<div class="bqxuuuey">
<div class="reaction">
@ -29,15 +30,18 @@
</template>
<script lang="ts" setup>
import type { Ref } from "vue";
import MkTooltip from "./MkTooltip.vue";
import XReactionIcon from "@/components/MkReactionIcon.vue";
import type { entities } from "firefish-js";
defineProps<{
showing: Ref<boolean>;
reaction: string;
users: any[]; // TODO
users: entities.User[]; // TODO
count: number;
emojis: any[]; // TODO
targetElement: HTMLElement;
emojis: entities.EmojiLite[]; // TODO
targetElement?: HTMLElement;
}>();
const emit = defineEmits<{

View File

@ -89,7 +89,7 @@ useTooltip(
emojis: props.note.emojis,
users,
count: props.count,
targetElement: buttonRef.value,
targetElement: buttonRef.value!,
},
{},
"closed",

View File

@ -46,7 +46,7 @@ const buttonRef = ref<HTMLElement>();
const canRenote = computed(
() =>
["public", "home"].includes(props.note.visibility) ||
props.note.userId === me.id,
props.note.userId === me?.id,
);
useTooltip(buttonRef, async (showing) => {

View File

@ -5,13 +5,13 @@
@after-leave="emit('closed')"
>
<div
v-show="showing"
v-show="unref(showing)"
ref="el"
class="buebdbiu _acrylic _shadow"
:style="{ zIndex, maxWidth: maxWidth + 'px' }"
>
<slot>
<Mfm v-if="asMfm" :text="text" />
<Mfm v-if="asMfm" :text="text!" />
<span v-else>{{ text }}</span>
</slot>
</div>
@ -19,15 +19,22 @@
</template>
<script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, ref } from "vue";
import {
type MaybeRef,
nextTick,
onMounted,
onUnmounted,
ref,
unref,
} from "vue";
import * as os from "@/os";
import { calcPopupPosition } from "@/scripts/popup-position";
import { defaultStore } from "@/store";
const props = withDefaults(
defineProps<{
showing: boolean;
targetElement?: HTMLElement;
showing: MaybeRef<boolean>;
targetElement?: HTMLElement | null;
x?: number;
y?: number;
text?: string;
@ -40,6 +47,7 @@ const props = withDefaults(
maxWidth: 250,
direction: "top",
innerMargin: 0,
targetElement: null,
},
);
@ -51,7 +59,7 @@ const el = ref<HTMLElement>();
const zIndex = os.claimZIndex("high");
function setPosition() {
const data = calcPopupPosition(el.value, {
const data = calcPopupPosition(el.value!, {
anchorElement: props.targetElement,
direction: props.direction,
align: "center",
@ -60,12 +68,12 @@ function setPosition() {
y: props.y,
});
el.value.style.transformOrigin = data.transformOrigin;
el.value.style.left = data.left + "px";
el.value.style.top = data.top + "px";
el.value!.style.transformOrigin = data.transformOrigin;
el.value!.style.left = `${data.left}px`;
el.value!.style.top = `${data.top}px`;
}
let loopHandler;
let loopHandler: number;
onMounted(() => {
nextTick(() => {

View File

@ -4,6 +4,7 @@
:target-element="targetElement"
:max-width="250"
@closed="emit('closed')"
:showing="showing"
>
<div class="beaffaef">
<div v-for="u in users" :key="u.id" class="user">
@ -18,12 +19,15 @@
</template>
<script lang="ts" setup>
import type { Ref } from "vue";
import MkTooltip from "./MkTooltip.vue";
import type { entities } from "firefish-js";
defineProps<{
users: any[]; // TODO
showing: Ref<boolean>;
users: entities.User[];
count: number;
targetElement: HTMLElement;
targetElement?: HTMLElement;
}>();
const emit = defineEmits<{

View File

@ -85,7 +85,7 @@ import icon from "@/scripts/icon";
interface Widget {
name: string;
id: string;
data: Record<string, any>;
data: Record<string, unknown>;
}
const props = defineProps<{
@ -137,12 +137,12 @@ function onContextmenu(widget: Widget, ev: MouseEvent) {
return isLink(el.parentElement);
}
};
if (isLink(ev.target)) return;
if (isLink(ev.target as HTMLElement)) return;
if (
["INPUT", "TEXTAREA", "IMG", "VIDEO", "CANVAS"].includes(
ev.target.tagName,
(ev.target as HTMLElement).tagName,
) ||
ev.target.attributes.contenteditable
(ev.target as HTMLElement).getAttribute("contentEditable")
)
return;
if (window.getSelection()?.toString() !== "") return;

View File

@ -22,7 +22,7 @@ import icon from "@/scripts/icon";
const props = withDefaults(
defineProps<{
to?: string;
to: string;
activeClass?: null | string;
behavior?: null | "window" | "browser" | "modalWindow";
}>(),

View File

@ -210,11 +210,13 @@ interface VueComponentConstructor<P, E> {
emits?: E;
}
type NonArrayAble<A> = A extends Array<unknown> ? never : A;
export async function popup<Props, Emits>(
component: VueComponentConstructor<Props, Emits>,
props: Props & Record<string, unknown>,
events: Partial<Emits> = {},
disposeEvent?: string,
props: Props,
events: Partial<NonArrayAble<NonNullable<Emits>>> = {},
disposeEvent?: keyof Partial<NonArrayAble<NonNullable<Emits>>>,
) {
markRaw(component);
@ -227,7 +229,7 @@ export async function popup<Props, Emits>(
};
const state = {
component,
props,
props: props as Record<string, unknown>,
events: disposeEvent
? {
...events,

View File

@ -20,6 +20,16 @@ export type UserLite = {
movedToUri: any;
emojis: EmojiLite[];
instance?: InstanceLite;
avatarColor: null;
emojiModPerm: "unauthorized" | "add" | "mod" | "full";
isAdmin?: boolean;
isModerator?: boolean;
isBot?: boolean;
isLocked: boolean;
isIndexable: boolean;
isCat?: boolean;
speakAsCat?: boolean;
driveCapacityOverrideMb: number | null,
};
export type UserDetailed = UserLite & {
@ -46,7 +56,6 @@ export type UserDetailed = UserLite & {
isCat: boolean;
isFollowed: boolean;
isFollowing: boolean;
isLocked: boolean;
isModerator: boolean;
isMuted: boolean;
isRenoteMuted: boolean;
@ -228,7 +237,10 @@ export interface RenoteNotification extends BaseNotification {
type: "renote";
user: User;
userId: User["id"];
note: Note;
note: Note & {
renote: Note,
renoteId: string,
};
}
export interface QuoteNotification extends BaseNotification {
type: "quote";