clickgo 6.2.0 → 6.4.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.
@@ -7076,7 +7076,7 @@ SVG 内容或 URL 地址。
7076
7076
 
7077
7077
  `(event: ISwitchChangeEvent) => void`
7078
7078
 
7079
- 值改变时触发。
7079
+ 值切换前触发,可调用 `event.preventDefault()` 阻止本次切换。`event.detail.value` 是切换前的当前值;未阻止时,随后更新状态并触发 `update:modelValue`。需要根据新状态执行重绘等操作时,应监听双向绑定的值,不要在此事件中读取尚未更新的值。
7080
7080
 
7081
7081
  ### 样式
7082
7082
 
@@ -7092,6 +7092,7 @@ SVG 内容或 URL 地址。
7092
7092
  <switch v-model="val"></switch>
7093
7093
  ```
7094
7094
 
7095
+
7095
7096
  ## tab
7096
7097
  ---
7097
7098
 
@@ -8033,6 +8034,8 @@ number 类型下增减按钮、键盘上下键及拖拽调值的步长,必须
8033
8034
 
8034
8035
  工具栏主要命令。
8035
8036
 
8037
+ 使用 `<toolbar-split></toolbar-split>` 分隔不同功能组,无需业务侧自定义分隔线样式。
8038
+
8036
8039
  #### right
8037
8040
 
8038
8041
  始终固定在工具栏右侧的命令。可在这里放置带 `pop` 插槽的按钮,将低优先级命令保留为 ClickGo 菜单。
@@ -8043,6 +8046,8 @@ number 类型下增减按钮、键盘上下键及拖拽调值的步长,必须
8043
8046
  <toolbar>
8044
8047
  <button type="tool">Open</button>
8045
8048
  <button type="tool">Save</button>
8049
+ <toolbar-split></toolbar-split>
8050
+ <button type="tool">Undo</button>
8046
8051
  <template v-slot:right>
8047
8052
  <button type="tool" area="mark">
8048
8053
  More
@@ -8057,6 +8062,32 @@ number 类型下增减按钮、键盘上下键及拖拽调值的步长,必须
8057
8062
  ```
8058
8063
 
8059
8064
 
8065
+ ## toolbar-split
8066
+ ---
8067
+
8068
+ 工具栏分隔线组件,用于分隔不同功能组的命令。
8069
+
8070
+ ### 样式
8071
+
8072
+ 作为 Toolbar 默认插槽或右侧插槽的子组件,显示居中的竖向分隔线。
8073
+
8074
+ 线宽为 1px,高度使用主题的 `--g-size-m`,颜色使用 `--g-border-color`,自动适应亮暗主题。命令间距由 Toolbar 管理,组件不额外添加边距,也不参与点击和键盘焦点。
8075
+
8076
+ 组件无参数、事件或插槽,提供 `separator` 角色和 `vertical` 方向供辅助技术识别。
8077
+
8078
+ ### 示例
8079
+
8080
+ ```xml
8081
+ <toolbar>
8082
+ <button type="tool">Open</button>
8083
+ <button type="tool">Save</button>
8084
+ <toolbar-split></toolbar-split>
8085
+ <button type="tool">Undo</button>
8086
+ <button type="tool">Redo</button>
8087
+ </toolbar>
8088
+ ```
8089
+
8090
+
8060
8091
  ## tuieditor
8061
8092
  ---
8062
8093
 
@@ -8680,12 +8711,15 @@ TUMS 监控组件。
8680
8711
 
8681
8712
  使用 iframe 元素,填满容器空间。无边框显示。
8682
8713
 
8714
+ 拖动或调整窗体大小时,会临时遮住网页以保持拖拽操作连续;结束后恢复网页交互。
8715
+
8683
8716
  ### 示例
8684
8717
 
8685
8718
  ```xml
8686
8719
  <web :src="pageUrl"></web>
8687
8720
  ```
8688
8721
 
8722
+
8689
8723
  ## xterm
8690
8724
  ---
