npm package: @lark-apaas/client-toolkit-lite
Description: Lightweight client toolkit for Express/Vite tech stack - hooks, utils, and UI components without SDK integrations
Latest version: 1.0.1

# @lark-apaas/client-toolkit-lite

轻量版客户端工具包，面向 Express/Vite 技术栈。从 `@lark-apaas/client-toolkit` 精简而来，保留核心能力（AppContainer、hooks、工具函数、路由组件、DataLoom），去掉重量级依赖（antd、Observable、Auth SDK、Slardar、Sonner 等）。

## 安装

```bash
npm install @lark-apaas/client-toolkit-lite
```

### Peer Dependencies

```bash
npm install react react-dom react-router-dom @tanstack/react-query
```

## 快速接入

### 1. 引入主题样式

在项目入口文件（如 `main.tsx`）中引入全局样式：

```tsx
// main.tsx
import '@lark-apaas/client-toolkit-lite/styles.css';
import { createRoot } from 'react-dom/client';
import App from './App';

createRoot(document.getElementById('root')!).render(<App />);
```

样式包含：
- **theme-layer.css** — Tailwind CSS 层声明（由消费端 Vite + PostCSS 处理）
- **tailwind-theme.css** — 设计系统 CSS 变量（颜色体系）
- **override.css** — 全局基础样式（border-color、background、container）
- **font-family.css** — 字体定义

### 2. 使用 AppContainer

`AppContainer` 是应用根容器，内部集成：
- **Safety** — 生产环境「妙搭构建」安全标识
- **QueryProvider** — React Query 数据管理
- **useAppInfo** — 自动同步 document title / favicon / OG meta
- **Runtime** — React DevTools Hook + Axios CSRF 全局注入（防重复）

```tsx
// App.tsx
import { AppContainer } from '@lark-apaas/client-toolkit-lite';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <AppContainer>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </AppContainer>
    </BrowserRouter>
  );
}
```

也可以单独使用 `QueryProvider`（不需要 AppContainer 的其他功能时）：

```tsx
import { QueryProvider } from '@lark-apaas/client-toolkit-lite';

<QueryProvider>{children}</QueryProvider>
```

### 3. Hooks

#### useAppInfo

获取应用元数据，自动同步到 document title / favicon / OG meta：

```tsx
import { useAppInfo } from '@lark-apaas/client-toolkit-lite';

const { appName, appLogo, description } = useAppInfo();
```

#### useCurrentUserProfile

获取当前登录用户信息（通过 DataLoom 拉取）：

```tsx
import { useCurrentUserProfile } from '@lark-apaas/client-toolkit-lite';

const { user_id, name, email, avatar } = useCurrentUserProfile();
```

#### useIsMobile

响应式移动端检测（768px 断点）：

```tsx
import { useIsMobile } from '@lark-apaas/client-toolkit-lite';

const isMobile = useIsMobile();
```

#### useLogout

退出登录（通过 DataLoom session.signOut）：

```tsx
import { useLogout } from '@lark-apaas/client-toolkit-lite';

const { handlerLogout, isLoading } = useLogout();
```

### 4. 路由组件

依赖 `react-router-dom`：

```tsx
import { ActiveLink, NavLink, UniversalLink } from '@lark-apaas/client-toolkit-lite';

// 支持 hash 定位的 NavLink，自动 active 检测
<ActiveLink to="/page#section">Section</ActiveLink>

// 增强版 NavLink，支持 hash + 滚动到顶部
<NavLink to="/about">About</NavLink>

// 统一链接：内部路由用 Link，外部 URL 用 a 标签（自动识别）
<UniversalLink to="https://example.com">External</UniversalLink>
<UniversalLink to="/internal">Internal</UniversalLink>
```

### 5. 工具函数

