@lokvis/ui-react 0.2.1 → 0.2.2

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.
Files changed (97) hide show
  1. package/dist/components/AssetPanel.d.ts.map +1 -1
  2. package/dist/components/AssetPanel.js +14 -14
  3. package/dist/components/AssetPanel.js.map +1 -1
  4. package/dist/components/Canvas.d.ts +4 -4
  5. package/dist/components/Canvas.d.ts.map +1 -1
  6. package/dist/components/Canvas.js +8 -8
  7. package/dist/components/Canvas.js.map +1 -1
  8. package/dist/components/CommandPalette.d.ts +7 -7
  9. package/dist/components/CommandPalette.d.ts.map +1 -1
  10. package/dist/components/CommandPalette.js +10 -10
  11. package/dist/components/CommandPalette.js.map +1 -1
  12. package/dist/components/CompareSlider.d.ts +6 -6
  13. package/dist/components/CompareSlider.d.ts.map +1 -1
  14. package/dist/components/CompareSlider.js +7 -7
  15. package/dist/components/CompareSlider.js.map +1 -1
  16. package/dist/components/DownloadPanel.d.ts +3 -3
  17. package/dist/components/DownloadPanel.d.ts.map +1 -1
  18. package/dist/components/DownloadPanel.js +9 -9
  19. package/dist/components/DownloadPanel.js.map +1 -1
  20. package/dist/components/ErrorBanner.d.ts +2 -2
  21. package/dist/components/ErrorBanner.d.ts.map +1 -1
  22. package/dist/components/ErrorBanner.js +3 -3
  23. package/dist/components/ErrorBanner.js.map +1 -1
  24. package/dist/components/ExifPanel.d.ts +1 -1
  25. package/dist/components/ExifPanel.d.ts.map +1 -1
  26. package/dist/components/ExifPanel.js +2 -2
  27. package/dist/components/ExifPanel.js.map +1 -1
  28. package/dist/components/GlobalDropzone.d.ts +5 -5
  29. package/dist/components/GlobalDropzone.d.ts.map +1 -1
  30. package/dist/components/GlobalDropzone.js +6 -6
  31. package/dist/components/GlobalDropzone.js.map +1 -1
  32. package/dist/components/HistoryPanel.d.ts +2 -2
  33. package/dist/components/HistoryPanel.d.ts.map +1 -1
  34. package/dist/components/HistoryPanel.js +23 -23
  35. package/dist/components/HistoryPanel.js.map +1 -1
  36. package/dist/components/Inspector.d.ts.map +1 -1
  37. package/dist/components/Inspector.js +6 -6
  38. package/dist/components/Inspector.js.map +1 -1
  39. package/dist/components/ParamForm.d.ts.map +1 -1
  40. package/dist/components/ParamForm.js +7 -7
  41. package/dist/components/ParamForm.js.map +1 -1
  42. package/dist/components/PipelineBar.d.ts.map +1 -1
  43. package/dist/components/PipelineBar.js +13 -13
  44. package/dist/components/PipelineBar.js.map +1 -1
  45. package/dist/components/ProgressBar.d.ts +4 -4
  46. package/dist/components/ProgressBar.d.ts.map +1 -1
  47. package/dist/components/ProgressBar.js +8 -8
  48. package/dist/components/ProgressBar.js.map +1 -1
  49. package/dist/components/StatusBar.d.ts +3 -3
  50. package/dist/components/StatusBar.d.ts.map +1 -1
  51. package/dist/components/StatusBar.js +11 -11
  52. package/dist/components/StatusBar.js.map +1 -1
  53. package/dist/components/ThemeToggle.d.ts +4 -4
  54. package/dist/components/ThemeToggle.d.ts.map +1 -1
  55. package/dist/components/ThemeToggle.js +7 -7
  56. package/dist/components/ThemeToggle.js.map +1 -1
  57. package/dist/components/Toolbar.d.ts.map +1 -1
  58. package/dist/components/Toolbar.js +2 -2
  59. package/dist/components/Toolbar.js.map +1 -1
  60. package/dist/components/WorkflowEditor.d.ts +6 -6
  61. package/dist/components/WorkflowEditor.d.ts.map +1 -1
  62. package/dist/components/WorkflowEditor.js +25 -25
  63. package/dist/components/WorkflowEditor.js.map +1 -1
  64. package/dist/components/WorkflowTemplates.d.ts +2 -2
  65. package/dist/components/WorkflowTemplates.d.ts.map +1 -1
  66. package/dist/components/WorkflowTemplates.js +3 -3
  67. package/dist/components/WorkflowTemplates.js.map +1 -1
  68. package/dist/components/Workspace.d.ts +22 -22
  69. package/dist/components/Workspace.d.ts.map +1 -1
  70. package/dist/components/Workspace.js +30 -30
  71. package/dist/components/Workspace.js.map +1 -1
  72. package/dist/index.d.ts +1 -0
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +3 -0
  75. package/dist/index.js.map +1 -1
  76. package/package.json +6 -6
  77. package/src/components/AssetPanel.tsx +263 -263
  78. package/src/components/Canvas.tsx +174 -174
  79. package/src/components/CommandPalette.tsx +242 -242
  80. package/src/components/CompareSlider.tsx +163 -163
  81. package/src/components/DownloadPanel.tsx +203 -203
  82. package/src/components/ErrorBanner.tsx +64 -64
  83. package/src/components/ExifPanel.tsx +154 -154
  84. package/src/components/GlobalDropzone.tsx +170 -170
  85. package/src/components/HistoryPanel.tsx +219 -219
  86. package/src/components/Inspector.tsx +136 -136
  87. package/src/components/ParamForm.tsx +136 -136
  88. package/src/components/PipelineBar.tsx +98 -98
  89. package/src/components/ProgressBar.tsx +78 -78
  90. package/src/components/StatusBar.tsx +148 -148
  91. package/src/components/ThemeToggle.tsx +98 -98
  92. package/src/components/Toolbar.tsx +65 -65
  93. package/src/components/WorkflowEditor.tsx +321 -321
  94. package/src/components/WorkflowTemplates.tsx +77 -77
  95. package/src/components/Workspace.tsx +223 -223
  96. package/src/css-modules.d.ts +3 -0
  97. package/src/index.ts +4 -0