8691
8725
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clickgo",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "Background interface, software interface, mobile phone APP interface operation library.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -0,0 +1,96 @@
1
+ // Run: node --experimental-vm-modules test/web-drag-mask.mjs
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { SourceTextModule, SyntheticModule } from 'node:vm';
5
+ import { JSDOM } from 'jsdom';
6
+ import ts from 'typescript';
7
+
8
+ const dom = new JSDOM('<!doctype html><html><head></head><body></body></html>');
9
+ for (const name of ['window', 'document', 'Element', 'SVGElement', 'Node', 'HTMLElement']) {
10
+ globalThis[name] = dom.window[name];
11
+ }
12
+ globalThis.getComputedStyle = dom.window.getComputedStyle.bind(dom.window);
13
+ const { createApp, compile, reactive, nextTick } = await import('vue');
14
+ const pointer = await import('@litert/pointer');
15
+ const state = reactive({ move: false });
16
+ const clickgo = new SyntheticModule(['control', 'dom'], function() {
17
+ this.setExport('control', { AbstractControl: class {} });
18
+ this.setExport('dom', { is: state });
19
+ });
20
+ const source = await readFile(new URL('../dist/sources/control/web/code.ts', import.meta.url), 'utf8');
21
+ const web = new SourceTextModule(ts.transpileModule(source, {
22
+ compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext },
23
+ }).outputText);
24
+ await web.link(() => clickgo);
25
+ await web.evaluate();
26
+ const control = new web.namespace.default();
27
+
28
+ // Exercise the actual launcher hooks with the installed Pointer library.
29
+ const launcher = await readFile(new URL('../dist/clickgo.ts', import.meta.url), 'utf8');
30
+ const hookSource = launcher.match(/ modules\.pointer\.addMoveHook\('down',[\s\S]*? modules\.pointer\.addMoveHook\('up',[\s\S]*? \}\);/)[0];
31
+ const hooks = new SourceTextModule(`import { pointer, is } from 'bridge';
32
+ const modules = { pointer }; const lDom = { is }; ${hookSource}`);
33
+ const bridge = new SyntheticModule(['pointer', 'is'], function() {
34
+ this.setExport('pointer', pointer);
35
+ this.setExport('is', state);
36
+ });
37
+ await hooks.link(() => bridge);
38
+ await hooks.evaluate();
39
+
40
+ const template = await readFile(new URL('../dist/sources/control/web/layout.html', import.meta.url), 'utf8');
41
+ const host = document.createElement('div');
42
+ document.body.append(host);
43
+ const app = createApp({
44
+ render: compile(template),
45
+ data: () => ({ src: 'about:blank' }),
46
+ computed: { showMask: () => control.showMask },
47
+ });
48
+ app.mount(host);
49
+ const iframe = host.querySelector('iframe');
50
+ const mask = host.querySelector('.mask');
51
+ assert.equal(iframe.getAttribute('src'), 'about:blank');
52
+ assert.equal(mask.style.display, 'none');
53
+
54
+ function event(type, x, y) {
55
+ const e = new dom.window.Event(type, { bubbles: true, cancelable: true });
56
+ Object.assign(e, { clientX: x, clientY: y, pointerId: 1, pointerType: 'mouse', button: 0 });
57
+ return e;
58
+ }
59
+
60
+ for (const operation of ['move', 'resize']) {
61
+ for (const finish of ['pointerup', 'pointercancel']) {
62
+ let updates = 0;
63
+ const handle = document.createElement('div');
64
+ document.body.append(handle);
65
+ handle.addEventListener('pointerdown', e => {
66
+ if (operation === 'resize') {
67
+ pointer.resize(e, {
68
+ border: 'rb', objectLeft: 0, objectTop: 0,
69
+ objectWidth: 400, objectHeight: 300,
70
+ move: () => { ++updates; },
71
+ });
72
+ }
73
+ else {
74
+ pointer.move(e, { move: () => { ++updates; } });
75
+ }
76
+ });
77
+ handle.dispatchEvent(event('pointerdown', 400, 300));
78
+ await nextTick();
79
+ assert.equal(state.move, true);
80
+ assert.notEqual(mask.style.display, 'none');
81
+ mask.dispatchEvent(event('pointermove', 350, 250));
82
+ mask.dispatchEvent(event('pointermove', 320, 230));
83
+ assert.equal(updates, 2);
84
+ mask.dispatchEvent(event(finish, 320, 230));
85
+ await nextTick();
86
+ assert.equal(state.move, false);
87
+ assert.equal(mask.style.display, 'none');
88
+ mask.dispatchEvent(event('pointermove', 300, 200));
89
+ assert.equal(updates, 2);
90
+ assert.equal(host.querySelector('iframe'), iframe);
91
+ handle.remove();
92
+ }
93
+ }
94
+ app.unmount();
95
+ dom.window.close();
96
+ console.log('WEB drag/resize mask, pointerup/cancel cleanup and iframe preservation checks passed.');