```tsx
import {
  // 平台相关
  getAppId,           // 获取应用 ID（from window.appId）
  getCsrfToken,       // 从 cookie 提取 CSRF token
  getEnvPath,         // 预览/运行态路径
  resolveAppUrl,      // 解析应用相对路径，自动加 CLIENT_BASE_PATH

  // HTTP
  getAxiosForBackend, // 获取后端 axios 实例（带登录重定向拦截）
  axiosForBackend,    // 同上，预创建的单例
  initAxiosConfig,    // 初始化 axios 拦截器（CSRF token 注入）

  // 存储
  scopedStorage,      // 应用隔离的 localStorage（key 加 appId 前缀）

  // 样式
  clsxWithTw,         // Tailwind class 合并（clsx + twMerge）

  // 工具
  copyToClipboard,    // 复制到剪贴板
  safeStringify,      // 安全 JSON 序列化（处理循环引用/BigInt）
  isPreview,          // 是否预览模式
  normalizeBasePath,  // 路径标准化（去尾部斜杠）
  getWsPath,          // WebSocket 路径

  // 设备检测
  isIpad, isMobile, isIOS,
} from '@lark-apaas/client-toolkit-lite';
```

### 6. 数据集成

```tsx
import { getAppInfo, getCurrentUserProfile, getDataloom } from '@lark-apaas/client-toolkit-lite';

// 获取应用元数据（缓存在 window._appInfo）
const appInfo = await getAppInfo();

// 获取当前用户（from window._userInfo）
const userProfile = getCurrentUserProfile();

// 获取 DataLoom 客户端（单例，懒初始化）
const dataloom = await getDataloom();
const users = await dataloom.service.user.search({ name: '张三' });
```

### 7. 图片资源

```tsx
import { avatarImages, bannerImages, coverImages } from '@lark-apaas/client-toolkit-lite';

// avatarImages.avatarImg1 ~ avatarImg11（11 张默认头像 CDN URL）
// bannerImages（24 张横幅，科技/专业/极简分类）
// coverImages（36 张封面，办公/建筑/风景/科技/3D 等分类）
```

### 8. 类型导出

```tsx
import type {
  AppInfoPayload,   // { name, avatar, description }
  IUserProfile,     // { user_id, email, name, avatar, status }
  IJson,            // Record<string, unknown>
  IFileAttachment,  // { bucket_id, file_path }
} from '@lark-apaas/client-toolkit-lite';
```

## 完整导出清单

| 分类 | 导出 |
|------|------|
| Components | AppContainer, QueryProvider |
| Route Components | ActiveLink, NavLink, UniversalLink |
| Hooks | useAppInfo, useCurrentUserProfile, useIsMobile, useLogout |
| Utils | clsxWithTw, isPreview, normalizeBasePath, getWsPath, getAppId, getCsrfToken, scopedStorage, copyToClipboard, isIpad, isMobile, isIOS, resolveAppUrl, getEnvPath, safeStringify, getAxiosForBackend, axiosForBackend, initAxiosConfig |
| Integrations | getAppInfo, getCurrentUserProfile, getDataloom |
| Types | AppInfoPayload, IUserProfile, IJson, IFileAttachment |
| Constants | avatarImages, bannerImages, coverImages |

## 与 client-toolkit 的区别

| 能力 | client-toolkit | lite |
|------|:-:|:-:|
| AppContainer（完整版） | ✅ | 精简版 |
| antd ConfigProvider | ✅ | ❌ |
| AuthProvider / CanRole | ✅ | ❌ |
| Observable / Slardar | ✅ | ❌ |
| Sonner toast | ✅ | ❌ |
| Logger（批量上报） | ✅ | ❌ |
| MiaodaInspector | ✅ | ❌ |
| UI 基础组件 | ✅ | ❌ |
| User 组件 | ✅ | ❌ |
| Runtime（完整版） | ✅ | 精简版 |
| DataLoom | ✅ | ✅ |
| Hooks | 6 个 | 4 个 |
| 路由组件 | ✅ | ✅ |
| 工具函数 | ✅ | ✅ |

## License

MIT