@@ -2,30 +2,30 @@
2
2
  * Workspace - 完整工作台组件
3
3
  *
4
4
  * W9 布局:
5
- * ┌──────────────────────────────────────────────┐
6
- * │ Toolbar
7
- * ├──────┬──────────────┬───────────────────────┤
8
- * │Asset │ Canvas Inspector
9
- * │Panel │ (center) (right)
10
- * ├──────┴──────────────┴───────────────────────┤
11
- * │ PipelineBar
12
- * ├──────────────────────────────────────────────┤
13
- * │ HistoryPanel (horizontal, W9.1)
14
- * ├──────────────────────────────────────────────┤
15
- * │ DownloadPanel (W9.5,条件渲染)
16
- * ├──────────────────────────────────────────────┤
17
- * │ StatusBar
18
- * └──────────────────────────────────────────────┘
5
+ * ┌──────────────────────────────────────────────┐
6
+ * │ Toolbar
7
+ * ├──────┬──────────────┬───────────────────────┤
8
+ * │Asset │ Canvas Inspector
9
+ * │Panel │ (center) (right)
10
+ * ├──────┴──────────────┴───────────────────────┤
11
+ * │ PipelineBar
12
+ * ├──────────────────────────────────────────────┤
13
+ * │ HistoryPanel (horizontal, W9.1)
14
+ * ├──────────────────────────────────────────────┤
15
+ * │ DownloadPanel (W9.5,条件渲染)
16
+ * ├──────────────────────────────────────────────┤
17
+ * │ StatusBar
18
+ * └──────────────────────────────────────────────┘
19
19
  *
20
20
  * W9 集成:
21
- * - 9.1 HistoryPanel 移到底部(horizontal variant)
22
- * - 9.2 CommandPalette(⌘K)挂载在 Workspace 内
23
- * - 9.3 GlobalDropzone 全屏拖拽 + MIME 校验
24
- * - 9.4 Canvas 内置 CompareSlider(before/after)
25
- * - 9.5 DownloadPanel 在 HistoryPanel 下方,有 outputs 时显示
26
- * - 9.6 StatusBar 已增强(当前工具/进度/在线)
27
- * - 9.7 ThemeToggle 通过 Toolbar rightExtra 挂载
28
- * - 9.8 响应式:移动端折叠为 drawer 模式
21
+ * - 9.1 HistoryPanel 移到底部(horizontal variant)
22
+ * - 9.2 CommandPalette(⌘K)挂载在 Workspace 内
23
+ * - 9.3 GlobalDropzone 全屏拖拽 + MIME 校验
24
+ * - 9.4 Canvas 内置 CompareSlider(before/after)
25
+ * - 9.5 DownloadPanel 在 HistoryPanel 下方,有 outputs 时显示
26
+ * - 9.6 StatusBar 已增强(当前工具/进度/在线)
27
+ * - 9.7 ThemeToggle 通过 Toolbar rightExtra 挂载
28
+ * - 9.8 响应式:移动端折叠为 drawer 模式
29
29
  *
30
30
  * 通过 useLokvis 自动初始化 Runtime 与插件。
31
31
  *
@@ -60,229 +60,229 @@ import { useShareLink } from '../hooks/useShareLink.js';
60
60
  import { useWorkspaceStore } from '../store/index.js';
61
61
 
62
62
  export interface WorkspaceProps extends UseLokvisOptions {
63
- /** 顶部标题 */
64
- title?: string;
65
- /** 是否显示状态栏(默认 true) */
66
- showStatusBar?: boolean;
67
- /** 是否显示历史面板(默认 true,W7.1) */
68
- showHistoryPanel?: boolean;
69
- /** 是否启用全屏拖拽导入(默认 true,W9.3) */
70
- enableGlobalDropzone?: boolean;
71
- /** 是否启用 Command Palette ⌘K(默认 true,W9.2) */
72
- enableCommandPalette?: boolean;
73
- /** 是否启用 ThemeToggle(默认 true,W9.7) */
74
- enableThemeToggle?: boolean;
75
- /** 是否启用 CompareSlider(默认 true,W9.4) */
76
- enableCompare?: boolean;
77
- /** 是否启用 DownloadPanel(默认 true,W9.5) */
78
- enableDownloadPanel?: boolean;
79
- /** 是否启用拖拽式 WorkflowEditor(默认 false,W10.4;关闭则用只读 PipelineBar) */
80
- enableWorkflowEditor?: boolean;
81
- /** 是否启用 ProgressBar + Cancel 按钮(默认 true,W11.6) */
82
- enableProgressBar?: boolean;
83
- /** 是否启用 ErrorBanner 错误信息横幅(默认 true,W11.3) */
84
- enableErrorBanner?: boolean;
85
- /** 是否从 URL ?workflow= 参数加载分享工作流(默认 true,W11.5) */
86
- enableShareLink?: boolean;
87
- className?: string;
63
+ /** 顶部标题 */
64
+ title?: string;
65
+ /** 是否显示状态栏(默认 true) */
66
+ showStatusBar?: boolean;
67
+ /** 是否显示历史面板(默认 true,W7.1) */
68
+ showHistoryPanel?: boolean;
69
+ /** 是否启用全屏拖拽导入(默认 true,W9.3) */
70
+ enableGlobalDropzone?: boolean;
71
+ /** 是否启用 Command Palette ⌘K(默认 true,W9.2) */
72
+ enableCommandPalette?: boolean;
73
+ /** 是否启用 ThemeToggle(默认 true,W9.7) */
74
+ enableThemeToggle?: boolean;
75
+ /** 是否启用 CompareSlider(默认 true,W9.4) */
76
+ enableCompare?: boolean;
77
+ /** 是否启用 DownloadPanel(默认 true,W9.5) */
78
+ enableDownloadPanel?: boolean;
79
+ /** 是否启用拖拽式 WorkflowEditor(默认 false,W10.4;关闭则用只读 PipelineBar) */
80
+ enableWorkflowEditor?: boolean;
81
+ /** 是否启用 ProgressBar + Cancel 按钮(默认 true,W11.6) */
82
+ enableProgressBar?: boolean;
83
+ /** 是否启用 ErrorBanner 错误信息横幅(默认 true,W11.3) */
84
+ enableErrorBanner?: boolean;
85
+ /** 是否从 URL ?workflow= 参数加载分享工作流(默认 true,W11.5) */
86
+ enableShareLink?: boolean;
87
+ className?: string;
88
88
  }
