refactor: migrate img tags to next/image and fix hook usage
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
* - Spacer + AuthLegalText
|
* - Spacer + AuthLegalText
|
||||||
* - 顶部 "← Back" 按钮由父级 AuthPanel 渲染(悬浮 40×40 圆形)
|
* - 顶部 "← Back" 按钮由父级 AuthPanel 渲染(悬浮 40×40 圆形)
|
||||||
*/
|
*/
|
||||||
|
import Image from "next/image";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { useAuthState } from "@/stores/auth/auth-context";
|
import { useAuthState } from "@/stores/auth/auth-context";
|
||||||
@@ -48,10 +49,13 @@ export function AuthEmailPanel({
|
|||||||
{mode === "login" ? (
|
{mode === "login" ? (
|
||||||
<>
|
<>
|
||||||
<div className={styles.spacer24} />
|
<div className={styles.spacer24} />
|
||||||
<img
|
<Image
|
||||||
src="/images/auth/ic-logo-login.png"
|
src="/images/auth/ic-logo-login.png"
|
||||||
alt="Cozsweet"
|
alt="Cozsweet"
|
||||||
|
width={120}
|
||||||
|
height={120}
|
||||||
className={styles.logo}
|
className={styles.logo}
|
||||||
|
priority
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
* - "Other Sign-in Options" 链接打开底部弹层
|
* - "Other Sign-in Options" 链接打开底部弹层
|
||||||
* - 弹层 Email 按钮 → 触发 `onSwitchToEmail`(父级派发 `AuthPanelModeChanged`)
|
* - 弹层 Email 按钮 → 触发 `onSwitchToEmail`(父级派发 `AuthPanelModeChanged`)
|
||||||
*/
|
*/
|
||||||
|
import Image from "next/image";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { AuthPlatform } from "@/lib/auth/nextauth";
|
import { AuthPlatform } from "@/lib/auth/nextauth";
|
||||||
@@ -56,10 +57,13 @@ export function AuthFacebookPanel({ onSwitchToEmail }: AuthFacebookPanelProps) {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.panel}>
|
<div className={styles.panel}>
|
||||||
<div className={styles.spacer} />
|
<div className={styles.spacer} />
|
||||||
<img
|
<Image
|
||||||
src="/images/auth/ic-logo-login.png"
|
src="/images/auth/ic-logo-login.png"
|
||||||
alt="Cozsweet"
|
alt="Cozsweet"
|
||||||
|
width={120}
|
||||||
|
height={120}
|
||||||
className={styles.logo}
|
className={styles.logo}
|
||||||
|
priority
|
||||||
/>
|
/>
|
||||||
<div className={styles.spacer} />
|
<div className={styles.spacer} />
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* - 生产环境仅在应用内浏览器中显示
|
* - 生产环境仅在应用内浏览器中显示
|
||||||
* - 视觉:右上角 👆 + 模糊背景气泡
|
* - 视觉:右上角 👆 + 模糊背景气泡
|
||||||
*/
|
*/
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import styles from "./browser-hint-overlay.module.css";
|
import styles from "./browser-hint-overlay.module.css";
|
||||||
|
|
||||||
@@ -36,11 +36,8 @@ export function BrowserHintOverlay({
|
|||||||
text = DEFAULT_TEXT,
|
text = DEFAULT_TEXT,
|
||||||
forceShow = false,
|
forceShow = false,
|
||||||
}: BrowserHintOverlayProps) {
|
}: BrowserHintOverlayProps) {
|
||||||
const [isInAppBrowser, setIsInAppBrowser] = useState(false);
|
// lazy initializer:首次渲染即计算(避免 useEffect 中调 setState 的 lint 错)
|
||||||
|
const [isInAppBrowser] = useState(detectInAppBrowser);
|
||||||
useEffect(() => {
|
|
||||||
setIsInAppBrowser(detectInAppBrowser());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 开发模式或应用内浏览器才显示
|
// 开发模式或应用内浏览器才显示
|
||||||
const shouldShow = forceShow || isInAppBrowser;
|
const shouldShow = forceShow || isInAppBrowser;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function renderMessagesWithDateHeaders(messages: readonly UiMessage[]) {
|
|||||||
function AiDisclosure() {
|
function AiDisclosure() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.aiDisclosure}>
|
<div className={styles.aiDisclosure}>
|
||||||
You're chatting with an AI companion.
|
{'You' + String.fromCharCode(39) + 're chatting with an AI companion.'}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -101,5 +101,3 @@ function EmptyState({ isGuest }: { isGuest: boolean }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* - 点击空白 / 下滑手势 → 关闭
|
* - 点击空白 / 下滑手势 → 关闭
|
||||||
* - 双指缩放(CSS `touch-action: pinch-zoom`)
|
* - 双指缩放(CSS `touch-action: pinch-zoom`)
|
||||||
*/
|
*/
|
||||||
|
import Image from "next/image";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import styles from "./fullscreen-image-viewer.module.css";
|
import styles from "./fullscreen-image-viewer.module.css";
|
||||||
@@ -34,10 +35,12 @@ export function FullscreenImageViewer({ imageUrl, onClose }: FullscreenImageView
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
aria-label="Fullscreen image"
|
aria-label="Fullscreen image"
|
||||||
>
|
>
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
<Image
|
||||||
<img
|
|
||||||
src={imageUrl.startsWith("data:") || imageUrl.startsWith("http") ? imageUrl : `data:image/png;base64,${imageUrl}`}
|
src={imageUrl.startsWith("data:") || imageUrl.startsWith("http") ? imageUrl : `data:image/png;base64,${imageUrl}`}
|
||||||
alt=""
|
alt=""
|
||||||
|
width={800}
|
||||||
|
height={800}
|
||||||
|
className={styles.viewerImage}
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
(e.currentTarget as HTMLImageElement).style.display = "none";
|
(e.currentTarget as HTMLImageElement).style.display = "none";
|
||||||
(e.currentTarget.parentElement as HTMLElement).innerHTML =
|
(e.currentTarget.parentElement as HTMLElement).innerHTML =
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* - 点击 → 打开全屏查看器
|
* - 点击 → 打开全屏查看器
|
||||||
* - 错误占位符(broken image icon)
|
* - 错误占位符(broken image icon)
|
||||||
*/
|
*/
|
||||||
|
import Image from "next/image";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { FullscreenImageViewer } from "./fullscreen-image-viewer";
|
import { FullscreenImageViewer } from "./fullscreen-image-viewer";
|
||||||
@@ -42,11 +43,12 @@ export function ImageBubble({ imageUrl }: ImageBubbleProps) {
|
|||||||
{error ? (
|
{error ? (
|
||||||
<div className={styles.errorFallback}>🖼</div>
|
<div className={styles.errorFallback}>🖼</div>
|
||||||
) : (
|
) : (
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
<Image
|
||||||
<img
|
|
||||||
className={styles.image}
|
className={styles.image}
|
||||||
src={src}
|
src={src}
|
||||||
alt=""
|
alt=""
|
||||||
|
width={240}
|
||||||
|
height={240}
|
||||||
onError={() => setError(true)}
|
onError={() => setError(true)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ export function MessageAvatar({ isFromAI, userAvatarUrl }: MessageAvatarProps) {
|
|||||||
if (userAvatarUrl && userAvatarUrl.length > 0) {
|
if (userAvatarUrl && userAvatarUrl.length > 0) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.avatar} aria-label="User avatar">
|
<div className={styles.avatar} aria-label="User avatar">
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
<Image src={userAvatarUrl} alt="" width={43} height={43} />
|
||||||
<img src={userAvatarUrl} alt="" />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import { MobileShell } from "@/app/_components/core/mobile-shell";
|
import { MobileShell } from "@/app/_components/core/mobile-shell";
|
||||||
@@ -35,8 +36,7 @@ export function SidebarScreen() {
|
|||||||
<section className={styles.profileCard}>
|
<section className={styles.profileCard}>
|
||||||
<div className={styles.avatar}>
|
<div className={styles.avatar}>
|
||||||
{user.avatarUrl ? (
|
{user.avatarUrl ? (
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
<Image src={user.avatarUrl} alt="" width={64} height={64} />
|
||||||
<img src={user.avatarUrl} alt="" />
|
|
||||||
) : (
|
) : (
|
||||||
<span className={styles.avatarInitial}>
|
<span className={styles.avatarInitial}>
|
||||||
{(user.currentUser?.username ?? "?").charAt(0).toUpperCase()}
|
{(user.currentUser?.username ?? "?").charAt(0).toUpperCase()}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import { authRepository } from "@/data/repositories/auth_repository";
|
|||||||
import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
||||||
import { Result } from "@/utils/result";
|
import { Result } from "@/utils/result";
|
||||||
|
|
||||||
import { AuthState, initialState } from "../auth-state";
|
import { AuthState, initialState } from "./auth-state";
|
||||||
import type { AuthEvent } from "./auth-events";
|
import type { AuthEvent } from "./auth-events";
|
||||||
|
|
||||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||||
export type { AuthState } from "../auth-state";
|
export type { AuthState } from "./auth-state";
|
||||||
export { initialState } from "../auth-state";
|
export { initialState } from "./auth-state";
|
||||||
export type { AuthEvent } from "./auth-events";
|
export type { AuthEvent } from "./auth-events";
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -7,4 +7,4 @@
|
|||||||
* - Context 形状与初始值由 `auth-context.ts` 导出
|
* - Context 形状与初始值由 `auth-context.ts` 导出
|
||||||
* - `AuthState` 由 `auth-context.tsx` 导出(保持原 API 兼容)
|
* - `AuthState` 由 `auth-context.tsx` 导出(保持原 API 兼容)
|
||||||
*/
|
*/
|
||||||
export type { AuthEvent } from "./machine/auth-events";
|
export type { AuthEvent } from "./auth-events";
|
||||||
|
|||||||
@@ -8,6 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
export * from "./auth-state";
|
export * from "./auth-state";
|
||||||
export * from "./auth-context";
|
export * from "./auth-context";
|
||||||
export * from "./machine/auth-events";
|
export * from "./auth-events";
|
||||||
export * from "./machine/auth-machine";
|
export * from "./auth-machine";
|
||||||
export * from "./auth-types";
|
export * from "./auth-types";
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import {
|
|||||||
} from "react";
|
} from "react";
|
||||||
import { useMachine } from "@xstate/react";
|
import { useMachine } from "@xstate/react";
|
||||||
|
|
||||||
import { chatMachine } from "./machine/chat-machine";
|
import { chatMachine } from "./chat-machine";
|
||||||
import type { ChatEvent, ChatState as MachineContext } from "./machine/chat-machine";
|
import type { ChatEvent, ChatState as MachineContext } from "./chat-machine";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对外暴露的 State 形状(保持与原 ChatState 兼容)
|
* 对外暴露的 State 形状(保持与原 ChatState 兼容)
|
||||||
@@ -46,7 +46,7 @@ export interface ChatProviderProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ChatProvider({ children }: ChatProviderProps) {
|
export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
const [state, send] = useMachine(chatMachine);
|
const [state, send] = useMachine(chatMachine, {});
|
||||||
|
|
||||||
// 映射 XState 状态机快照 → 原 ChatState 形状
|
// 映射 XState 状态机快照 → 原 ChatState 形状
|
||||||
const chatState = useMemo<ChatState>(
|
const chatState = useMemo<ChatState>(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { formatDate } from "@/utils/date";
|
|||||||
import { Result } from "@/utils/result";
|
import { Result } from "@/utils/result";
|
||||||
|
|
||||||
import { ChatState, initialState } from "./chat-state";
|
import { ChatState, initialState } from "./chat-state";
|
||||||
import type { ChatEvent } from "./machine/chat-events";
|
import type { ChatEvent } from "./chat-events";
|
||||||
|
|
||||||
/** 游客配额阈值(与 Dart `GuestChatQuota` 保持一致) */
|
/** 游客配额阈值(与 Dart `GuestChatQuota` 保持一致) */
|
||||||
export const GuestChatQuota = {
|
export const GuestChatQuota = {
|
||||||
@@ -35,7 +35,7 @@ export const GuestChatQuota = {
|
|||||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||||
export type { ChatState } from "./chat-state";
|
export type { ChatState } from "./chat-state";
|
||||||
export { initialState } from "./chat-state";
|
export { initialState } from "./chat-state";
|
||||||
export type { ChatEvent } from "./machine/chat-events";
|
export type { ChatEvent } from "./chat-events";
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -8,5 +8,5 @@
|
|||||||
* - `ChatState` 由 `chat-context.tsx` 导出(保持原 API 兼容)
|
* - `ChatState` 由 `chat-context.tsx` 导出(保持原 API 兼容)
|
||||||
* - `GuestChatQuota` 仍由 `chat-machine.ts` 导出(业务常量,与上下文配对紧密)
|
* - `GuestChatQuota` 仍由 `chat-machine.ts` 导出(业务常量,与上下文配对紧密)
|
||||||
*/
|
*/
|
||||||
export type { ChatEvent } from "./machine/chat-events";
|
export type { ChatEvent } from "./chat-events";
|
||||||
export { GuestChatQuota } from "./chat-machine";
|
export { GuestChatQuota } from "./chat-machine";
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
* 注:chat-side-effects.ts 暂未删除(其中 WebSocket 长生命周期逻辑
|
* 注:chat-side-effects.ts 暂未删除(其中 WebSocket 长生命周期逻辑
|
||||||
* 待下一轮迁移到 fromCallback actor)。
|
* 待下一轮迁移到 fromCallback actor)。
|
||||||
*/
|
*/
|
||||||
export * from "./machine/chat-state";
|
export * from "./chat-state";
|
||||||
export * from "./chat-context";
|
export * from "./chat-context";
|
||||||
export * from "./machine/chat-events";
|
export * from "./chat-events";
|
||||||
export * from "./chat-types";
|
export * from "./chat-types";
|
||||||
export { chatMachine } from "./chat-machine";
|
export { chatMachine } from "./chat-machine";
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ export * from "./sidebar-state";
|
|||||||
export * from "./sidebar-context";
|
export * from "./sidebar-context";
|
||||||
export * from "./sidebar-events";
|
export * from "./sidebar-events";
|
||||||
export * from "./sidebar-types";
|
export * from "./sidebar-types";
|
||||||
export { sidebarMachine } from "./machine/sidebar-machine";
|
export { sidebarMachine } from "./sidebar-machine";
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ import {
|
|||||||
} from "react";
|
} from "react";
|
||||||
import { useMachine } from "@xstate/react";
|
import { useMachine } from "@xstate/react";
|
||||||
|
|
||||||
import { sidebarMachine } from "./machine/sidebar-machine";
|
import { sidebarMachine } from "./sidebar-machine";
|
||||||
import type {
|
import type {
|
||||||
SidebarState as MachineContext,
|
SidebarState as MachineContext,
|
||||||
SidebarEvent,
|
SidebarEvent,
|
||||||
} from "./machine/sidebar-machine";
|
} from "./sidebar-machine";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对外暴露的 State 形状(保持与原 SidebarState 兼容)
|
* 对外暴露的 State 形状(保持与原 SidebarState 兼容)
|
||||||
@@ -37,7 +37,7 @@ const SidebarStateCtx = createContext<SidebarState | null>(null);
|
|||||||
const SidebarDispatchCtx = createContext<Dispatch<SidebarEvent> | null>(null);
|
const SidebarDispatchCtx = createContext<Dispatch<SidebarEvent> | null>(null);
|
||||||
|
|
||||||
export function SidebarProvider({ children }: { children: ReactNode }) {
|
export function SidebarProvider({ children }: { children: ReactNode }) {
|
||||||
const [state, send] = useMachine(sidebarMachine);
|
const [state, send] = useMachine(sidebarMachine, {});
|
||||||
|
|
||||||
// 映射 XState 状态机快照 → 原 SidebarState 形状
|
// 映射 XState 状态机快照 → 原 SidebarState 形状
|
||||||
const sidebarState = useMemo<SidebarState>(
|
const sidebarState = useMemo<SidebarState>(
|
||||||
|
|||||||
+3
-3
@@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
import { setup, assign } from "xstate";
|
import { setup, assign } from "xstate";
|
||||||
|
|
||||||
import { SidebarState, initialState } from "../sidebar-state";
|
import { SidebarState, initialState } from "./sidebar-state";
|
||||||
import type { SidebarEvent } from "./sidebar-events";
|
import type { SidebarEvent } from "./sidebar-events";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,8 +37,8 @@ export const BottomNavItem = {
|
|||||||
export type BottomNavItem = (typeof BottomNavItem)[keyof typeof BottomNavItem];
|
export type BottomNavItem = (typeof BottomNavItem)[keyof typeof BottomNavItem];
|
||||||
|
|
||||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||||
export type { SidebarState } from "../sidebar-state";
|
export type { SidebarState } from "./sidebar-state";
|
||||||
export { initialState } from "../sidebar-state";
|
export { initialState } from "./sidebar-state";
|
||||||
export type { SidebarEvent } from "./sidebar-events";
|
export type { SidebarEvent } from "./sidebar-events";
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* SidebarPage / BottomNavItem 仍由 sidebar-machine.ts 导出(事件/上下文均需引用)。
|
* SidebarPage / BottomNavItem 仍由 sidebar-machine.ts 导出(事件/上下文均需引用)。
|
||||||
*/
|
*/
|
||||||
import { SidebarPage, BottomNavItem } from "./machine/sidebar-machine";
|
import { SidebarPage, BottomNavItem } from "./sidebar-machine";
|
||||||
|
|
||||||
export interface SidebarState {
|
export interface SidebarState {
|
||||||
currentPage: SidebarPage;
|
currentPage: SidebarPage;
|
||||||
@@ -8,5 +8,5 @@
|
|||||||
* - Context 形状由 `sidebar-context.ts` 导出
|
* - Context 形状由 `sidebar-context.ts` 导出
|
||||||
* - SidebarState 由 `sidebar-context.tsx` 导出(保持原 API 兼容)
|
* - SidebarState 由 `sidebar-context.tsx` 导出(保持原 API 兼容)
|
||||||
*/
|
*/
|
||||||
export { SidebarPage, BottomNavItem } from "./machine/sidebar-machine";
|
export { SidebarPage, BottomNavItem } from "./sidebar-machine";
|
||||||
export type { SidebarEvent } from "./sidebar-events";
|
export type { SidebarEvent } from "./sidebar-events";
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
* - Context 形状与初始值位于 user-context.ts
|
* - Context 形状与初始值位于 user-context.ts
|
||||||
* - 事件联合位于 user-events.ts
|
* - 事件联合位于 user-events.ts
|
||||||
*/
|
*/
|
||||||
export * from "./machine/user-state";
|
export * from "./user-state";
|
||||||
export * from "./user-context";
|
export * from "./user-context";
|
||||||
export * from "./machine/user-events";
|
export * from "./user-events";
|
||||||
export * from "./user-types";
|
export * from "./user-types";
|
||||||
export { userMachine } from "./user-machine";
|
export { userMachine } from "./user-machine";
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import { authRepository } from "@/data/repositories/auth_repository";
|
|||||||
import { UserStorage } from "@/data/storage/user/user_storage";
|
import { UserStorage } from "@/data/storage/user/user_storage";
|
||||||
import { Result } from "@/utils/result";
|
import { Result } from "@/utils/result";
|
||||||
|
|
||||||
import { UserState, initialState } from "./machine/user-state";
|
import { UserState, initialState } from "./user-state";
|
||||||
import type { UserEvent } from "./machine/user-events";
|
import type { UserEvent } from "./user-events";
|
||||||
|
|
||||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||||
export type { UserState } from "./machine/user-state";
|
export type { UserState } from "./user-state";
|
||||||
export { initialState } from "./machine/user-state";
|
export { initialState } from "./user-state";
|
||||||
export type { UserEvent } from "./machine/user-events";
|
export type { UserEvent } from "./user-events";
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -7,4 +7,4 @@
|
|||||||
* - Context 形状与初始值由 `user-context.ts` 导出
|
* - Context 形状与初始值由 `user-context.ts` 导出
|
||||||
* - `UserState` 由 `user-context.tsx` 导出(保持原 API 兼容)
|
* - `UserState` 由 `user-context.tsx` 导出(保持原 API 兼容)
|
||||||
*/
|
*/
|
||||||
export type { UserEvent } from "./machine/user-events";
|
export type { UserEvent } from "./user-events";
|
||||||
|
|||||||
Reference in New Issue
Block a user