dsh-plugin-core 0.35.19 → 0.35.20
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 +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/ui/display/CodeViewer.d.ts +2 -1
- package/dist/ui/display/CodeViewer.d.ts.map +1 -1
- package/dist/ui/display/CodeViewer.js +20 -71
- package/dist/ui/display/CodeViewer.js.map +1 -1
- package/dist/ui/display/code-viewer.d.ts +9 -0
- package/dist/ui/display/code-viewer.d.ts.map +1 -0
- package/dist/ui/display/code-viewer.js +9 -0
- package/dist/ui/display/code-viewer.js.map +1 -0
- package/dist/ui/infra/code-mirror-surface.d.ts +29 -0
- package/dist/ui/infra/code-mirror-surface.d.ts.map +1 -0
- package/dist/ui/infra/code-mirror-surface.js +83 -0
- package/dist/ui/infra/code-mirror-surface.js.map +1 -0
- package/dist/ui/inputs/CodeEditor.d.ts +30 -0
- package/dist/ui/inputs/CodeEditor.d.ts.map +1 -0
- package/dist/ui/inputs/CodeEditor.js +25 -0
- package/dist/ui/inputs/CodeEditor.js.map +1 -0
- package/docs/design/structure.md +9 -6
- package/docs/help/ui.doc.ts +36 -1
- package/docs/help/ui.md +28 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ Three things worth knowing on day one:
|
|
|
81
81
|
| `dsh-plugin-core/design` | Token variables (light + dark), `createStyleKit` injector factory, dark-mode predicate | no |
|
|
82
82
|
| `dsh-plugin-core/ui` | The whole control set — actions, inputs, display, feedback, layout, navigation | yes |
|
|
83
83
|
| `dsh-plugin-core/ui/official` | Direct re-exports of the host's official primitives, for the rare case you need one | yes |
|
|
84
|
-
| `dsh-plugin-core/ui/code-viewer` |
|
|
84
|
+
| `dsh-plugin-core/ui/code-viewer` | Read-only `CodeViewer` + editable `CodeEditor`, sharing one CodeMirror surface (file preview uses the viewer) | yes |
|
|
85
85
|
| `dsh-plugin-core/ui/host-toast` | Bridge to the host's own toast | yes |
|
|
86
86
|
| `dsh-plugin-core/utils` | Pure helpers: date, string, bytes, HTTP, built-in zh/en dictionary | no |
|
|
87
87
|
| `dsh-plugin-core/adv/explorer` | File browser, file picker, docked file preview | yes |
|
|
@@ -123,6 +123,7 @@ Everything is built from tokens, takes its data through props, and follows the h
|
|
|
123
123
|
- `ModelPicker` — a domain picker for the host model catalog, wired on both sides: in the host `apply` register `serveModelCatalog(ctx, { path })` from `dsh-plugin-core/host`, then in the client `apply` call `connectHost(ctx, { modelsPath: path })` with the **same** path constant; `refreshModelCatalog()` re-pulls the catalog when providers or models change. Unwired pickers show an empty state rather than inventing entries.
|
|
124
124
|
- `DateTimePicker` — one control for a single instant or a range, precision `day` / `hour` / `minute` / `second`, two independent calendars, keyboard support, start floored and end ceiled.
|
|
125
125
|
- `InputGroup` — input with attached actions.
|
|
126
|
+
- `CodeEditor` — a controlled CodeMirror editor imported from `dsh-plugin-core/ui/code-viewer`: pass `value` + `onChange`, and optionally `path` to pick a language (omitted = plain text). It stays off the main `ui` entry so its heavy dependency remains optional; `CodeViewer` from the same subpath is the read-only counterpart.
|
|
126
127
|
|
|
127
128
|
#### Display
|
|
128
129
|
|
package/README.zh-CN.md
CHANGED
|
@@ -81,7 +81,7 @@ export function TaskEditor(props: { name: string; setName: (v: string) => void }
|
|
|
81
81
|
| `dsh-plugin-core/design` | token 变量(明 + 暗)、`createStyleKit` 注入器工厂、明暗判据 | 否 |
|
|
82
82
|
| `dsh-plugin-core/ui` | 全套控件:动作、录入、展示、反馈、布局、导航 | 是 |
|
|
83
83
|
| `dsh-plugin-core/ui/official` | 官方 primitives 的直接再导出(少数确实要用官方原件的场景) | 是 |
|
|
84
|
-
| `dsh-plugin-core/ui/code-viewer` |
|
|
84
|
+
| `dsh-plugin-core/ui/code-viewer` | 只读 `CodeViewer` + 可编辑 `CodeEditor`,共用一份 CodeMirror 底座(文件预览源码态用查看器) | 是 |
|
|
85
85
|
| `dsh-plugin-core/ui/host` | 宿主自带 toast 的桥接 | 是 |
|
|
86
86
|
| `dsh-plugin-core/utils` | 纯方法:日期、字符串、字节、HTTP,外加内置中英字典 | 否 |
|
|
87
87
|
| `dsh-plugin-core/explorer` | 文件浏览、文件选择、右侧停靠的文件预览 | 是 |
|
|
@@ -123,6 +123,7 @@ export function TaskEditor(props: { name: string; setName: (v: string) => void }
|
|
|
123
123
|
- `ModelPicker`——选择模型的领域选择器,两段式接线:宿主 `apply` 调 `dsh-plugin-core/host` 的 `serveModelCatalog(ctx, { path })`,client `apply` 用**同一个 path 常量**调 `connectHost(ctx, { modelsPath: path })`;供应商 / 模型有增减时调 `refreshModelCatalog()` 重拉。没接线就是空态,不编造。
|
|
124
124
|
- `DateTimePicker`——一个控件覆盖「一个时刻」与「时间段」,精度 `day` / `hour` / `minute` / `second`,左右两块独立月历,键盘可用,起始端归零、结束端拉满。
|
|
125
125
|
- `InputGroup`——带附着动作的输入框。
|
|
126
|
+
- `CodeEditor`——从 `dsh-plugin-core/ui/code-viewer` 引的受控 CodeMirror 编辑控件:给 `value` + `onChange` 即可,传 `path` 按扩展名高亮,不传即纯文本。重依赖只挂这条子路径、不进 `ui` 主入口;同子路径的 `CodeViewer` 是只读那一半。
|
|
126
127
|
|
|
127
128
|
#### 展示
|
|
128
129
|
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* 移植自兄弟项目 dsh-task-dispatch-table(src/client/ui/CodeViewer.tsx),按本仓约定重写:
|
|
9
9
|
* 类名 dshpc-cv*、颜色吃 --dshpc-* token、官方图标 / writeClipboard 经 ui/official.ts 单一入口。
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* 只读但可选中:底座用 <CodeMirror readOnly>(= EditorState.readOnly,挡住一切输入),
|
|
12
12
|
* 不设置 editable=false —— 后者会把内容设为不可编辑并连带禁用鼠标选区,导致无法框选复制。
|
|
13
|
+
* 需要可编辑请用同一子路径导出的 CodeEditor。
|
|
13
14
|
*
|
|
14
15
|
* 明暗判据(唯一):body[data-ds-dark-theme](见 design/style-kit.ts DARK_THEME_SELECTOR),
|
|
15
16
|
* 禁用 prefers-color-scheme。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeViewer.d.ts","sourceRoot":"","sources":["../../../src/ui/display/CodeViewer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CodeViewer.d.ts","sourceRoot":"","sources":["../../../src/ui/display/CodeViewer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAgC,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAG3F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAKpD,MAAM,WAAW,eAAe;IAC9B,YAAY;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,4CAA4C;IAC5C,CAAC,EAAE,SAAS,CAAA;IACZ,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uBAAuB;IACvB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAiC/D"}
|
|
@@ -8,56 +8,24 @@
|
|
|
8
8
|
* 移植自兄弟项目 dsh-task-dispatch-table(src/client/ui/CodeViewer.tsx),按本仓约定重写:
|
|
9
9
|
* 类名 dshpc-cv*、颜色吃 --dshpc-* token、官方图标 / writeClipboard 经 ui/official.ts 单一入口。
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* 只读但可选中:底座用 <CodeMirror readOnly>(= EditorState.readOnly,挡住一切输入),
|
|
12
12
|
* 不设置 editable=false —— 后者会把内容设为不可编辑并连带禁用鼠标选区,导致无法框选复制。
|
|
13
|
+
* 需要可编辑请用同一子路径导出的 CodeEditor。
|
|
13
14
|
*
|
|
14
15
|
* 明暗判据(唯一):body[data-ds-dark-theme](见 design/style-kit.ts DARK_THEME_SELECTOR),
|
|
15
16
|
* 禁用 prefers-color-scheme。
|
|
16
17
|
*/
|
|
17
|
-
import { createElement as h,
|
|
18
|
-
import CodeMirror from '@uiw/react-codemirror';
|
|
19
|
-
import { EditorView } from '@codemirror/view';
|
|
18
|
+
import { createElement as h, useState } from 'react';
|
|
20
19
|
import { IconButton } from '../actions/Button.js';
|
|
21
20
|
import { IconCheckOutlineRegular, IconCopyOutlineRegular, writeClipboard } from '../official.js';
|
|
22
|
-
import { languageForPath } from './code-viewer-lang.js';
|
|
23
|
-
import { codeMirrorTheme } from './code-viewer-theme.js';
|
|
24
21
|
import { ensureComponentStyles } from '../infra/css.js';
|
|
25
22
|
import { CODE_VIEWER_CSS } from './code-viewer-css.js';
|
|
26
|
-
|
|
27
|
-
const DARK_ATTR = 'data-ds-dark-theme';
|
|
28
|
-
function hostDark() {
|
|
29
|
-
if (typeof document === 'undefined')
|
|
30
|
-
return false;
|
|
31
|
-
const body = document.body;
|
|
32
|
-
return body === null ? false : body.hasAttribute(DARK_ATTR);
|
|
33
|
-
}
|
|
23
|
+
import { CodeMirrorSurface } from '../infra/code-mirror-surface.js';
|
|
34
24
|
export function CodeViewer(props) {
|
|
25
|
+
// 复制钮用 .dshpc-cv__copy:谁用 dshpc 类名谁注入(与底座同一个域,幂等)。
|
|
35
26
|
ensureComponentStyles('code-viewer', CODE_VIEWER_CSS);
|
|
36
27
|
const { text, path, t, className, style, height = '100%', lineNumbers = true } = props;
|
|
37
28
|
const [copied, setCopied] = useState(false);
|
|
38
|
-
const [dark, setDark] = useState(hostDark);
|
|
39
|
-
/** 编辑器实例(定位到行要 dispatch scrollIntoView)。 */
|
|
40
|
-
const viewRef = useRef(null);
|
|
41
|
-
// 用户切主题 = 宿主 toggleAttribute 写 body[data-ds-dark-theme] ⇒ 用 MutationObserver 跟。
|
|
42
|
-
// 挂载时先 sync 一次:插件挂载可能早于宿主写好该属性。
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
if (typeof document === 'undefined' || typeof MutationObserver !== 'function')
|
|
45
|
-
return;
|
|
46
|
-
const body = document.body;
|
|
47
|
-
if (body === null)
|
|
48
|
-
return;
|
|
49
|
-
const sync = () => { setDark(body.hasAttribute(DARK_ATTR)); };
|
|
50
|
-
sync();
|
|
51
|
-
const observer = new MutationObserver(sync);
|
|
52
|
-
observer.observe(body, { attributeFilter: [DARK_ATTR] });
|
|
53
|
-
return () => { observer.disconnect(); };
|
|
54
|
-
}, []);
|
|
55
|
-
const language = useMemo(() => languageForPath(path), [path]);
|
|
56
|
-
const extensions = useMemo(() => [
|
|
57
|
-
...codeMirrorTheme(dark),
|
|
58
|
-
EditorView.lineWrapping, // 默认全换行,避免横向滚动条
|
|
59
|
-
...(language !== null ? [language] : []),
|
|
60
|
-
], [dark, language]);
|
|
61
29
|
const copy = () => {
|
|
62
30
|
void writeClipboard(text).then((ok) => {
|
|
63
31
|
if (ok) {
|
|
@@ -66,42 +34,23 @@ export function CodeViewer(props) {
|
|
|
66
34
|
}
|
|
67
35
|
});
|
|
68
36
|
};
|
|
69
|
-
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
const view = viewRef.current;
|
|
72
|
-
if (view === null || props.focusLine === undefined)
|
|
73
|
-
return;
|
|
74
|
-
if (props.focusLine > view.state.doc.lines)
|
|
75
|
-
return;
|
|
76
|
-
view.dispatch({ effects: EditorView.scrollIntoView(view.state.doc.line(props.focusLine).from, { y: 'center' }) });
|
|
77
|
-
}, [text, props.focusLine]);
|
|
78
|
-
return h('div', { className: `dshpc-cv${className ? ` ${className}` : ''}`, style }, h(IconButton, {
|
|
79
|
-
variant: 'outline',
|
|
80
|
-
size: 'md',
|
|
81
|
-
icon: copied ? h(IconCheckOutlineRegular) : h(IconCopyOutlineRegular),
|
|
82
|
-
label: copied ? t('codeCopied') : t('codeCopy'),
|
|
83
|
-
className: 'dshpc-cv__copy',
|
|
84
|
-
onClick: copy,
|
|
85
|
-
}), h(CodeMirror, {
|
|
37
|
+
return h(CodeMirrorSurface, {
|
|
86
38
|
value: text,
|
|
87
|
-
|
|
88
|
-
theme: 'none',
|
|
89
|
-
extensions,
|
|
39
|
+
path,
|
|
90
40
|
readOnly: true,
|
|
91
41
|
height,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}));
|
|
42
|
+
lineNumbers,
|
|
43
|
+
className,
|
|
44
|
+
style,
|
|
45
|
+
focusLine: props.focusLine,
|
|
46
|
+
overlay: h(IconButton, {
|
|
47
|
+
variant: 'outline',
|
|
48
|
+
size: 'md',
|
|
49
|
+
icon: copied ? h(IconCheckOutlineRegular) : h(IconCopyOutlineRegular),
|
|
50
|
+
label: copied ? t('codeCopied') : t('codeCopy'),
|
|
51
|
+
className: 'dshpc-cv__copy',
|
|
52
|
+
onClick: copy,
|
|
53
|
+
}),
|
|
54
|
+
});
|
|
106
55
|
}
|
|
107
56
|
//# sourceMappingURL=CodeViewer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeViewer.js","sourceRoot":"","sources":["../../../src/ui/display/CodeViewer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CodeViewer.js","sourceRoot":"","sources":["../../../src/ui/display/CodeViewer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,aAAa,IAAI,CAAC,EAAE,QAAQ,EAAyC,MAAM,OAAO,CAAA;AAC3F,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEhG,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AAqBnE,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,mDAAmD;IACnD,qBAAqB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAA;IACrD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;IACtF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,KAAK,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAW,EAAE,EAAE;YAC7C,IAAI,EAAE,EAAE,CAAC;gBACP,SAAS,CAAC,IAAI,CAAC,CAAA;gBACf,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAA;YACjD,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,OAAO,CAAC,CAAC,iBAAiB,EAAE;QAC1B,KAAK,EAAE,IAAI;QACX,IAAI;QACJ,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,WAAW;QACX,SAAS;QACT,KAAK;QACL,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE;YACrB,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC;YACrE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;YAC/C,SAAS,EAAE,gBAAgB;YAC3B,OAAO,EAAE,IAAI;SACd,CAAC;KACH,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dsh-plugin-core/ui/code-viewer` 子路径入口。
|
|
3
|
+
*
|
|
4
|
+
* 只读与可编辑是两个控件、一份 CodeMirror 底座;共用同一条子路径,不新开导出口
|
|
5
|
+
* (`docs/design/structure.md` §六:不再新增子路径)。重依赖只从这条子路径可达。
|
|
6
|
+
*/
|
|
7
|
+
export { CodeViewer, type CodeViewerProps } from './CodeViewer.js';
|
|
8
|
+
export { CodeEditor, type CodeEditorProps } from '../inputs/CodeEditor.js';
|
|
9
|
+
//# sourceMappingURL=code-viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-viewer.d.ts","sourceRoot":"","sources":["../../../src/ui/display/code-viewer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dsh-plugin-core/ui/code-viewer` 子路径入口。
|
|
3
|
+
*
|
|
4
|
+
* 只读与可编辑是两个控件、一份 CodeMirror 底座;共用同一条子路径,不新开导出口
|
|
5
|
+
* (`docs/design/structure.md` §六:不再新增子路径)。重依赖只从这条子路径可达。
|
|
6
|
+
*/
|
|
7
|
+
export { CodeViewer } from './CodeViewer.js';
|
|
8
|
+
export { CodeEditor } from '../inputs/CodeEditor.js';
|
|
9
|
+
//# sourceMappingURL=code-viewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-viewer.js","sourceRoot":"","sources":["../../../src/ui/display/code-viewer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAwB,MAAM,iBAAiB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAwB,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMirror 共用底座 —— 只读 CodeViewer 与可编辑 CodeEditor 共用这一份渲染。
|
|
3
|
+
*
|
|
4
|
+
* 放 infra 而不是某个控件目录:它是跨类共用的底座,不是控件(`structure.md` §二)。
|
|
5
|
+
* 不对外导出,只在 `dsh-plugin-core/ui/code-viewer` 子路径内被两个控件引用 ——
|
|
6
|
+
* `@uiw/react-codemirror` 是重依赖,不能从 `src/ui/index.ts` 可达。
|
|
7
|
+
*
|
|
8
|
+
* 明暗判据(唯一):body[data-ds-dark-theme],禁用 prefers-color-scheme。
|
|
9
|
+
*/
|
|
10
|
+
import { type CSSProperties, type ReactElement, type ReactNode } from 'react';
|
|
11
|
+
export interface CodeMirrorSurfaceProps {
|
|
12
|
+
/** 受控文本。 */
|
|
13
|
+
value: string;
|
|
14
|
+
/** 文件路径(按扩展名选语法高亮)。 */
|
|
15
|
+
path: string;
|
|
16
|
+
/** 只读开关:true = EditorState.readOnly,挡住一切输入但仍可框选复制。 */
|
|
17
|
+
readOnly: boolean;
|
|
18
|
+
/** 可编辑时回传全文;只读时不传。 */
|
|
19
|
+
onChange?: (value: string) => void;
|
|
20
|
+
/** 可选:浮在编辑器右上角的插槽(只读查看器的复制按钮)。 */
|
|
21
|
+
overlay?: ReactNode;
|
|
22
|
+
className?: string;
|
|
23
|
+
style?: CSSProperties;
|
|
24
|
+
height?: string;
|
|
25
|
+
lineNumbers?: boolean;
|
|
26
|
+
focusLine?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function CodeMirrorSurface(props: CodeMirrorSurfaceProps): ReactElement;
|
|
29
|
+
//# sourceMappingURL=code-mirror-surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-mirror-surface.d.ts","sourceRoot":"","sources":["../../../src/ui/infra/code-mirror-surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAA4D,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAiBvI,MAAM,WAAW,sBAAsB;IACrC,YAAY;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,sDAAsD;IACtD,QAAQ,EAAE,OAAO,CAAA;IACjB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,kCAAkC;IAClC,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAgE7E"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMirror 共用底座 —— 只读 CodeViewer 与可编辑 CodeEditor 共用这一份渲染。
|
|
3
|
+
*
|
|
4
|
+
* 放 infra 而不是某个控件目录:它是跨类共用的底座,不是控件(`structure.md` §二)。
|
|
5
|
+
* 不对外导出,只在 `dsh-plugin-core/ui/code-viewer` 子路径内被两个控件引用 ——
|
|
6
|
+
* `@uiw/react-codemirror` 是重依赖,不能从 `src/ui/index.ts` 可达。
|
|
7
|
+
*
|
|
8
|
+
* 明暗判据(唯一):body[data-ds-dark-theme],禁用 prefers-color-scheme。
|
|
9
|
+
*/
|
|
10
|
+
import { createElement as h, useEffect, useMemo, useRef, useState } from 'react';
|
|
11
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
12
|
+
import { EditorView } from '@codemirror/view';
|
|
13
|
+
import { ensureComponentStyles } from './css.js';
|
|
14
|
+
import { CODE_VIEWER_CSS } from '../display/code-viewer-css.js';
|
|
15
|
+
import { languageForPath } from '../display/code-viewer-lang.js';
|
|
16
|
+
import { codeMirrorTheme } from '../display/code-viewer-theme.js';
|
|
17
|
+
const DARK_ATTR = 'data-ds-dark-theme';
|
|
18
|
+
function hostDark() {
|
|
19
|
+
if (typeof document === 'undefined')
|
|
20
|
+
return false;
|
|
21
|
+
const body = document.body;
|
|
22
|
+
return body === null ? false : body.hasAttribute(DARK_ATTR);
|
|
23
|
+
}
|
|
24
|
+
export function CodeMirrorSurface(props) {
|
|
25
|
+
ensureComponentStyles('code-viewer', CODE_VIEWER_CSS);
|
|
26
|
+
const { value, path, readOnly, onChange, overlay, className, style, height = '100%', lineNumbers = true } = props;
|
|
27
|
+
const [dark, setDark] = useState(hostDark);
|
|
28
|
+
/** 编辑器实例(定位到行要 dispatch scrollIntoView)。 */
|
|
29
|
+
const viewRef = useRef(null);
|
|
30
|
+
// 用户切主题 = 宿主 toggleAttribute 写 body[data-ds-dark-theme] ⇒ 用 MutationObserver 跟。
|
|
31
|
+
// 挂载时先 sync 一次:插件挂载可能早于宿主写好该属性。
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (typeof document === 'undefined' || typeof MutationObserver !== 'function')
|
|
34
|
+
return;
|
|
35
|
+
const body = document.body;
|
|
36
|
+
if (body === null)
|
|
37
|
+
return;
|
|
38
|
+
const sync = () => { setDark(body.hasAttribute(DARK_ATTR)); };
|
|
39
|
+
sync();
|
|
40
|
+
const observer = new MutationObserver(sync);
|
|
41
|
+
observer.observe(body, { attributeFilter: [DARK_ATTR] });
|
|
42
|
+
return () => { observer.disconnect(); };
|
|
43
|
+
}, []);
|
|
44
|
+
const language = useMemo(() => languageForPath(path), [path]);
|
|
45
|
+
const extensions = useMemo(() => [
|
|
46
|
+
...codeMirrorTheme(dark),
|
|
47
|
+
EditorView.lineWrapping, // 默认全换行,避免横向滚动条
|
|
48
|
+
...(language !== null ? [language] : []),
|
|
49
|
+
], [dark, language]);
|
|
50
|
+
// 定位到行:预览分页是逐步追加的,文本到了才能滚 ⇒ 跟着 value 再试一次。
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const view = viewRef.current;
|
|
53
|
+
if (view === null || props.focusLine === undefined)
|
|
54
|
+
return;
|
|
55
|
+
if (props.focusLine > view.state.doc.lines)
|
|
56
|
+
return;
|
|
57
|
+
view.dispatch({ effects: EditorView.scrollIntoView(view.state.doc.line(props.focusLine).from, { y: 'center' }) });
|
|
58
|
+
}, [value, props.focusLine]);
|
|
59
|
+
return h('div', { className: `dshpc-cv${className ? ` ${className}` : ''}`, style }, overlay ?? null, h(CodeMirror, {
|
|
60
|
+
value,
|
|
61
|
+
className: 'dshpc-cv__editor dshpc-scroll-thin',
|
|
62
|
+
theme: 'none',
|
|
63
|
+
extensions,
|
|
64
|
+
readOnly,
|
|
65
|
+
onChange: onChange === undefined ? undefined : (next) => { onChange(next); },
|
|
66
|
+
height,
|
|
67
|
+
onCreateEditor: (view) => { viewRef.current = view; },
|
|
68
|
+
style: { flex: '1 1 auto', minHeight: 0, overflow: 'hidden' },
|
|
69
|
+
// 编辑辅助只在可编辑态打开:只读查看器不该有当前行高亮 / 补全 / 括号配对这些编辑噪音。
|
|
70
|
+
basicSetup: {
|
|
71
|
+
lineNumbers,
|
|
72
|
+
foldGutter: false,
|
|
73
|
+
highlightActiveLine: !readOnly,
|
|
74
|
+
highlightActiveLineGutter: !readOnly,
|
|
75
|
+
autocompletion: !readOnly,
|
|
76
|
+
bracketMatching: true,
|
|
77
|
+
closeBrackets: !readOnly,
|
|
78
|
+
indentOnInput: !readOnly,
|
|
79
|
+
searchKeymap: !readOnly,
|
|
80
|
+
},
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=code-mirror-surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-mirror-surface.js","sourceRoot":"","sources":["../../../src/ui/infra/code-mirror-surface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeEditor —— 可编辑的 CodeMirror 控件(录入类)。
|
|
3
|
+
*
|
|
4
|
+
* 与只读 CodeViewer 共用 `infra/code-mirror-surface`,两者同在 `dsh-plugin-core/ui/code-viewer`
|
|
5
|
+
* 子路径导出:调用方想只读用 CodeViewer、想编辑用 CodeEditor,重依赖只在这一条子路径里。
|
|
6
|
+
* 不要把它加进 `src/ui/index.ts` —— 那会把 CodeMirror 拖进所有插件的包。
|
|
7
|
+
*
|
|
8
|
+
* 受控:控件自己不存文本,改一个字就经 onChange 回传全文,由调用方决定怎么保存。
|
|
9
|
+
*/
|
|
10
|
+
import { type CSSProperties, type ReactElement } from 'react';
|
|
11
|
+
export interface CodeEditorProps {
|
|
12
|
+
/** 受控文本。 */
|
|
13
|
+
value: string;
|
|
14
|
+
/** 文本变化回调(每次编辑带出全文)。 */
|
|
15
|
+
onChange: (value: string) => void;
|
|
16
|
+
/** 可选:文件路径,按扩展名选语法高亮;不传即纯文本。 */
|
|
17
|
+
path?: string;
|
|
18
|
+
/** 可选:透传调用方样式类名。 */
|
|
19
|
+
className?: string;
|
|
20
|
+
/** 可选:透传根 div 行内样式。 */
|
|
21
|
+
style?: CSSProperties;
|
|
22
|
+
/** 可选:编辑器高度,默认 "100%";无确定高度上下文传 "auto" 随内容撑高。 */
|
|
23
|
+
height?: string;
|
|
24
|
+
/** 可选:是否显示行号,默认 true。 */
|
|
25
|
+
lineNumbers?: boolean;
|
|
26
|
+
/** 可选:挂载/换文本后把这一行滚到视口中部。 */
|
|
27
|
+
focusLine?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function CodeEditor(props: CodeEditorProps): ReactElement;
|
|
30
|
+
//# sourceMappingURL=CodeEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../../src/ui/inputs/CodeEditor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAsB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAGjF,MAAM,WAAW,eAAe;IAC9B,YAAY;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,wBAAwB;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uBAAuB;IACvB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAY/D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeEditor —— 可编辑的 CodeMirror 控件(录入类)。
|
|
3
|
+
*
|
|
4
|
+
* 与只读 CodeViewer 共用 `infra/code-mirror-surface`,两者同在 `dsh-plugin-core/ui/code-viewer`
|
|
5
|
+
* 子路径导出:调用方想只读用 CodeViewer、想编辑用 CodeEditor,重依赖只在这一条子路径里。
|
|
6
|
+
* 不要把它加进 `src/ui/index.ts` —— 那会把 CodeMirror 拖进所有插件的包。
|
|
7
|
+
*
|
|
8
|
+
* 受控:控件自己不存文本,改一个字就经 onChange 回传全文,由调用方决定怎么保存。
|
|
9
|
+
*/
|
|
10
|
+
import { createElement as h } from 'react';
|
|
11
|
+
import { CodeMirrorSurface } from '../infra/code-mirror-surface.js';
|
|
12
|
+
export function CodeEditor(props) {
|
|
13
|
+
return h(CodeMirrorSurface, {
|
|
14
|
+
value: props.value,
|
|
15
|
+
path: props.path ?? '',
|
|
16
|
+
readOnly: false,
|
|
17
|
+
onChange: props.onChange,
|
|
18
|
+
className: props.className,
|
|
19
|
+
style: props.style,
|
|
20
|
+
height: props.height,
|
|
21
|
+
lineNumbers: props.lineNumbers,
|
|
22
|
+
focusLine: props.focusLine,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=CodeEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeEditor.js","sourceRoot":"","sources":["../../../src/ui/inputs/CodeEditor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,IAAI,CAAC,EAAyC,MAAM,OAAO,CAAA;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AAqBnE,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,OAAO,CAAC,CAAC,iBAAiB,EAAE;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;QACtB,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC,CAAA;AACJ,CAAC"}
|
package/docs/design/structure.md
CHANGED
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
2. **必须拿到业务对象(工作区 / 会话 / 文件 / 模型)才能工作吗?** → 落 `src/adv/`,不进 `ui`。
|
|
29
29
|
3. **按「用户拿它做什么」选类**:
|
|
30
30
|
|
|
31
|
-
| 类 | 判据 | 成员(2026-11-
|
|
31
|
+
| 类 | 判据 | 成员(2026-11-11) |
|
|
32
32
|
|---|---|---|
|
|
33
33
|
| **动作** `actions` | 点它触发一次操作,本身不产生值 | Button、IconButton |
|
|
34
|
-
| **录入** `inputs` | 产生或修改一个值 | Input、NumberInput、PrefixedInput、Textarea、Checkbox、Segmented、Picker、DateTimePicker、WorkspacePicker、ModelPicker、InputGroup |
|
|
34
|
+
| **录入** `inputs` | 产生或修改一个值 | Input、NumberInput、PrefixedInput、Textarea、Checkbox、Segmented、Picker、DateTimePicker、WorkspacePicker、ModelPicker、InputGroup、CodeEditor |
|
|
35
35
|
| **展示** `display` | 只呈现内容,不改变状态 | Card、StripCard、Surface、Chip、Table、ListRow、CodeViewer、MarqueeText、FlipText、LiveText、SectionHead、FieldHint |
|
|
36
36
|
| **反馈** `feedback` | 表达「正在进行 / 刚完成 / 出错了」 | Modal、SideSheet、AlertModal、ConfirmModal、alertModal、confirmModal、Toast、host-toast、Loader、LoaderBar、Loading |
|
|
37
37
|
| **布局** `layout` | 只决定内部元素怎么摆、怎么拼 | SplitGroup、PanelDock、QuickToolbar、resizer |
|
|
@@ -62,10 +62,10 @@ src/
|
|
|
62
62
|
│ ├── inputs/ Field(Input/NumberInput/PrefixedInput)· Textarea · Checkbox
|
|
63
63
|
│ │ Segmented · Picker(+ picker-logic / picker-icons)
|
|
64
64
|
│ │ DateTimePicker(+ datetime-logic)· InputGroup
|
|
65
|
-
│ │ WorkspacePicker · ModelPicker
|
|
65
|
+
│ │ WorkspacePicker · ModelPicker · CodeEditor
|
|
66
66
|
│ ├── display/ Card · StripCard · Surface · Chip · Table · ListRow(+ table-logic / table-shared)
|
|
67
|
-
│ │ CodeViewer(+ code-viewer-lang / -theme
|
|
68
|
-
│ │ LiveText · SectionHead · FieldHint
|
|
67
|
+
│ │ CodeViewer(+ code-viewer-lang / -theme / 子路径入口 code-viewer)
|
|
68
|
+
│ │ MarqueeText · FlipText · LiveText · SectionHead · FieldHint
|
|
69
69
|
│ ├── feedback/ Modal · SideSheet · AlertModal · ConfirmModal(+ modal-host)
|
|
70
70
|
│ │ Toast(+ toast-host)· host-toast · Loader · LoaderBar · Loading
|
|
71
71
|
│ ├── layout/ SplitGroup · PanelDock(+ panel-dock-logic)· QuickToolbar
|
|
@@ -73,6 +73,7 @@ src/
|
|
|
73
73
|
│ ├── navigation/ Pagination(+ pagination-logic)
|
|
74
74
|
│ └── infra/ css · controls-css · locale · tooltip · host-data
|
|
75
75
|
│ overlay / panel(跨类共用浮层底座 + 皮肤)· thenable · ticker · chevron
|
|
76
|
+
│ code-mirror-surface(只读 / 可编辑共用的渲染底座)
|
|
76
77
|
│
|
|
77
78
|
├── utils/ ③ 纯方法 —— 零 React / 零 DOM(谁都能用,它不依赖谁)
|
|
78
79
|
│ ├── date 日期 / 相对时间 / 时间区间
|
|
@@ -113,13 +114,15 @@ utils(谁都不依赖,谁都可以用)
|
|
|
113
114
|
|---|---|---|
|
|
114
115
|
| `dsh-plugin-core/ui` | 全部控件(唯一主入口,扁平导出) | 单入口是业界共识(AntD / MUI 同);按类开 7 条子路径只增加记忆成本 |
|
|
115
116
|
| `dsh-plugin-core/ui/official` | L1 官方 adapter | `adv/*` 要直接取官方件,属结构性第二入口 |
|
|
116
|
-
| `dsh-plugin-core/ui/code-viewer` | CodeViewer | 直接引 `@uiw/react-codemirror
|
|
117
|
+
| `dsh-plugin-core/ui/code-viewer` | CodeViewer(只读)· CodeEditor(可编辑) | 直接引 `@uiw/react-codemirror`,重依赖必须可选;两个控件共用 `infra/code-mirror-surface`,不另开导出口 |
|
|
117
118
|
| `dsh-plugin-core/ui/host-toast` | 宿主原生 Toast | 入口静态 import 官方件会让 Node 单测崩(旧坑) |
|
|
118
119
|
| `dsh-plugin-core/adv/explorer` | 文件浏览 | 应用模块独立子路径 |
|
|
119
120
|
| `dsh-plugin-core/adv/session` | 会话预览 | 同上 |
|
|
120
121
|
|
|
121
122
|
**不再新增子路径**:想加,先问「是重依赖,还是只是分类?」—— 分类归目录,不归导出口。
|
|
122
123
|
|
|
124
|
+
只读 / 可编辑是同一份 CodeMirror 能力的两种用法,属分类不属新依赖,故共用 `ui/code-viewer` 一条子路径:可编辑件归 `inputs`、只读件归 `display`,两个控件都不进主入口(否则重依赖会拖进所有插件的包)。
|
|
125
|
+
|
|
123
126
|
## 七、demo 展示分区(两级,17 页)
|
|
124
127
|
|
|
125
128
|
侧栏与右侧共用 `packages/demo/src/sections/index.tsx` 的 `ALL_SECTIONS`(单一事实源)。
|
package/docs/help/ui.doc.ts
CHANGED
|
@@ -346,8 +346,43 @@ const doc: DocTopic = {
|
|
|
346
346
|
zh: '定制边界:props 就是定制面,要改行为请组合 props,不要 fork 源码;追加 class/style 只允许补布局,皮肤走 token 覆盖;缺控件请先提需求。',
|
|
347
347
|
en: 'Customization: props are the surface — compose them instead of forking source; appended class/style may only patch layout, skins go through token overrides; raise a request before writing a missing control yourself.',
|
|
348
348
|
},
|
|
349
|
+
{
|
|
350
|
+
zh: '代码编辑走独立子路径 `dsh-plugin-core/ui/code-viewer`:`CodeViewer` 只读(文件预览源码态用的也是它),`CodeEditor` 可编辑,两者共用一份 CodeMirror 底座。重依赖只挂在这条子路径上,不进 `ui` 主入口,所以不用编辑器的插件不会背上它。',
|
|
351
|
+
en: 'Code editing lives on the separate `dsh-plugin-core/ui/code-viewer` subpath: `CodeViewer` is read-only (also used by file preview source mode) and `CodeEditor` is editable; both share one CodeMirror surface. The heavy dependency stays on this subpath, off the main `ui` entry, so plugins that never edit code do not carry it.',
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
code: [
|
|
355
|
+
{ id: 'ui-setup', lang: 'ts', src: setup },
|
|
356
|
+
{
|
|
357
|
+
id: 'ui-code-editor',
|
|
358
|
+
lang: 'ts',
|
|
359
|
+
src: `import { CodeEditor, CodeViewer } from 'dsh-plugin-core/ui/code-viewer'
|
|
360
|
+
|
|
361
|
+
// 可编辑:值由调用方存,改一个字就把全文交回来
|
|
362
|
+
h(CodeEditor, {
|
|
363
|
+
value: draft,
|
|
364
|
+
onChange: (next) => setDraft(next),
|
|
365
|
+
path: 'notes.md',
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
// 只读:原来的查看器(文件预览源码态用的也是它)
|
|
369
|
+
h(CodeViewer, { text: draft, path: 'notes.md', t })`,
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
api: [
|
|
373
|
+
{
|
|
374
|
+
id: 'ui-code-editor-api',
|
|
375
|
+
rows: [
|
|
376
|
+
{ name: 'value', type: 'string', def: '—', desc: { zh: 'CodeEditor 受控文本;控件自己不存状态', en: 'Controlled text for CodeEditor; the control keeps no state of its own' } },
|
|
377
|
+
{ name: 'onChange', type: '(value: string) => void', def: '—', desc: { zh: '每次编辑回传全文,由调用方决定怎么保存', en: 'Emits the full text on every edit; the caller decides how to persist it' } },
|
|
378
|
+
{ name: 'path', type: 'string', def: "''", desc: { zh: '按扩展名选语法高亮;不传即纯文本', en: 'Picks a language by extension; omitted means plain text' } },
|
|
379
|
+
{ name: 'height', type: 'string', def: "'100%'", desc: { zh: '编辑器高度;无确定高度上下文传 auto 随内容撑高', en: 'Editor height; pass auto to grow with content when no fixed height exists' } },
|
|
380
|
+
{ name: 'lineNumbers', type: 'boolean', def: 'true', desc: { zh: '是否显示行号', en: 'Whether line numbers are shown' } },
|
|
381
|
+
{ name: 'focusLine', type: 'number', def: '—', desc: { zh: '挂载 / 换文本后把这一行滚到视口中部', en: 'Scrolls this line into the centre after mount or a text change' } },
|
|
382
|
+
{ name: 'className / style', type: 'string / CSSProperties', def: '—', desc: { zh: '透传给根 div,只补布局,皮肤走 token', en: 'Passed to the root div; layout only, skins go through tokens' } },
|
|
383
|
+
],
|
|
384
|
+
},
|
|
349
385
|
],
|
|
350
|
-
code: [{ id: 'ui-setup', lang: 'ts', src: setup }],
|
|
351
386
|
},
|
|
352
387
|
{
|
|
353
388
|
id: 'button',
|
package/docs/help/ui.md
CHANGED
|
@@ -22,6 +22,20 @@
|
|
|
22
22
|
|
|
23
23
|
> EN: Customization: props are the surface — compose them instead of forking source; appended class/style may only patch layout, skins go through token overrides; raise a request before writing a missing control yourself.
|
|
24
24
|
|
|
25
|
+
代码编辑走独立子路径 `dsh-plugin-core/ui/code-viewer`:`CodeViewer` 只读(文件预览源码态用的也是它),`CodeEditor` 可编辑,两者共用一份 CodeMirror 底座。重依赖只挂在这条子路径上,不进 `ui` 主入口,所以不用编辑器的插件不会背上它。
|
|
26
|
+
|
|
27
|
+
> EN: Code editing lives on the separate `dsh-plugin-core/ui/code-viewer` subpath: `CodeViewer` is read-only (also used by file preview source mode) and `CodeEditor` is editable; both share one CodeMirror surface. The heavy dependency stays on this subpath, off the main `ui` entry, so plugins that never edit code do not carry it.
|
|
28
|
+
|
|
29
|
+
| 参数 | 类型 | 默认 | 说明(zh) | 说明(en) |
|
|
30
|
+
|---|---|---|---|---|
|
|
31
|
+
| `value` | `string` | — | CodeEditor 受控文本;控件自己不存状态 | Controlled text for CodeEditor; the control keeps no state of its own |
|
|
32
|
+
| `onChange` | `(value: string) => void` | — | 每次编辑回传全文,由调用方决定怎么保存 | Emits the full text on every edit; the caller decides how to persist it |
|
|
33
|
+
| `path` | `string` | '' | 按扩展名选语法高亮;不传即纯文本 | Picks a language by extension; omitted means plain text |
|
|
34
|
+
| `height` | `string` | '100%' | 编辑器高度;无确定高度上下文传 auto 随内容撑高 | Editor height; pass auto to grow with content when no fixed height exists |
|
|
35
|
+
| `lineNumbers` | `boolean` | true | 是否显示行号 | Whether line numbers are shown |
|
|
36
|
+
| `focusLine` | `number` | — | 挂载 / 换文本后把这一行滚到视口中部 | Scrolls this line into the centre after mount or a text change |
|
|
37
|
+
| `className / style` | `string / CSSProperties` | — | 透传给根 div,只补布局,皮肤走 token | Passed to the root div; layout only, skins go through tokens |
|
|
38
|
+
|
|
25
39
|
```ts id="ui-setup"
|
|
26
40
|
import { createStyleKit } from 'dsh-plugin-core/design'
|
|
27
41
|
import { setStyleKit } from 'dsh-plugin-core/ui'
|
|
@@ -31,6 +45,20 @@ setStyleKit(createStyleKit({ id: 'dsh-task-reminder-ui' }))
|
|
|
31
45
|
// 用不到的控件其 CSS 也不会进你的包。
|
|
32
46
|
```
|
|
33
47
|
|
|
48
|
+
```ts id="ui-code-editor"
|
|
49
|
+
import { CodeEditor, CodeViewer } from 'dsh-plugin-core/ui/code-viewer'
|
|
50
|
+
|
|
51
|
+
// 可编辑:值由调用方存,改一个字就把全文交回来
|
|
52
|
+
h(CodeEditor, {
|
|
53
|
+
value: draft,
|
|
54
|
+
onChange: (next) => setDraft(next),
|
|
55
|
+
path: 'notes.md',
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// 只读:原来的查看器(文件预览源码态用的也是它)
|
|
59
|
+
h(CodeViewer, { text: draft, path: 'notes.md', t })
|
|
60
|
+
```
|
|
61
|
+
|
|
34
62
|
## Button / IconButton / Segmented
|
|
35
63
|
|
|
36
64
|
> EN: Button / IconButton / Segmented
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-core",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.20",
|
|
4
4
|
"packageManager": "pnpm@12.3.4",
|
|
5
5
|
"description": "Shared base for DSH plugins: design tokens, UI controls, utils, workspace explorer, session preview",
|
|
6
6
|
"keywords": [
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"default": "./dist/ui/official.js"
|
|
34
34
|
},
|
|
35
35
|
"./ui/code-viewer": {
|
|
36
|
-
"types": "./dist/ui/display/
|
|
37
|
-
"default": "./dist/ui/display/
|
|
36
|
+
"types": "./dist/ui/display/code-viewer.d.ts",
|
|
37
|
+
"default": "./dist/ui/display/code-viewer.js"
|
|
38
38
|
},
|
|
39
39
|
"./ui/host-toast": {
|
|
40
40
|
"types": "./dist/ui/feedback/host-toast.d.ts",
|