89
89
 
90
90
  /** W9.8 移动端抽屉切换状态 */
91
91
  type MobilePanel = 'asset' | 'inspector' | null;
92
92
 
93
93
  export function Workspace({
94
- title,
95
- showStatusBar = true,
96
- showHistoryPanel = true,
97
- enableGlobalDropzone = true,
98
- enableCommandPalette = true,
99
- enableThemeToggle = true,
100
- enableCompare = true,
101
- enableDownloadPanel = true,
102
- enableWorkflowEditor = false,
103
- enableProgressBar = true,
104
- enableErrorBanner = true,
105
- enableShareLink = true,
106
- className = '',
107
- ...lokvisOptions
94
+ title,
95
+ showStatusBar = true,
96
+ showHistoryPanel = true,
97
+ enableGlobalDropzone = true,
98
+ enableCommandPalette = true,
99
+ enableThemeToggle = true,
100
+ enableCompare = true,
101
+ enableDownloadPanel = true,
102
+ enableWorkflowEditor = false,
103
+ enableProgressBar = true,
104
+ enableErrorBanner = true,
105
+ enableShareLink = true,
106
+ className = '',
107
+ ...lokvisOptions
108
108
  }: WorkspaceProps) {
109
- const { status, error } = useLokvis(lokvisOptions);
110
- const { isMobile } = useBreakpoints();
111
- const [paletteOpen, setPaletteOpen] = useCommandPalette({ enabled: enableCommandPalette });
112
- // W9.8 移动端抽屉:Asset / Inspector 切换显示
113
- const [mobilePanel, setMobilePanel] = React.useState<MobilePanel>(null);
109
+ const { status, error } = useLokvis(lokvisOptions);
110
+ const { isMobile } = useBreakpoints();
111
+ const [paletteOpen, setPaletteOpen] = useCommandPalette({ enabled: enableCommandPalette });
112
+ // W9.8 移动端抽屉:Asset / Inspector 切换显示
113
+ const [mobilePanel, setMobilePanel] = React.useState<MobilePanel>(null);
114
114
 
115
- // W11.5: 从 URL ?workflow= 参数加载分享工作流(runtime 就绪后执行一次)
116
- // 保护:若用户已通过其它路径(如 localStorage 恢复或手动添加)有 nodes,
117
- // 不静默替换 —— 用 confirm 让用户显式选择,避免丢失未保存工作。
118
- // 注:不用 useWorkspaceStore 订阅 nodes.length 做 effect 依赖
119
- // (review 反馈:那样 nodesLength 变化会触发 effect 重跑,而 ref 已 true
120
- // 时重跑无意义,且语义上 effect 只应在 status 切换时跑一次)。
121
- // 改用 getState() 在体内读取最新值,既不订阅也不进 deps。
122
- const { loadFromCurrentUrl } = useShareLink();
123
- const shareLoadedRef = React.useRef(false);
124
- React.useEffect(() => {
125
- if (enableShareLink && !shareLoadedRef.current && status !== 'initializing' && status !== 'error') {
126
- shareLoadedRef.current = true;
127
- // 仅在 URL 含 ?workflow= 参数时才提示(避免无谓 confirm 弹窗)
128
- const hasShareParam = typeof window !== 'undefined'
129
- && new URLSearchParams(window.location.search).has('workflow');
130
- if (!hasShareParam) return;
131
- // 读取当前 nodes 长度(最新值,非订阅快照)
132
- const currentNodesLength = useWorkspaceStore.getState().nodes.length;
133
- if (currentNodesLength > 0) {
134
- const ok = window.confirm(
135
- `检测到分享工作流链接,但当前已有 ${currentNodesLength} 个节点。是否替换为分享的工作流?`
136
- );
137
- if (!ok) return;
138
- }
139
- loadFromCurrentUrl();
140
- }
141
- }, [enableShareLink, status, loadFromCurrentUrl]);
115
+ // W11.5: 从 URL ?workflow= 参数加载分享工作流(runtime 就绪后执行一次)
116
+ // 保护:若用户已通过其它路径(如 localStorage 恢复或手动添加)有 nodes,
117
+ // 不静默替换 —— 用 confirm 让用户显式选择,避免丢失未保存工作。
118
+ // 注:不用 useWorkspaceStore 订阅 nodes.length 做 effect 依赖
119
+ // (review 反馈:那样 nodesLength 变化会触发 effect 重跑,而 ref 已 true
120
+ // 时重跑无意义,且语义上 effect 只应在 status 切换时跑一次)。
121
+ // 改用 getState() 在体内读取最新值,既不订阅也不进 deps。
122
+ const { loadFromCurrentUrl } = useShareLink();
123
+ const shareLoadedRef = React.useRef(false);
124
+ React.useEffect(() => {
125
+ if (enableShareLink && !shareLoadedRef.current && status !== 'initializing' && status !== 'error') {
126
+ shareLoadedRef.current = true;
127
+ // 仅在 URL 含 ?workflow= 参数时才提示(避免无谓 confirm 弹窗)
128
+ const hasShareParam = typeof window !== 'undefined'
129
+ && new URLSearchParams(window.location.search).has('workflow');
130
+ if (!hasShareParam) return;
131
+ // 读取当前 nodes 长度(最新值,非订阅快照)
132
+ const currentNodesLength = useWorkspaceStore.getState().nodes.length;
133
+ if (currentNodesLength > 0) {
134
+ const ok = window.confirm(
135
+ `检测到分享工作流链接,但当前已有 ${currentNodesLength} 个节点。是否替换为分享的工作流?`
136
+ );
137
+ if (!ok) return;
138
+ }
139
+ loadFromCurrentUrl();
140
+ }
141
+ }, [enableShareLink, status, loadFromCurrentUrl]);
142
142
 
143
- if (status === 'initializing') {
144
- return (
145
- <div className="flex h-full items-center justify-center">
146
- <div className="flex flex-col items-center gap-4">
147
- <div className="relative flex h-12 w-12 items-center justify-center">
148
- <div className="absolute inset-0 rounded-full border-2 border-indigo-200 dark:border-indigo-800" />
149
- <div className="h-8 w-8 animate-spin rounded-full border-2 border-transparent border-t-indigo-500" />
150
- </div>
151
- <div className="text-center">
152
- <p className="text-sm font-medium text-zinc-700 dark:text-zinc-300">Initializing Runtime</p>
153
- <p className="mt-1 text-xs text-zinc-400">Loading plugins and capabilities...</p>
154
- </div>
155
- </div>
156
- </div>
157
- );
158
- }
143
+ if (status === 'initializing') {
144
+ return (
145
+ <div className="flex h-full items-center justify-center">
146
+ <div className="flex flex-col items-center gap-4">
147
+ <div className="relative flex h-12 w-12 items-center justify-center">
148
+ <div className="absolute inset-0 rounded-full border-2 border-[var(--lokvis-primary)]/40" />
149
+ <div className="h-8 w-8 animate-spin rounded-full border-2 border-transparent border-t-indigo-500" />
150
+ </div>
151
+ <div className="text-center">
152
+ <p className="text-sm font-medium text-[var(--lokvis-fg-muted)]">Initializing Runtime</p>
153
+ <p className="mt-1 text-xs text-[var(--lokvis-fg-subtle)]">Loading plugins and capabilities...</p>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ );
158
+ }
159
159
 
160
- if (status === 'error') {
161
- return (
162
- <div className="flex h-full items-center justify-center px-6">
163
- <div className="max-w-md rounded-xl border border-red-200 bg-red-50 p-6 text-center dark:border-red-800/50 dark:bg-red-950/20">
164
- <div className="mb-3 flex h-10 w-10 mx-auto items-center justify-center rounded-full bg-red-100 dark:bg-red-900/40">
165
- <Icon size={20} className="text-red-500"><circle cx="12" cy="12" r="10" /><line x1="12" y1="8" x2="12" y2="12" /><line x1="12" y1="16" x2="12.01" y2="16" /></Icon>
166
- </div>
167
- <p className="font-semibold text-red-700 dark:text-red-400">Failed to initialize</p>
168
- <p className="mt-1.5 text-sm text-red-600/80 dark:text-red-400/70">{error}</p>
169
- </div>
170
- </div>
171
- );
172
- }
160
+ if (status === 'error') {
161
+ return (
162
+ <div className="flex h-full items-center justify-center px-6">
163
+ <div className="max-w-md rounded-xl border border-[var(--lokvis-danger)]/30 bg-[var(--lokvis-danger)]/10 p-6 text-center">
164
+ <div className="mb-3 flex h-10 w-10 mx-auto items-center justify-center rounded-full bg-[var(--lokvis-danger)]/15">
165
+ <Icon size={20} className="text-[var(--lokvis-danger)]"><circle cx="12" cy="12" r="10" /><line x1="12" y1="8" x2="12" y2="12" /><line x1="12" y1="16" x2="12.01" y2="16" /></Icon>
166
+ </div>
167
+ <p className="font-semibold text-[var(--lokvis-danger)]">Failed to initialize</p>
168
+ <p className="mt-1.5 text-sm text-[var(--lokvis-danger)]/80">{error}</p>
169
+ </div>
170
+ </div>
171
+ );
172
+ }
173
173
 
174
- // W9.7 Toolbar rightExtra: ThemeToggle + ⌘K hint
175
- const toolbarRight = (
176
- <>
177
- {enableCommandPalette && (
178
- <button
179
- type="button"
180
- onClick={() => setPaletteOpen(true)}
181
- aria-label="Open command palette"
182
- title="Command palette (⌘K)"
183
- className="flex h-7 items-center gap-1 rounded-md border border-zinc-200 px-1.5 text-[10px] text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-700 dark:border-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200"
184
- >
185
- <Icon size={11}><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></Icon>
186
- <kbd className="font-sans">⌘K</kbd>
187
- </button>
188
- )}
189
- {enableThemeToggle && <ThemeToggle />}
190
- {/* W9.8 移动端面板切换按钮 */}
191
- {isMobile && (
192
- <>
193
- <button
194
- type="button"
195
- onClick={() => setMobilePanel(mobilePanel === 'asset' ? null : 'asset')}
196
- aria-label="Toggle asset panel"
197
- aria-pressed={mobilePanel === 'asset'}
198
- className="flex h-7 w-7 items-center justify-center rounded-md text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200"
199
- >
200
- <Icon size={14}><rect x="3" y="3" width="7" height="18" rx="1" /><path d="M14 3h7v18h-7z" opacity="0.3" /></Icon>
201
- </button>
202
- <button
203
- type="button"
204
- onClick={() => setMobilePanel(mobilePanel === 'inspector' ? null : 'inspector')}
205
- aria-label="Toggle inspector panel"
206
- aria-pressed={mobilePanel === 'inspector'}
207
- className="flex h-7 w-7 items-center justify-center rounded-md text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200"
208
- >
209
- <Icon size={14}><path d="M3 3h7v18H3z" opacity="0.3" /><rect x="14" y="3" width="7" height="18" rx="1" /></Icon>
210
- </button>
211
- </>
212
- )}
213
- </>
214
- );
174
+ // W9.7 Toolbar rightExtra: ThemeToggle + ⌘K hint
175
+ const toolbarRight = (
176
+ <>
177
+ {enableCommandPalette && (
178
+ <button
179
+ type="button"
180
+ onClick={() => setPaletteOpen(true)}
181
+ aria-label="Open command palette"
182
+ title="Command palette (⌘K)"
183
+ className="flex h-7 items-center gap-1 rounded-md border border-[var(--lokvis-border)] px-1.5 text-[10px] text-[var(--lokvis-fg-muted)] transition-colors hover:bg-[var(--lokvis-surface-muted)] hover:text-[var(--lokvis-fg-muted)]"
184
+ >
185
+ <Icon size={11}><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></Icon>
186
+ <kbd className="font-sans">⌘K</kbd>
187
+ </button>
188
+ )}
189
+ {enableThemeToggle && <ThemeToggle />}
190
+ {/* W9.8 移动端面板切换按钮 */}
191
+ {isMobile && (
192
+ <>
193
+ <button
194
+ type="button"
195
+ onClick={() => setMobilePanel(mobilePanel === 'asset' ? null : 'asset')}
196
+ aria-label="Toggle asset panel"
197
+ aria-pressed={mobilePanel === 'asset'}
198
+ className="flex h-7 w-7 items-center justify-center rounded-md text-[var(--lokvis-fg-muted)] hover:bg-[var(--lokvis-surface-muted)] hover:text-[var(--lokvis-fg-muted)]"
199
+ >
200
+ <Icon size={14}><rect x="3" y="3" width="7" height="18" rx="1" /><path d="M14 3h7v18h-7z" opacity="0.3" /></Icon>
201
+ </button>
202
+ <button
203
+ type="button"
204
+ onClick={() => setMobilePanel(mobilePanel === 'inspector' ? null : 'inspector')}
205
+ aria-label="Toggle inspector panel"
206
+ aria-pressed={mobilePanel === 'inspector'}
207
+ className="flex h-7 w-7 items-center justify-center rounded-md text-[var(--lokvis-fg-muted)] hover:bg-[var(--lokvis-surface-muted)] hover:text-[var(--lokvis-fg-muted)]"
208
+ >
209
+ <Icon size={14}><path d="M3 3h7v18H3z" opacity="0.3" /><rect x="14" y="3" width="7" height="18" rx="1" /></Icon>
210
+ </button>
211
+ </>
212
+ )}
213
+ </>
214
+ );
215
215
 
216
- return (
217
- <div className={`flex h-full flex-col bg-white dark:bg-zinc-900 ${className}`}>
218
- {/* Top: Toolbar */}
219
- <Toolbar title={title} rightExtra={toolbarRight} />
216
+ return (
217
+ <div className={`flex h-full flex-col bg-[var(--lokvis-surface)] ${className}`}>
218
+ {/* Top: Toolbar */}
219
+ <Toolbar title={title} rightExtra={toolbarRight} />
220
220
 
221
- {/* W11.3 ErrorBanner (有 error 时显示) */}
222
- {enableErrorBanner && <ErrorBanner />}
221
+ {/* W11.3 ErrorBanner (有 error 时显示) */}
222
+ {enableErrorBanner && <ErrorBanner />}
223
223
 
224
- {/* W9.3 全屏拖拽 */}
225
- {enableGlobalDropzone && <GlobalDropzone />}
224
+ {/* W9.3 全屏拖拽 */}
225
+ {enableGlobalDropzone && <GlobalDropzone />}
226
226
 
227
- {/* W9.2 Command Palette */}
228
- {enableCommandPalette && (
229
- <CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} />
230
- )}
227
+ {/* W9.2 Command Palette */}
228
+ {enableCommandPalette && (
229
+ <CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} />
230
+ )}
231
231
 
232
- {/* Middle: Panel area */}
233
- <div className="flex flex-1 overflow-hidden relative">
234
- {/* W9.8 桌面:三栏并列;移动:Canvas 单独,其他为 overlay drawer */}
235
- <div
236
- className={`${
237
- isMobile
238
- ? `absolute inset-y-0 left-0 z-20 w-64 max-w-[80vw] transition-transform duration-200 ${
239
- mobilePanel === 'asset' ? 'translate-x-0' : '-translate-x-full'
240
- }`
241
- : 'relative'
242
- }`}
243
- >
244
- <AssetPanel className="h-full" />
245
- </div>
232
+ {/* Middle: Panel area */}
233
+ <div className="flex flex-1 overflow-hidden relative">
234
+ {/* W9.8 桌面:三栏并列;移动:Canvas 单独,其他为 overlay drawer */}
235
+ <div
236
+ className={`${
237
+ isMobile
238
+ ? `absolute inset-y-0 left-0 z-20 w-64 max-w-[80vw] transition-transform duration-200 ${
239
+ mobilePanel === 'asset' ? 'translate-x-0' : '-translate-x-full'
240
+ }`
241
+ : 'relative'
242
+ }`}
243
+ >
244
+ <AssetPanel className="h-full" />
245
+ </div>
246
246
 
247
- <Canvas enableCompare={enableCompare} />
247
+ <Canvas enableCompare={enableCompare} />
248
248
 
249
- <div
250
- className={`${
251
- isMobile
252
- ? `absolute inset-y-0 right-0 z-20 w-72 max-w-[80vw] transition-transform duration-200 ${
253
- mobilePanel === 'inspector' ? 'translate-x-0' : 'translate-x-full'
254
- }`
255
- : 'relative'
256
- }`}
257
- >
258
- <Inspector className="h-full" />
259
- </div>
249
+ <div
250
+ className={`${
251
+ isMobile
252
+ ? `absolute inset-y-0 right-0 z-20 w-72 max-w-[80vw] transition-transform duration-200 ${
253
+ mobilePanel === 'inspector' ? 'translate-x-0' : 'translate-x-full'
254
+ }`
255
+ : 'relative'
256
+ }`}
257
+ >
258
+ <Inspector className="h-full" />
259
+ </div>
260
260
 
261
- {/* W9.8 移动端遮罩:点击关闭抽屉 */}
262
- {isMobile && mobilePanel !== null && (
263
- <button
264
- type="button"
265
- aria-label="Close panel"
266
- onClick={() => setMobilePanel(null)}
267
- className="absolute inset-0 z-10 bg-black/30"
268
- />
269
- )}
270
- </div>
261
+ {/* W9.8 移动端遮罩:点击关闭抽屉 */}
262
+ {isMobile && mobilePanel !== null && (
263
+ <button
264
+ type="button"
265
+ aria-label="Close panel"
266
+ onClick={() => setMobilePanel(null)}
267
+ className="absolute inset-0 z-10 bg-[var(--lokvis-overlay)]"
268
+ />
269
+ )}
270
+ </div>
271
271
 
272
- {/* Pipeline bar */}
273
- {enableWorkflowEditor ? <WorkflowEditor /> : <PipelineBar />}
272
+ {/* Pipeline bar */}
273
+ {enableWorkflowEditor ? <WorkflowEditor /> : <PipelineBar />}
274
274
 
275
- {/* W11.6 ProgressBar + Cancel */}
276
- {enableProgressBar && <ProgressBar />}
275
+ {/* W11.6 ProgressBar + Cancel */}
276
+ {enableProgressBar && <ProgressBar />}
277
277
 
278
- {/* W9.1 History panel (horizontal at bottom) */}
279
- {showHistoryPanel && <HistoryPanel variant="horizontal" />}
278
+ {/* W9.1 History panel (horizontal at bottom) */}
279
+ {showHistoryPanel && <HistoryPanel variant="horizontal" />}
280
280
 
281
- {/* W9.5 Download panel (条件渲染:有 outputs 时显示) */}
282
- {enableDownloadPanel && <DownloadPanel />}
281
+ {/* W9.5 Download panel (条件渲染:有 outputs 时显示) */}
282
+ {enableDownloadPanel && <DownloadPanel />}
283
283
 
284
- {/* Bottom: StatusBar */}
285
- {showStatusBar && <StatusBar />}
286
- </div>
287
- );
284
+ {/* Bottom: StatusBar */}
285
+ {showStatusBar && <StatusBar />}
286
+ </div>
287
+ );
288
288
  }
@@ -0,0 +1,3 @@
1
+ /** 允许在 TypeScript 中 import CSS 文件(side-effect import) */
2
+ declare module '*.css';
3
+ declare module '@lokvis/ui-core/styles.css';
package/src/index.ts CHANGED
@@ -23,6 +23,10 @@
23
23
  * - `useCommandPalette()` - ⌘K shortcut registration hook (W9.2)
24
24
  */
25
25
 
26
+ // 引入设计 token(--lokvis-* CSS 变量),消费方无需手动 import styles.css。
27
+ // sideEffects: ["**/*.css"] 保证 bundler 不 tree-shake 此 import。
28
+ import '@lokvis/ui-core/styles.css';
29
+
26
30
  export { useLokvis, type UseLokvisOptions, type UseLokvisResult } from './hooks/useLokvis.js';
27
31
  export { useTheme, type UseThemeResult, type ThemeMode } from './hooks/useTheme.js';
28
32
  export { useMediaQuery, useBreakpoints, type Breakpoints } from './hooks/useMediaQuery.js';