@cut-workbench/workbench 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -9
- package/dist/CutWorkbench.d.ts +26 -1
- package/dist/auto.cjs +4 -0
- package/dist/auto.d.ts +19 -0
- package/dist/auto.js +8 -0
- package/dist/components/common/UnsupportedBrowser.d.ts +6 -1
- package/dist/components/layout/AppShell.d.ts +17 -3
- package/dist/components/layout/WorkbenchToolbar.d.ts +39 -2
- package/dist/cut-workbench.css +47 -6
- package/dist/features/lab/index.d.ts +5 -1
- package/dist/features/media-library/components/DropZone.d.ts +6 -0
- package/dist/features/media-library/lib/pick-files.d.ts +24 -0
- package/dist/hooks/use-toast-safe.d.ts +9 -1
- package/dist/index.cjs +937 -1969
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +825 -1836
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +3 -0
- package/dist/lab-disabled.cjs +6 -0
- package/dist/lab-disabled.cjs.map +1 -0
- package/dist/lab-disabled.d.ts +13 -0
- package/dist/lab-disabled.js +5 -0
- package/dist/lab-disabled.js.map +1 -0
- package/dist/lab.cjs +1194 -0
- package/dist/lab.cjs.map +1 -0
- package/dist/lab.d.ts +32 -0
- package/dist/lab.js +1193 -0
- package/dist/lab.js.map +1 -0
- package/dist/lib/notify.d.ts +40 -0
- package/dist/notify-CEwFQgjC.js +233 -0
- package/dist/notify-CEwFQgjC.js.map +1 -0
- package/dist/notify-CMNwDFGw.cjs +380 -0
- package/dist/notify-CMNwDFGw.cjs.map +1 -0
- package/dist/umd/cut-workbench.umd.js +1 -1
- package/package.json +84 -67
package/README.md
CHANGED
|
@@ -5,22 +5,55 @@
|
|
|
5
5
|
|
|
6
6
|
## 安装
|
|
7
7
|
|
|
8
|
+
**只需要装这一个包**:
|
|
9
|
+
|
|
8
10
|
```bash
|
|
9
|
-
npm i @cut-workbench/workbench
|
|
10
|
-
# 引擎依赖(预览 / 导出必需)
|
|
11
|
-
npm i @webav/av-cliper @webav/av-canvas @webav/av-recorder
|
|
11
|
+
npm i @cut-workbench/workbench
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
`@
|
|
15
|
-
`@webav
|
|
14
|
+
`@cut-workbench/core`、`@cut-workbench/react` 以及引擎依赖
|
|
15
|
+
`@webav/av-cliper`、`@webav/av-canvas`、`@webav/av-recorder` 都是它的
|
|
16
|
+
**dependencies**,会一起装上 —— 不需要你再显式安装,也不需要知道有这些东西。
|
|
17
|
+
|
|
18
|
+
选装(按需):
|
|
19
|
+
|
|
20
|
+
| 想要什么 | 装什么 |
|
|
21
|
+
|---|---|
|
|
22
|
+
| 只取纯逻辑,不渲染 UI | `npm i @cut-workbench/core` |
|
|
23
|
+
| 只要 React hooks,自己写 UI | `npm i @cut-workbench/core @cut-workbench/react` |
|
|
24
|
+
| Electron 宿主桥(「下载」→「保存到指定路径」) | `npm i @cut-workbench/host-electron` |
|
|
25
|
+
| 需要控制 React 实例 | 宿主自己提供 `react` / `react-dom` / `zustand`(见下) |
|
|
26
|
+
|
|
27
|
+
### 关于 `react` / `react-dom` / `zustand`
|
|
28
|
+
|
|
29
|
+
这三个是 **peer 依赖**,由宿主提供,库不会替你装 —— 一旦出现两份 React,
|
|
30
|
+
宿主会碰到 `Cannot read properties of null (reading 'useContext')`。项目已有
|
|
31
|
+
React 时无需任何额外操作。
|
|
32
|
+
|
|
33
|
+
`zustand` 同理:`@cut-workbench/react` 直接 import 它,两份实例会让订阅错乱,
|
|
34
|
+
所以必须由宿主提供(React 项目通常已有)。
|
|
35
|
+
|
|
36
|
+
### 为什么 WebAV 是 dependencies 而不是 peer
|
|
37
|
+
|
|
38
|
+
`@webav/*` 是**运行时必需**的:没有 `av-cliper` / `av-canvas` 就没有预览和
|
|
39
|
+
导出,功能直接不可用。所以这个包选择把它们带上,让「装一个包就能用」成立。
|
|
40
|
+
|
|
41
|
+
`@cut-workbench/core` 则相反 —— 它的定位是「只取纯逻辑」,有人只要 timeline
|
|
42
|
+
模型和工程序列化,不该被迫装 WebAV,所以 core 那边是 `optional` peer。
|
|
43
|
+
|
|
44
|
+
> ⚠️ 0.1.0 的 WebAV 是 peer,只靠 npm 7+ 自动安装 peer 的隐式行为碰巧能跑;
|
|
45
|
+
> **pnpm / yarn 不会自动装 peer**,在它们下面构建会报
|
|
46
|
+
> `[MISSING_EXPORT] "Combinator" is not exported by "__vite-optional-peer-dep:…"`。
|
|
47
|
+
> 0.2.0 起改为 dependencies,与包管理器无关。
|
|
16
48
|
|
|
17
49
|
## React 项目
|
|
18
50
|
|
|
51
|
+
**推荐:用 `/auto` 子入口**,一行自带样式:
|
|
52
|
+
|
|
19
53
|
```tsx
|
|
20
54
|
import { createEditor } from '@cut-workbench/core/engine'
|
|
21
55
|
import { CutEditorProvider } from '@cut-workbench/react'
|
|
22
|
-
import { CutWorkbench, CutWorkbenchProvider } from '@cut-workbench/workbench'
|
|
23
|
-
import '@cut-workbench/workbench/style.css'
|
|
56
|
+
import { CutWorkbench, CutWorkbenchProvider } from '@cut-workbench/workbench/auto'
|
|
24
57
|
|
|
25
58
|
const editor = createEditor()
|
|
26
59
|
|
|
@@ -33,11 +66,77 @@ createRoot(el).render(
|
|
|
33
66
|
)
|
|
34
67
|
```
|
|
35
68
|
|
|
69
|
+
**根入口不自带样式** —— 给已经有自己的构建流程、需要控制 CSS 顺序
|
|
70
|
+
(例如要压过某条全局重置)的场景:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { CutWorkbench, CutWorkbenchProvider } from '@cut-workbench/workbench'
|
|
74
|
+
import '@cut-workbench/workbench/style.css' // ← 必须自己引,忘了就是无样式
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
两者的 API 完全一致,`/auto` 只是多了一行 `import './cut-workbench.css'`。
|
|
78
|
+
**不要同时引两个入口** —— 样式会被引入两次(作用域化之后是幂等的,但没必要)。
|
|
79
|
+
|
|
80
|
+
## 布局
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
┌───────────────────────────────────────────┐
|
|
84
|
+
│ 顶栏 │
|
|
85
|
+
├──────────┬──────────────┬─────────────────┤
|
|
86
|
+
│ 素材库 │ 预览 │ 属性 │ ← 上半区,可纵向滚动
|
|
87
|
+
├──────────┴──────────────┴─────────────────┤
|
|
88
|
+
│ 时间轴(横跨整行) │ ← 下栏
|
|
89
|
+
└───────────────────────────────────────────┘
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
时间轴**通栏占满底部一行**,不随左右面板宽度变化。左上「素材」、中「预览」、
|
|
93
|
+
右「属性」三栏可拖拽调整,面板内的内容各自滚动。
|
|
94
|
+
|
|
95
|
+
> 0.2.0 之前时间轴被塞在中间列里,左右面板一拉宽就把它挤窄,工具条按钮会
|
|
96
|
+
> 溢出到属性面板上;窄列下播放控制条的时间码也会被裁掉。现在布局与控件都有
|
|
97
|
+
> 容器级自适应(按容器宽度分档收起次要控件,而不是按视口宽度),
|
|
98
|
+
> `scripts/layout-test.mjs` 守着这两条。
|
|
99
|
+
|
|
100
|
+
## 顶栏定制
|
|
101
|
+
|
|
102
|
+
内置顶栏分三层可定制,由浅到深:
|
|
103
|
+
|
|
104
|
+
**1. 改文案** —— `labels`:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<CutWorkbench toolbar={{ labels: { export: '导出成片', untitledProject: '新建项目' } }} />
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**2. 改局部** —— `brand` / `title` / `status` / `actions`:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<CutWorkbench
|
|
114
|
+
toolbar={{
|
|
115
|
+
brand: <MyLogo />, // 默认**没有**品牌区,避免露出本库名字
|
|
116
|
+
title: null, // 不要工程名区
|
|
117
|
+
status: <AutoSaveBadge />, // 默认「空工程 · 16:9」
|
|
118
|
+
actions: <MyShareButton />, // 追加在右侧按钮组末尾
|
|
119
|
+
editableTitle: true, // 双击工程名重命名(走撤销栈)
|
|
120
|
+
showCapabilityBadge: false, // 隐藏引擎能力徽标
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**3. 整条替换** —— `slots.topBar`(优先级最高):
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
<CutWorkbench slots={{ topBar: <MyHeader /> }} /> // 传 null 表示完全不要顶栏
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
> `slots.topBar` 会替换**整条**顶栏,撤销/导出等内置动作一并由宿主负责;
|
|
132
|
+
> `toolbar` 只换其中一块,其余保留。可运行示例见 playground 的
|
|
133
|
+
> `/toolbar-demo.html`。
|
|
134
|
+
|
|
135
|
+
|
|
36
136
|
## 非 React 项目
|
|
37
137
|
|
|
38
138
|
```js
|
|
39
|
-
import { initCutWorkbench } from '@cut-workbench/workbench'
|
|
40
|
-
import '@cut-workbench/workbench/style.css'
|
|
139
|
+
import { initCutWorkbench } from '@cut-workbench/workbench/auto'
|
|
41
140
|
|
|
42
141
|
const wb = initCutWorkbench('#app', { theme: 'dark', namespace: 'my-project' })
|
|
43
142
|
await wb.whenReady()
|
|
@@ -58,6 +157,51 @@ UMD 单文件已把 React、WebAV、Worker 与样式全部内联,暴露 `windo
|
|
|
58
157
|
> ⚠️ React 19 不再发布 UMD 产物,因此 UMD 版本内置了一份 React。有任何构建工具时
|
|
59
158
|
> 都优先选 ESM。
|
|
60
159
|
|
|
160
|
+
## 类型与依赖缺失
|
|
161
|
+
|
|
162
|
+
如果引擎依赖没解析到(例如被 npm 的 hoisting 拔掉、或在 pnpm 下版本冲突),
|
|
163
|
+
工作台不会白屏:能力探测会把「缺依赖」和「浏览器不支持」分开报告,
|
|
164
|
+
阻断页直接给出可执行的安装命令:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
缺少 @webav/av-cliper,请执行 npm i @webav/av-cliper @webav/av-canvas @webav/av-recorder
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
注意缺失依赖只在**构建期**解析 —— 装完必须重新跑一次构建,刷新浏览器没用。
|
|
171
|
+
|
|
172
|
+
## 关掉能力实验室(可选)
|
|
173
|
+
|
|
174
|
+
`config.features.lab` 是**运行时**开关,默认 `false`。lab 本体是独立子入口
|
|
175
|
+
`@cut-workbench/workbench/lab`,主包对它做动态 import —— 所以默认配置下
|
|
176
|
+
lab 的代码(含 `@webav/av-recorder`)不会加载,但打包器仍会产出一个约 33 KB 的
|
|
177
|
+
lab chunk。
|
|
178
|
+
|
|
179
|
+
要在产物里**彻底删掉**它,在宿主的构建配置里把子入口指到空实现:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
// vite.config.ts
|
|
183
|
+
export default {
|
|
184
|
+
resolve: {
|
|
185
|
+
alias: [
|
|
186
|
+
{
|
|
187
|
+
find: /^@cut-workbench\/workbench\/lab$/,
|
|
188
|
+
replacement: '@cut-workbench/workbench/lab-disabled',
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
验证方式:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
grep -c "FrameCounterClip" dist/assets/*.js # 应为 0
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
> 为什么不是 `define: { __CUT_WORKBENCH_LAB__: 'false' }`:实测(Vite 8 /
|
|
202
|
+
> Rolldown)动态 import 只要出现在模块图里,chunk 就会被写进 dist,即便所在
|
|
203
|
+
> 分支已被折成死代码。只有把模块解析本身换掉才真正生效。
|
|
204
|
+
|
|
61
205
|
## 主题定制
|
|
62
206
|
|
|
63
207
|
```tsx
|
package/dist/CutWorkbench.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* - 不强制能力阻断页(宿主可自行决定)。
|
|
9
9
|
*/
|
|
10
10
|
import { type ReactNode } from 'react';
|
|
11
|
+
import { type WorkbenchToolbarLabels } from './components/layout/WorkbenchToolbar';
|
|
11
12
|
export interface CutWorkbenchSlots {
|
|
12
13
|
/** 替换内置顶栏;传 `null` 表示不要顶栏 */
|
|
13
14
|
topBar?: ReactNode | null;
|
|
@@ -16,8 +17,32 @@ export interface CutWorkbenchSlots {
|
|
|
16
17
|
inspector?: ReactNode;
|
|
17
18
|
timeline?: ReactNode;
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* 顶栏的局部自定义。
|
|
22
|
+
*
|
|
23
|
+
* 与 `slots.topBar` 的区别:`slots.topBar` 会替换**整条**顶栏(撤销、导出等
|
|
24
|
+
* 内置动作一并消失,宿主自己负责);`toolbar` 只替换其中某一块,其余保留。
|
|
25
|
+
*/
|
|
26
|
+
export interface CutWorkbenchToolbarOptions {
|
|
27
|
+
/** 左侧品牌区;传 `null` 表示不要(默认就没有,避免在宿主产品里露出本库品牌) */
|
|
28
|
+
brand?: ReactNode | null;
|
|
29
|
+
/** 工程名区;传 `null` 表示不要 */
|
|
30
|
+
title?: ReactNode | null;
|
|
31
|
+
/** 工程名右侧状态(默认「空工程 · 16:9」);传 `null` 表示不要 */
|
|
32
|
+
status?: ReactNode | null;
|
|
33
|
+
/** 在右侧按钮组末尾追加宿主动作 */
|
|
34
|
+
actions?: ReactNode;
|
|
35
|
+
/** 是否显示引擎能力徽标,默认 true */
|
|
36
|
+
showCapabilityBadge?: boolean;
|
|
37
|
+
/** 是否允许双击工程名重命名,默认 false */
|
|
38
|
+
editableTitle?: boolean;
|
|
39
|
+
/** 覆盖内置文案 */
|
|
40
|
+
labels?: WorkbenchToolbarLabels;
|
|
41
|
+
}
|
|
19
42
|
export interface CutWorkbenchProps {
|
|
20
43
|
slots?: CutWorkbenchSlots;
|
|
44
|
+
/** 顶栏的局部自定义(`slots.topBar` 优先级更高) */
|
|
45
|
+
toolbar?: CutWorkbenchToolbarOptions;
|
|
21
46
|
className?: string;
|
|
22
47
|
/**
|
|
23
48
|
* 工程持久化回调。
|
|
@@ -34,4 +59,4 @@ export interface CutWorkbenchProps {
|
|
|
34
59
|
*
|
|
35
60
|
* 必须在 `<WorkbenchProvider>` + `<CutEditorProvider>` 之内使用。
|
|
36
61
|
*/
|
|
37
|
-
export declare function CutWorkbench({ slots, className, onSaveProject, onOpenProject, enforceCapability, }: CutWorkbenchProps): import("react").JSX.Element;
|
|
62
|
+
export declare function CutWorkbench({ slots, toolbar: toolbarOptions, className, onSaveProject, onOpenProject, enforceCapability, }: CutWorkbenchProps): import("react").JSX.Element;
|
package/dist/auto.cjs
ADDED
package/dist/auto.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自带样式的接入入口。
|
|
3
|
+
*
|
|
4
|
+
* 根入口(`@cut-workbench/workbench`)刻意**不带**样式:宿主若已有自己的构建
|
|
5
|
+
* 流程、需要控制 CSS 顺序(例如要压过某条全局重置),可以自己决定何时引入
|
|
6
|
+
* `@cut-workbench/workbench/style.css`。
|
|
7
|
+
*
|
|
8
|
+
* 这个入口把「引入样式 + 导出 API」合成一步:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { CutWorkbench, CutWorkbenchProvider } from '@cut-workbench/workbench/auto'
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ 下面这行 import 是 Vite 产出 CSS 的唯一依据(`build.mjs` 会把产物写进
|
|
15
|
+
* `dist/cut-workbench.css`)。它会被 tsc 原样写进 `dist/auto.d.ts`,而 dist 下
|
|
16
|
+
* 没有 `styles/` 目录,接入方关掉 skipLibCheck 会报 TS2882 ——
|
|
17
|
+
* 由 `scripts/fix-dts-paths.mjs` 在构建后剥离。
|
|
18
|
+
*/
|
|
19
|
+
export * from './index';
|
package/dist/auto.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// 由 build.mjs 生成:自带样式的入口,见 src/auto.ts
|
|
2
|
+
//
|
|
3
|
+
// ⚠️ 本文件必须留在 package.json 的 "sideEffects" 白名单里。打包器会按
|
|
4
|
+
// sideEffects 判定「整个模块可丢弃」,而 auto 的唯一副作用就是下面这行
|
|
5
|
+
// CSS 导入 —— 一旦被判为无副作用,宿主 bundle 里不会报错、日志里没有痕迹,
|
|
6
|
+
// 只是页面彻底没有样式(实测 Vite/Rolldown 行为)。
|
|
7
|
+
import './cut-workbench.css'
|
|
8
|
+
export * from './index.js'
|
|
@@ -4,6 +4,11 @@ interface UnsupportedBrowserProps {
|
|
|
4
4
|
loading: boolean;
|
|
5
5
|
error?: string | null;
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* 不满足运行条件时的阻断页:逐项说明缺失能力,不做静默降级。
|
|
9
|
+
*
|
|
10
|
+
* 「依赖没装」与「浏览器不支持」要分开呈现 —— 前者是宿主的构建问题(可执行
|
|
11
|
+
* 安装命令解决),后者只能换浏览器。混在一起会让人对着一条装包报错去升浏览器。
|
|
12
|
+
*/
|
|
8
13
|
export declare function UnsupportedBrowser({ report, loading, error }: UnsupportedBrowserProps): import("react").JSX.Element;
|
|
9
14
|
export {};
|
|
@@ -17,10 +17,24 @@ interface AppShellProps {
|
|
|
17
17
|
className?: string;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* 工作台骨架:顶栏 + 上半区(素材 / 预览 / 属性)+ 底部通栏时间轴。
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* ```
|
|
23
|
+
* ┌───────────────────────────────────────────┐
|
|
24
|
+
* │ 顶栏 │
|
|
25
|
+
* ├──────────┬──────────────┬─────────────────┤
|
|
26
|
+
* │ 素材库 │ 预览 │ 属性 │ 上半区
|
|
27
|
+
* ├──────────┴──────────────┴─────────────────┤
|
|
28
|
+
* │ 时间轴(横跨整行) │ 下栏
|
|
29
|
+
* └───────────────────────────────────────────┘
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* 时间轴必须是**通栏**的:它曾被塞进中间列,于是左右面板一拉宽就把时间轴
|
|
33
|
+
* 挤窄,工具条上的按钮直接溢出到属性面板上(实测右栏拉宽时溢出 203px)。
|
|
34
|
+
* 与此同时,几乎所有 NLE 都是「轨道占满底部一条」,通栏也更符合预期。
|
|
35
|
+
*
|
|
36
|
+
* 尺寸一律用 inline style 的像素值(受控),配合 PanelResizer 的拖拽回写;
|
|
37
|
+
* 不用 tailwind 动态 class,避免被 purge 掉导致尺寸失效。
|
|
24
38
|
*/
|
|
25
39
|
export declare function AppShell({ topBar, left, center, right, timeline, leftWidth, rightWidth, timelineHeight, leftResizer, rightResizer, timelineResizer, className, }: AppShellProps): import("react").JSX.Element;
|
|
26
40
|
export {};
|
|
@@ -5,9 +5,30 @@
|
|
|
5
5
|
* - 品牌区可替换(`brand`),不强制显示项目名;
|
|
6
6
|
* - 保存/打开是可选回调,宿主不提供就不渲染按钮;
|
|
7
7
|
* - 「视图切换(编辑器/实验室)」只在开启 lab 特性时显示。
|
|
8
|
+
*
|
|
9
|
+
* 可自定义的层次(由浅到深):
|
|
10
|
+
* 1. **文案**:`labels` 覆盖工程名占位、能力徽标等;
|
|
11
|
+
* 2. **局部**:`brand` / `title` / `status` / `actions` / `showCapabilityBadge`
|
|
12
|
+
* 逐块替换;
|
|
13
|
+
* 3. **整条**:`slots.topBar`(传 `null` 表示完全不要顶栏)。
|
|
8
14
|
*/
|
|
9
|
-
import type
|
|
15
|
+
import { type ReactNode } from 'react';
|
|
10
16
|
import type { CapabilityInfo } from './use-capability-info';
|
|
17
|
+
/** 可覆盖的文案;缺省用内置中文 */
|
|
18
|
+
export interface WorkbenchToolbarLabels {
|
|
19
|
+
/** 空工程的占位名(工程名称为空时显示) */
|
|
20
|
+
untitledProject?: string;
|
|
21
|
+
/** 「空工程」/「N 个片段」里的占位 */
|
|
22
|
+
emptyProject?: string;
|
|
23
|
+
export?: string;
|
|
24
|
+
canvasSettings?: string;
|
|
25
|
+
showLab?: string;
|
|
26
|
+
backToEditor?: string;
|
|
27
|
+
save?: string;
|
|
28
|
+
open?: string;
|
|
29
|
+
undo?: string;
|
|
30
|
+
redo?: string;
|
|
31
|
+
}
|
|
11
32
|
export interface WorkbenchToolbarProps {
|
|
12
33
|
capability: CapabilityInfo;
|
|
13
34
|
onExport: () => void;
|
|
@@ -17,8 +38,24 @@ export interface WorkbenchToolbarProps {
|
|
|
17
38
|
onOpenProject?: () => void;
|
|
18
39
|
/** 替换左侧品牌区;传 null 表示不要 */
|
|
19
40
|
brand?: ReactNode | null;
|
|
41
|
+
/**
|
|
42
|
+
* 替换「工程名」区;传 null 表示不要。
|
|
43
|
+
*
|
|
44
|
+
* 不传时用内置的只读展示(工程名 + 未保存圆点)。
|
|
45
|
+
*/
|
|
46
|
+
title?: ReactNode | null;
|
|
47
|
+
/** 替换工程名右侧的状态文案区(默认「空工程 · 16:9」);传 null 表示不要 */
|
|
48
|
+
status?: ReactNode | null;
|
|
49
|
+
/** 在右侧按钮组**末尾**追加宿主自己的动作 */
|
|
50
|
+
actions?: ReactNode;
|
|
51
|
+
/** 是否显示引擎能力徽标,默认 true */
|
|
52
|
+
showCapabilityBadge?: boolean;
|
|
53
|
+
/** 是否允许双击工程名重命名,默认 false(宿主可能用自己的工程体系) */
|
|
54
|
+
editableTitle?: boolean;
|
|
20
55
|
/** 是否显示「实验室」入口 */
|
|
21
56
|
showLab?: boolean;
|
|
57
|
+
/** 覆盖内置文案 */
|
|
58
|
+
labels?: WorkbenchToolbarLabels;
|
|
22
59
|
}
|
|
23
60
|
/** 顶栏:品牌 / 工程名 / 撤销重做 / 保存 / 导出 / 能力徽标 / 视图切换 */
|
|
24
|
-
export declare function WorkbenchToolbar({ capability, onExport, onSaveProject, onOpenProject, brand, showLab, }: WorkbenchToolbarProps): import("react").JSX.Element;
|
|
61
|
+
export declare function WorkbenchToolbar({ capability, onExport, onSaveProject, onOpenProject, brand, title, status, actions, showCapabilityBadge, showLab, editableTitle, labels, }: WorkbenchToolbarProps): import("react").JSX.Element;
|
package/dist/cut-workbench.css
CHANGED
|
@@ -112,7 +112,6 @@
|
|
|
112
112
|
--font-weight-normal: 400;
|
|
113
113
|
--font-weight-medium: 500;
|
|
114
114
|
--font-weight-semibold: 600;
|
|
115
|
-
--tracking-tight: -.025em;
|
|
116
115
|
--tracking-wide: .025em;
|
|
117
116
|
--tracking-widest: .1em;
|
|
118
117
|
--leading-tight: 1.25;
|
|
@@ -132,6 +131,10 @@
|
|
|
132
131
|
container: card-header / inline-size;
|
|
133
132
|
}
|
|
134
133
|
|
|
134
|
+
.cw-root .\@container {
|
|
135
|
+
container-type: inline-size;
|
|
136
|
+
}
|
|
137
|
+
|
|
135
138
|
.cw-root .pointer-events-auto {
|
|
136
139
|
pointer-events: auto;
|
|
137
140
|
}
|
|
@@ -636,6 +639,10 @@
|
|
|
636
639
|
min-height: calc(var(--spacing) * 16);
|
|
637
640
|
}
|
|
638
641
|
|
|
642
|
+
.cw-root .min-h-\[220px\] {
|
|
643
|
+
min-height: 220px;
|
|
644
|
+
}
|
|
645
|
+
|
|
639
646
|
.cw-root .min-h-screen {
|
|
640
647
|
min-height: 100vh;
|
|
641
648
|
}
|
|
@@ -676,6 +683,10 @@
|
|
|
676
683
|
width: calc(var(--spacing) * 44);
|
|
677
684
|
}
|
|
678
685
|
|
|
686
|
+
.cw-root .w-48 {
|
|
687
|
+
width: calc(var(--spacing) * 48);
|
|
688
|
+
}
|
|
689
|
+
|
|
679
690
|
.cw-root .w-72 {
|
|
680
691
|
width: calc(var(--spacing) * 72);
|
|
681
692
|
}
|
|
@@ -853,6 +864,10 @@
|
|
|
853
864
|
cursor: row-resize;
|
|
854
865
|
}
|
|
855
866
|
|
|
867
|
+
.cw-root .cursor-text {
|
|
868
|
+
cursor: text;
|
|
869
|
+
}
|
|
870
|
+
|
|
856
871
|
.cw-root .touch-none {
|
|
857
872
|
touch-action: none;
|
|
858
873
|
}
|
|
@@ -1051,6 +1066,10 @@
|
|
|
1051
1066
|
overflow-y: auto;
|
|
1052
1067
|
}
|
|
1053
1068
|
|
|
1069
|
+
.cw-root .overflow-y-hidden {
|
|
1070
|
+
overflow-y: hidden;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1054
1073
|
.cw-root .rounded {
|
|
1055
1074
|
border-radius: .25rem;
|
|
1056
1075
|
}
|
|
@@ -1185,6 +1204,16 @@
|
|
|
1185
1204
|
border-color: currentColor;
|
|
1186
1205
|
}
|
|
1187
1206
|
|
|
1207
|
+
.cw-root .border-destructive\/40 {
|
|
1208
|
+
border-color: var(--cw-destructive);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1212
|
+
.cw-root .border-destructive\/40 {
|
|
1213
|
+
border-color: color-mix(in oklab, var(--cw-destructive) 40%, transparent);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1188
1217
|
.cw-root .border-destructive\/50 {
|
|
1189
1218
|
border-color: var(--cw-destructive);
|
|
1190
1219
|
}
|
|
@@ -1895,11 +1924,6 @@
|
|
|
1895
1924
|
font-weight: var(--font-weight-semibold);
|
|
1896
1925
|
}
|
|
1897
1926
|
|
|
1898
|
-
.cw-root .tracking-tight {
|
|
1899
|
-
--tw-tracking: var(--tracking-tight);
|
|
1900
|
-
letter-spacing: var(--tracking-tight);
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
1927
|
.cw-root .tracking-wide {
|
|
1904
1928
|
--tw-tracking: var(--tracking-wide);
|
|
1905
1929
|
letter-spacing: var(--tracking-wide);
|
|
@@ -2566,6 +2590,11 @@
|
|
|
2566
2590
|
color: var(--cw-accent-foreground);
|
|
2567
2591
|
}
|
|
2568
2592
|
|
|
2593
|
+
.cw-root .focus\:ring-1:focus {
|
|
2594
|
+
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
2595
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2569
2598
|
.cw-root .focus\:ring-2:focus {
|
|
2570
2599
|
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
2571
2600
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -3044,6 +3073,12 @@
|
|
|
3044
3073
|
border-radius: 0;
|
|
3045
3074
|
}
|
|
3046
3075
|
|
|
3076
|
+
@media not all and (min-width: 560px) {
|
|
3077
|
+
.cw-root .max-\[560px\]\:hidden {
|
|
3078
|
+
display: none;
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3047
3082
|
@media (min-width: 40rem) {
|
|
3048
3083
|
.cw-root .sm\:inline {
|
|
3049
3084
|
display: inline;
|
|
@@ -3119,6 +3154,12 @@
|
|
|
3119
3154
|
}
|
|
3120
3155
|
}
|
|
3121
3156
|
|
|
3157
|
+
@container (min-width: 720px) {
|
|
3158
|
+
.cw-root .\@\[720px\]\:flex {
|
|
3159
|
+
display: flex;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3122
3163
|
.dark\:border-input:where([data-cw-theme="dark"], .cw-root[data-cw-theme="dark"] *) {
|
|
3123
3164
|
border-color: var(--cw-input);
|
|
3124
3165
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lab feature 的公开 API
|
|
2
|
+
* Lab feature 的公开 API(内部模块,不对宿主暴露)。
|
|
3
|
+
*
|
|
4
|
+
* 对外入口是 `@cut-workbench/workbench/lab`(见 src/lab.ts);这里只做转发,
|
|
5
|
+
* 避免 `CutWorkbench` 直接触达 `components/LabPage`(那样会把 lab 及其
|
|
6
|
+
* `@webav/av-recorder` 拉回主包的模块图)。
|
|
3
7
|
*/
|
|
4
8
|
export { LabPage } from './components/LabPage';
|
|
@@ -8,6 +8,12 @@ interface DropZoneProps {
|
|
|
8
8
|
/**
|
|
9
9
|
* 拖拽 / 点击导入区域。
|
|
10
10
|
*
|
|
11
|
+
* 两条入口:
|
|
12
|
+
* - **拖拽**:走 react-dropzone(宿主无法介入,这是浏览器原生行为);
|
|
13
|
+
* - **点击**:优先走 `HostBridge.files.pickFiles` —— 宿主可能不用系统文件
|
|
14
|
+
* 对话框,而是从自己的素材库 / 云端 / URL 导入。宿主返回 `null`(不接管)
|
|
15
|
+
* 时才回退到内置 `<input type=file>`。
|
|
16
|
+
*
|
|
11
17
|
* 注意:react-dropzone 的 accept 只做初筛,真正按 MIME + 扩展名校验在
|
|
12
18
|
* core/media/file-reader,从而保证「拖入 .webm 得到明确错误」而不是被静默拒绝。
|
|
13
19
|
*/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 选择素材文件:宿主优先,回退到浏览器的 `<input type=file>`。
|
|
3
|
+
*
|
|
4
|
+
* 为什么不能只用 react-dropzone 的 input:
|
|
5
|
+
* 素材来源不一定在本地文件系统 —— 宿主可能从自己的素材库、云端、录制器或
|
|
6
|
+
* URL 导入。`HostBridge.files.pickFiles` 就是给这类宿主用的口子。
|
|
7
|
+
*
|
|
8
|
+
* 三种结果必须区分清楚:
|
|
9
|
+
* - `File[]`:宿主或浏览器选到了文件;
|
|
10
|
+
* - `[]`:用户主动取消 —— **不要**再回退,否则会连弹两个选择框;
|
|
11
|
+
* - `null`:宿主不接管 —— 回退到内置 input。
|
|
12
|
+
*/
|
|
13
|
+
import type { HostBridge } from '@cut-workbench/core';
|
|
14
|
+
export interface PickMediaOptions {
|
|
15
|
+
/** MIME 或扩展名,形如 `video/mp4`、`.srt` */
|
|
16
|
+
accept: string[];
|
|
17
|
+
multiple?: boolean;
|
|
18
|
+
/** 给宿主 UI 用的提示文案 */
|
|
19
|
+
description?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @returns 选中的文件;用户取消时为空数组
|
|
23
|
+
*/
|
|
24
|
+
export declare function pickMediaFiles(bridge: HostBridge | null | undefined, options: PickMediaOptions): Promise<File[]>;
|
|
@@ -12,10 +12,18 @@ export interface EditorActions {
|
|
|
12
12
|
jumpToStart: () => void;
|
|
13
13
|
jumpToEnd: () => void;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* 把异常转成可见提示,禁止静默吞掉。
|
|
17
|
+
*
|
|
18
|
+
* 这是**非 hook** 版本,供事件回调 / 非组件代码调用(例如 `useAvCanvas` 的
|
|
19
|
+
* 初始化失败)。它拿不到 React context,因此走 `notify` 注册的默认桥:
|
|
20
|
+
* `WorkbenchProvider` 挂载时会把 `bridge` 注册进来,宿主实现了 `notify`
|
|
21
|
+
* 就交给宿主,否则退回库内 toast。
|
|
22
|
+
*/
|
|
16
23
|
export declare function reportError(error: unknown, fallback?: string): void;
|
|
17
24
|
export declare function useToastSafe(): {
|
|
18
25
|
success: (message: string, description?: string) => void;
|
|
19
26
|
error: (message: string, description?: string) => void;
|
|
20
27
|
info: (message: string, description?: string) => void;
|
|
28
|
+
warning: (message: string, description?: string) => void;
|
|
21
29
|
};
|