diff --git a/docs/src/content/registry.ts b/docs/src/content/registry.ts
index 3da098a..4311648 100644
--- a/docs/src/content/registry.ts
+++ b/docs/src/content/registry.ts
@@ -31,8 +31,8 @@ const packageDefinitions: readonly PackageDefinition[] = [
key: "blocks",
label: "Blocks",
description: {
- zh: "构建应用外壳,并接入导航、通知、聊天、媒体和外观控制。",
- us: "Build an application shell and add navigation, notifications, chat, media, and appearance controls.",
+ zh: "构建应用外壳,并接入导航、通知、聊天和外观控制。",
+ us: "Build an application shell and add navigation, notifications, chat, and appearance controls.",
},
},
{
@@ -51,6 +51,14 @@ const packageDefinitions: readonly PackageDefinition[] = [
us: "Build a rich-text editor progressively from its root and content surface to custom actions and media.",
},
},
+ {
+ key: "media",
+ label: "Media",
+ description: {
+ zh: "通过存储 Adapter 构建媒体浏览、上传、目录管理和资源选择流程。",
+ us: "Build media browsing, uploads, folder management, and asset selection with a storage adapter.",
+ },
+ },
{
key: "preferences",
label: "Preferences",
diff --git a/packages/blocks/docs/en-US/advanced/media.mdx b/packages/blocks/docs/en-US/advanced/media.mdx
deleted file mode 100644
index 2edec21..0000000
--- a/packages/blocks/docs/en-US/advanced/media.mdx
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Media library
-description: Supply a storage adapter and add browsing, upload, folders, and asset selection.
-order: 21
-toc:
- - id: implement-the-adapter
- title: Implement the adapter
- - id: provide-media
- title: Provide media
- - id: selection-flows
- title: Selection flows
----
-
-## Implement the adapter {#implement-the-adapter}
-
-`MediaAdapter` is the media feature's complete persistence boundary. Implement its query, upload, folder, update, and delete operations with the product's storage service.
-
-## Provide media {#provide-media}
-
-Mount the adapter once around the media surfaces:
-
-```tsx
-import { MediaLibrary, MediaProvider } from "@workspace/blocks/media"
-
-;
-
-
-```
-
-The optional `notify` callback translates operational results into the application's toast or notification system.
-
-## Selection flows {#selection-flows}
-
-Use `MediaPickerDialog` for single or multiple asset selection. `readMediaDimensions`, `formatMediaFileSize`, and `defaultMediaReference` cover the common presentation work around uploads and previews.
diff --git a/packages/blocks/docs/en-US/guide/installation.mdx b/packages/blocks/docs/en-US/guide/installation.mdx
index 218fadc..18e78de 100644
--- a/packages/blocks/docs/en-US/guide/installation.mdx
+++ b/packages/blocks/docs/en-US/guide/installation.mdx
@@ -33,7 +33,7 @@ Import the block stylesheet once from the application entry:
import "@workspace/blocks/globals.css"
```
-Keep feature imports on their explicit subpaths. For example, importing `@workspace/blocks/media` does not pull chat into the same module graph.
+Keep feature imports on their explicit subpaths. For example, importing `@workspace/blocks/notifications` does not pull chat into the same module graph. Media workflows are provided separately by `@workspace/media`.
## Application providers {#application-providers}
diff --git a/packages/blocks/docs/en-US/overview.mdx b/packages/blocks/docs/en-US/overview.mdx
index d35320d..ce83d85 100644
--- a/packages/blocks/docs/en-US/overview.mdx
+++ b/packages/blocks/docs/en-US/overview.mdx
@@ -13,7 +13,7 @@ toc:
## What you will build {#what-you-will-build}
-This tutorial builds an application shell step by step. You will begin with the shared layout, connect navigation, then add notifications, chat, media, and appearance preferences.
+This tutorial builds an application shell step by step. You will begin with the shared layout, connect navigation, then add notifications, chat, and appearance preferences.
By the end, the application owns its data and business rules while `@workspace/blocks` owns the reusable presentation and interaction patterns.
@@ -29,5 +29,5 @@ Blocks sit above `@workspace/ui`. They combine low-level components into feature
2. Create the application shell.
3. Define navigation and route state.
4. Connect notifications.
-5. Add chat and media workflows.
+5. Add chat workflows.
6. Finish with persistent appearance controls.
diff --git a/packages/blocks/docs/zh-Hans/advanced/media.mdx b/packages/blocks/docs/zh-Hans/advanced/media.mdx
deleted file mode 100644
index f1e46f1..0000000
--- a/packages/blocks/docs/zh-Hans/advanced/media.mdx
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: 媒体库
-description: 提供存储 Adapter,并加入浏览、上传、文件夹和资源选择能力。
-order: 21
-toc:
- - id: implement-the-adapter
- title: 实现 Adapter
- - id: provide-media
- title: 提供媒体能力
- - id: selection-flows
- title: 选择流程
----
-
-## 实现 Adapter {#implement-the-adapter}
-
-`MediaAdapter` 是媒体功能完整的持久化边界。通过产品存储服务实现查询、上传、文件夹、更新和删除操作。
-
-## 提供媒体能力 {#provide-media}
-
-在媒体界面外挂载一次 Adapter:
-
-```tsx
-import { MediaLibrary, MediaProvider } from "@workspace/blocks/media"
-
-;
-
-
-```
-
-可选的 `notify` 回调把操作结果转换为应用的 Toast 或通知。
-
-## 选择流程 {#selection-flows}
-
-单选或多选资源使用 `MediaPickerDialog`。`readMediaDimensions`、`formatMediaFileSize` 和 `defaultMediaReference` 覆盖上传与预览相关的常用展示工作。
diff --git a/packages/blocks/docs/zh-Hans/guide/installation.mdx b/packages/blocks/docs/zh-Hans/guide/installation.mdx
index 37c836e..a221b65 100644
--- a/packages/blocks/docs/zh-Hans/guide/installation.mdx
+++ b/packages/blocks/docs/zh-Hans/guide/installation.mdx
@@ -33,7 +33,7 @@ Blocks 使用 `@workspace/ui`、React Query 和工作区国际化运行时。工
import "@workspace/blocks/globals.css"
```
-功能模块应始终从显式子路径导入。例如,导入 `@workspace/blocks/media` 不会把聊天功能加入同一个模块图。
+功能模块应始终从显式子路径导入。例如,导入 `@workspace/blocks/notifications` 不会把聊天功能加入同一个模块图。媒体工作流由独立的 `@workspace/media` 提供。
## 应用 Providers {#application-providers}
diff --git a/packages/blocks/docs/zh-Hans/overview.mdx b/packages/blocks/docs/zh-Hans/overview.mdx
index d29c561..eeafb19 100644
--- a/packages/blocks/docs/zh-Hans/overview.mdx
+++ b/packages/blocks/docs/zh-Hans/overview.mdx
@@ -13,7 +13,7 @@ toc:
## 将要构建的内容 {#what-you-will-build}
-本教程会逐步构建一个应用外壳。你将从共享布局开始,接入导航,再添加通知、聊天、媒体和外观偏好。
+本教程会逐步构建一个应用外壳。你将从共享布局开始,接入导航,再添加通知、聊天和外观偏好。
完成后,应用负责数据和业务规则,`@workspace/blocks` 负责可复用的展示与交互模式。
@@ -29,5 +29,5 @@ Blocks 位于 `@workspace/ui` 之上。它们将底层组件组合成完整功
2. 创建应用外壳。
3. 定义导航和路由状态。
4. 接入通知。
-5. 添加聊天和媒体工作流。
+5. 添加聊天工作流。
6. 使用持久化外观控件完成应用。
diff --git a/packages/media/docs/en-US/advanced/storage-adapter.mdx b/packages/media/docs/en-US/advanced/storage-adapter.mdx
new file mode 100644
index 0000000..b42de2b
--- /dev/null
+++ b/packages/media/docs/en-US/advanced/storage-adapter.mdx
@@ -0,0 +1,41 @@
+---
+title: Storage adapter
+description: Connect queries, uploads, mutations, URL resolution, and pagination to product infrastructure.
+order: 20
+toc:
+ - id: implement-the-contract
+ title: Implement the contract
+ - id: separate-display-and-reference-urls
+ title: Separate display and reference URLs
+ - id: preserve-query-semantics
+ title: Preserve query semantics
+---
+
+## Implement the contract {#implement-the-contract}
+
+`MediaAdapter` is the package's complete persistence boundary. Implement its asset queries, folder operations, uploads, updates, and deletes with the product's storage service.
+
+```ts
+import type { MediaAdapter } from "@workspace/media"
+
+export const mediaAdapter: MediaAdapter = {
+ listAssets: (query) => api.media.list(query),
+ listFolders: () => api.media.listFolders(),
+ upload: (input) => api.media.upload(input),
+ createFolder: (input) => api.media.createFolder(input),
+ updateFolder: (input) => api.media.updateFolder(input),
+ deleteFolder: (id) => api.media.deleteFolder(id),
+ moveAsset: (id, folderId) => api.media.move(id, folderId),
+ renameAsset: (id, name) => api.media.rename(id, name),
+ updateFavorite: (id, favorite) => api.media.favorite(id, favorite),
+ deleteAsset: (id) => api.media.delete(id),
+}
+```
+
+## Separate display and reference URLs {#separate-display-and-reference-urls}
+
+Use `resolveUrl` for short-lived signed URLs or image transformations used while rendering. Use `resolveReference` for the value returned by the picker and stored in another document. When `resolveReference` is absent, images use `defaultMediaReference`, which preserves intrinsic dimensions in the URL.
+
+## Preserve query semantics {#preserve-query-semantics}
+
+Treat `MediaAssetQuery` as an immutable request. Apply `allowedKinds`, `filter`, `folder`, and `keyword` before pagination, then return `hasNextPage` based on the filtered result. This keeps desktop and mobile filters consistent.
diff --git a/packages/media/docs/en-US/examples/asset-picker.mdx b/packages/media/docs/en-US/examples/asset-picker.mdx
new file mode 100644
index 0000000..ebb5a5f
--- /dev/null
+++ b/packages/media/docs/en-US/examples/asset-picker.mdx
@@ -0,0 +1,34 @@
+---
+title: Asset picker
+description: Reuse the media library as a controlled single- or multiple-selection dialog.
+order: 30
+toc:
+ - id: open-the-picker
+ title: Open the picker
+ - id: constrain-selection
+ title: Constrain selection
+ - id: consume-results
+ title: Consume results
+---
+
+## Open the picker {#open-the-picker}
+
+`MediaPickerDialog` reuses the same adapter and folder model as the full library:
+
+```tsx
+import { MediaPickerDialog } from "@workspace/media"
+
+; editor.insertImages(assets)}
+/>
+```
+
+## Constrain selection {#constrain-selection}
+
+Pass `allowedKinds={["image"]}` for an image-only workflow. The dialog selects one asset by default; pass `multiple` when the consumer accepts several assets, and provide `initialSelection` when editing an existing value.
+
+## Consume results {#consume-results}
+
+The confirmation callback receives complete `MediaAsset` records. Store the adapter-provided reference rather than a temporary preview URL when the result must survive signed-URL expiration.
diff --git a/packages/media/docs/en-US/guide/setup.mdx b/packages/media/docs/en-US/guide/setup.mdx
new file mode 100644
index 0000000..e6142bd
--- /dev/null
+++ b/packages/media/docs/en-US/guide/setup.mdx
@@ -0,0 +1,48 @@
+---
+title: Installation and setup
+description: Add Media, register its catalog, and connect the storage adapter.
+order: 10
+toc:
+ - id: add-the-package
+ title: Add the package
+ - id: register-styles-and-catalogs
+ title: Register styles and catalogs
+ - id: provide-media
+ title: Provide media
+---
+
+## Add the package {#add-the-package}
+
+Add Media to the consuming application:
+
+```json
+{
+ "dependencies": {
+ "@workspace/media": "workspace:*"
+ }
+}
+```
+
+## Register styles and catalogs {#register-styles-and-catalogs}
+
+Import the stylesheet once so Tailwind includes utilities used by the package:
+
+```css
+@import "@workspace/media/globals.css";
+```
+
+Add `@workspace/media/locales/{locale}` to the application's internationalization catalog sources.
+
+## Provide media {#provide-media}
+
+Mount the adapter once around every media surface that should share storage behavior and notifications:
+
+```tsx
+import { MediaLibrary, MediaProvider } from "@workspace/media"
+
+;
+
+
+```
+
+The optional `notify` callback turns operation results into the application's toast or notification system.
diff --git a/packages/media/docs/en-US/overview.mdx b/packages/media/docs/en-US/overview.mdx
new file mode 100644
index 0000000..5dbfdd0
--- /dev/null
+++ b/packages/media/docs/en-US/overview.mdx
@@ -0,0 +1,31 @@
+---
+title: Overview
+description: Understand the Media package, its storage boundary, and the workflows it owns.
+order: 1
+toc:
+ - id: package-role
+ title: Package role
+ - id: capabilities
+ title: Capabilities
+ - id: design-boundary
+ title: Design boundary
+---
+
+## Package role {#package-role}
+
+`@workspace/media` provides reusable media-library and asset-picker surfaces. The host application supplies persistence through `MediaAdapter`; Media owns browsing, filtering, pagination, uploads, folders, selection, and asset actions.
+
+## Capabilities {#capabilities}
+
+- Browse images and videos with search, filters, folders, favorites, and pagination.
+- Upload to local or cloud storage targets exposed by the adapter.
+- Create, rename, nest, and delete organizational folders.
+- Select one or multiple assets through `MediaPickerDialog`.
+- Resolve display URLs and stable references independently.
+- Ship `en-US` and `zh-Hans` message catalogs.
+
+## Design boundary {#design-boundary}
+
+Media does not choose an API, database, object store, CDN, or signing strategy. The application implements those decisions behind `MediaAdapter` and can replace them without changing the interface components.
+
+> Folders classify assets inside the library. They do not need to mirror object-storage paths or change public URLs.
diff --git a/packages/media/docs/zh-Hans/advanced/storage-adapter.mdx b/packages/media/docs/zh-Hans/advanced/storage-adapter.mdx
new file mode 100644
index 0000000..27f8643
--- /dev/null
+++ b/packages/media/docs/zh-Hans/advanced/storage-adapter.mdx
@@ -0,0 +1,41 @@
+---
+title: 存储 Adapter
+description: 将查询、上传、变更、URL 解析和分页连接到产品基础设施。
+order: 20
+toc:
+ - id: implement-the-contract
+ title: 实现完整契约
+ - id: separate-display-and-reference-urls
+ title: 区分展示与引用 URL
+ - id: preserve-query-semantics
+ title: 保持查询语义
+---
+
+## 实现完整契约 {#implement-the-contract}
+
+`MediaAdapter` 是这个包完整的持久化边界。通过产品的存储服务实现资源查询、目录操作、上传、更新和删除。
+
+```ts
+import type { MediaAdapter } from "@workspace/media"
+
+export const mediaAdapter: MediaAdapter = {
+ listAssets: (query) => api.media.list(query),
+ listFolders: () => api.media.listFolders(),
+ upload: (input) => api.media.upload(input),
+ createFolder: (input) => api.media.createFolder(input),
+ updateFolder: (input) => api.media.updateFolder(input),
+ deleteFolder: (id) => api.media.deleteFolder(id),
+ moveAsset: (id, folderId) => api.media.move(id, folderId),
+ renameAsset: (id, name) => api.media.rename(id, name),
+ updateFavorite: (id, favorite) => api.media.favorite(id, favorite),
+ deleteAsset: (id) => api.media.delete(id),
+}
+```
+
+## 区分展示与引用 URL {#separate-display-and-reference-urls}
+
+使用 `resolveUrl` 返回渲染时需要的短期签名 URL 或图片转换地址。使用 `resolveReference` 返回选择器写入其他文档的值。未提供 `resolveReference` 时,图片会使用 `defaultMediaReference`,在 URL 中保留固有尺寸。
+
+## 保持查询语义 {#preserve-query-semantics}
+
+将 `MediaAssetQuery` 当作不可变请求。在分页前依次应用 `allowedKinds`、`filter`、`folder` 和 `keyword`,然后根据筛选后的结果返回 `hasNextPage`。这样可以保持桌面端与移动端筛选行为一致。
diff --git a/packages/media/docs/zh-Hans/examples/asset-picker.mdx b/packages/media/docs/zh-Hans/examples/asset-picker.mdx
new file mode 100644
index 0000000..28b1c40
--- /dev/null
+++ b/packages/media/docs/zh-Hans/examples/asset-picker.mdx
@@ -0,0 +1,34 @@
+---
+title: 资源选择器
+description: 将媒体库复用为受控的单选或多选对话框。
+order: 30
+toc:
+ - id: open-the-picker
+ title: 打开选择器
+ - id: constrain-selection
+ title: 限制选择范围
+ - id: consume-results
+ title: 使用选择结果
+---
+
+## 打开选择器 {#open-the-picker}
+
+`MediaPickerDialog` 会复用完整媒体库相同的 Adapter 和目录模型:
+
+```tsx
+import { MediaPickerDialog } from "@workspace/media"
+
+; editor.insertImages(assets)}
+/>
+```
+
+## 限制选择范围 {#constrain-selection}
+
+图片专用流程传入 `allowedKinds={["image"]}`。对话框默认单选;消费方可以接受多个资源时传入 `multiple`,编辑已有值时通过 `initialSelection` 恢复选择。
+
+## 使用选择结果 {#consume-results}
+
+确认回调会收到完整的 `MediaAsset` 记录。如果结果需要在签名 URL 失效后继续使用,应保存 Adapter 提供的稳定引用,而不是临时预览地址。
diff --git a/packages/media/docs/zh-Hans/guide/setup.mdx b/packages/media/docs/zh-Hans/guide/setup.mdx
new file mode 100644
index 0000000..003df3e
--- /dev/null
+++ b/packages/media/docs/zh-Hans/guide/setup.mdx
@@ -0,0 +1,48 @@
+---
+title: 安装与设置
+description: 添加 Media、注册词典并连接存储 Adapter。
+order: 10
+toc:
+ - id: add-the-package
+ title: 添加包
+ - id: register-styles-and-catalogs
+ title: 注册样式与词典
+ - id: provide-media
+ title: 提供媒体能力
+---
+
+## 添加包 {#add-the-package}
+
+在使用方应用中添加 Media:
+
+```json
+{
+ "dependencies": {
+ "@workspace/media": "workspace:*"
+ }
+}
+```
+
+## 注册样式与词典 {#register-styles-and-catalogs}
+
+导入一次样式表,让 Tailwind 包含 Media 使用的工具类:
+
+```css
+@import "@workspace/media/globals.css";
+```
+
+将 `@workspace/media/locales/{locale}` 加入应用的国际化 catalog sources。
+
+## 提供媒体能力 {#provide-media}
+
+在需要共享存储行为和通知方式的媒体界面外统一挂载 Adapter:
+
+```tsx
+import { MediaLibrary, MediaProvider } from "@workspace/media"
+
+;
+
+
+```
+
+可选的 `notify` 回调会把操作结果接入应用自己的 Toast 或通知系统。
diff --git a/packages/media/docs/zh-Hans/overview.mdx b/packages/media/docs/zh-Hans/overview.mdx
new file mode 100644
index 0000000..680bac5
--- /dev/null
+++ b/packages/media/docs/zh-Hans/overview.mdx
@@ -0,0 +1,31 @@
+---
+title: 概览
+description: 了解 Media 包、存储边界以及它负责的媒体工作流。
+order: 1
+toc:
+ - id: package-role
+ title: 包的职责
+ - id: capabilities
+ title: 功能范围
+ - id: design-boundary
+ title: 设计边界
+---
+
+## 包的职责 {#package-role}
+
+`@workspace/media` 提供可复用的媒体库和资源选择界面。宿主应用通过 `MediaAdapter` 提供持久化能力;Media 负责浏览、筛选、分页、上传、目录、选择和资源操作。
+
+## 功能范围 {#capabilities}
+
+- 通过搜索、筛选、目录、收藏和分页浏览图片与视频。
+- 上传到 Adapter 暴露的本地或云端存储目标。
+- 创建、重命名、嵌套和删除分类目录。
+- 通过 `MediaPickerDialog` 单选或多选资源。
+- 分别解析展示 URL 和稳定引用。
+- 提供 `en-US` 与 `zh-Hans` 消息词典。
+
+## 设计边界 {#design-boundary}
+
+Media 不会替应用选择 API、数据库、对象存储、CDN 或签名策略。应用在 `MediaAdapter` 后实现这些决策,替换实现时无需修改界面组件。
+
+> 目录只用于媒体库内部分类,不必对应对象存储路径,也不需要改变公开 URL。
diff --git a/packages/ui/docs/en-US/overview.mdx b/packages/ui/docs/en-US/overview.mdx
index 83f874b..4c9c5d6 100644
--- a/packages/ui/docs/en-US/overview.mdx
+++ b/packages/ui/docs/en-US/overview.mdx
@@ -21,4 +21,4 @@ This tutorial installs the styles, introduces component subpaths, builds a small
## UI or Blocks {#ui-or-blocks}
-Use UI components when the application owns the workflow. Use `@workspace/blocks` when the interface also needs a complete feature contract such as navigation, media storage, search adapters, or notification queries.
+Use UI components when the application owns the workflow. Use `@workspace/blocks` for complete application-shell features such as navigation and notifications, and focused packages such as `@workspace/media` or `@workspace/search` for domain workflows.
diff --git a/packages/ui/docs/zh-Hans/overview.mdx b/packages/ui/docs/zh-Hans/overview.mdx
index edaea83..5032d71 100644
--- a/packages/ui/docs/zh-Hans/overview.mdx
+++ b/packages/ui/docs/zh-Hans/overview.mdx
@@ -21,4 +21,4 @@ toc:
## UI 还是 Blocks {#ui-or-blocks}
-当应用自己拥有业务流程时使用 UI 组件。当界面还需要导航、媒体存储、搜索适配器或通知查询等完整功能契约时,使用 `@workspace/blocks`。
+当应用自己拥有业务流程时使用 UI 组件。导航和通知等完整应用外壳功能使用 `@workspace/blocks`,媒体与搜索等领域工作流使用 `@workspace/media` 或 `@workspace/search` 等专用包。