clickgo 6.5.1 → 6.5.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.
@@ -1711,7 +1711,7 @@ cell 之间的间距,默认 0。
1711
1711
  ## dock
1712
1712
  ---
1713
1713
 
1714
- 桌面软件侧栏停靠容器。负责展开、收起和浮动显示,与 `dock-group`、`dock-item` 搭配使用;业务内容由 Form/Panel 的局部应用组件提供。当所属 Form 宽度小于 `600px` 时,Dock 会自动进入不可展开的收起模式,并在空间恢复后回到 `expanded` 指定的状态。
1714
+ 桌面软件侧栏停靠容器。负责展开、收起和浮动显示,与 `dock-group`、`dock-item` 搭配使用;业务内容由 Form/Panel 的局部应用组件提供。当所属 Form 宽度小于 `600px` 时,Dock 会自动进入不可展开的收起模式,并在空间恢复后回到 `expanded` 指定的状态。收起后的浮动面板宽度不会超过 Dock 到浏览器视窗边缘的剩余空间。
1715
1715
 
1716
1716
  ### 参数
1717
1717
 
@@ -3001,7 +3001,7 @@ public init(canvas: fabric.Canvas): void {
3001
3001
 
3002
3002
  `(size: { width: number; height: number }) => void`
3003
3003
 
3004
- 窗体实际显示尺寸变化时触发,首次挂载也会触发。框架只报告尺寸,不自动改变窗体位置、大小或窗口能力;应用可据此自行切换 `move`、`resize`、`min`、`max` 等参数。
3004
+ 窗体实际显示尺寸变化时触发,首次挂载也会触发。浏览器模式下非最大化窗体的实际显示尺寸不超过视窗;应用可据此自行切换 `move`、`resize`、`min`、`max` 等参数。
3005
3005
 
3006
3006
  ### 样式
3007
3007
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clickgo",
3
- "version": "6.5.1",
3
+ "version": "6.5.2",
4
4
  "description": "Background interface, software interface, mobile phone APP interface operation library.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -6,6 +6,12 @@ import { SourceTextModule, SyntheticModule } from 'node:vm';
6
6
  const sizeWatches = [];
7
7
  const sizeUnwatches = [];
8
8
 
9
+ globalThis.document = {
10
+ 'documentElement': {
11
+ 'clientWidth': 360
12
+ }
13
+ };
14
+
9
15
  class AbstractControl {
10
16
  constructor(rootForm, height) {
11
17
  this.rootForm = rootForm;
@@ -47,6 +53,9 @@ const clickgo = new SyntheticModule(['control', 'dom'], function() {
47
53
  handler();
48
54
  }
49
55
  return true;
56
+ },
57
+ isRtl(element) {
58
+ return element.rtl;
50
59
  }
51
60
  });
52
61
  });
@@ -73,6 +82,9 @@ assert.equal(dockB.narrow, false);
73
82
  assert.equal(dockA1.floatAreaHeight, 300);
74
83
  assert.equal(dockA2.floatAreaHeight, 400);
75
84
  assert.equal(dockB.floatAreaHeight, 500);
85
+ assert.equal(dockA1.viewportWidth, 360);
86
+ assert.equal(dockA2.viewportWidth, 360);
87
+ assert.equal(dockB.viewportWidth, 360);
76
88
 
77
89
  dockB.toggleFloat(1);
78
90
  dockA1.toggleFloat(2);
@@ -82,12 +94,79 @@ assert.equal(dockA2.floatGroup, 3);
82
94
  assert.equal(dockB.floatGroup, 1);
83
95
 
84
96
  const dockA1Watch = dockA1.access.formSizeWatch;
97
+ const dockA1ViewportWatch = dockA1.access.viewportSizeWatch;
85
98
  dockA1.onUnmounted();
86
99
  assert.equal(dockA1.access.formSizeWatch, null);
87
- assert.equal(sizeUnwatches.length, 1);
100
+ assert.equal(dockA1.access.viewportSizeWatch, null);
101
+ assert.equal(sizeUnwatches.length, 2);
88
102
  assert.equal(sizeUnwatches[0].current, dockA1);
89
103
  assert.equal(sizeUnwatches[0].element, formA.element);
90
104
  assert.equal(sizeUnwatches[0].handler, dockA1Watch.handler);
91
- assert.equal(sizeWatches.length, 3);
105
+ assert.equal(sizeUnwatches[1].current, dockA1);
106
+ assert.equal(sizeUnwatches[1].element, document.documentElement);
107
+ assert.equal(sizeUnwatches[1].handler, dockA1ViewportWatch.handler);
108
+ assert.equal(sizeWatches.length, 6);
109
+
110
+ const groupMod = new SourceTextModule(await readFile(new URL('../dist/sources/control/dock-group/code.js', import.meta.url), 'utf8'));
111
+ await groupMod.link(() => clickgo);
112
+ await groupMod.evaluate();
113
+ const DockGroup = groupMod.namespace.default;
114
+
115
+ const areaRect = {
116
+ 'left': 40,
117
+ 'right': 80,
118
+ 'top': 0,
119
+ 'bottom': 300
120
+ };
121
+ const group = new DockGroup();
122
+ group.index = 0;
123
+ group.element = {
124
+ 'rtl': false,
125
+ 'getBoundingClientRect': () => ({
126
+ 'top': 0
127
+ })
128
+ };
129
+ group.refs = {
130
+ 'content': {
131
+ 'offsetHeight': 200
132
+ }
133
+ };
134
+ group.dock = {
135
+ 'expandedData': false,
136
+ 'floatGroup': 0,
137
+ 'floatAreaHeight': 300,
138
+ 'viewportWidth': 360,
139
+ 'positionData': 'left',
140
+ 'widthComp': '400px',
141
+ 'getFloatArea': () => ({
142
+ 'getBoundingClientRect': () => areaRect
143
+ })
144
+ };
145
+
146
+ group.updateFloatLayout();
147
+ assert.equal(group.floatMaxWidth, 280, 'LTR left Dock must use only the viewport space on its right');
148
+ assert.equal(group.floatStyle['max-width'], '280px');
149
+
150
+ group.element.rtl = true;
151
+ areaRect.left = 320;
152
+ areaRect.right = 360;
153
+ group.updateFloatLayout();
154
+ assert.equal(group.floatMaxWidth, 320, 'RTL left Dock must open toward the viewport space on its left');
155
+
156
+ group.dock.positionData = 'right';
157
+ areaRect.left = 0;
158
+ areaRect.right = 40;
159
+ group.updateFloatLayout();
160
+ assert.equal(group.floatMaxWidth, 320, 'RTL right Dock must open toward the viewport space on its right');
161
+
162
+ const dockStyle = await readFile(new URL('../dist/sources/control/dock/style.scss', import.meta.url), 'utf8');
163
+ assert.match(dockStyle, /border-inline-end/, 'left Dock border must follow the inline end edge');
164
+ assert.match(dockStyle, /border-inline-start/, 'right Dock border must follow the inline start edge');
165
+ assert.match(dockStyle, /:dir\(rtl\)[\s\S]*scaleX\(-1\)/, 'Dock chevron must mirror in RTL');
166
+
167
+ const groupStyle = await readFile(new URL('../dist/sources/control/dock-group/style.scss', import.meta.url), 'utf8');
168
+ assert.match(groupStyle, /inset-inline-start:\s*100%/, 'left Dock floating panel must open toward inline end');
169
+ assert.match(groupStyle, /inset-inline-end:\s*100%/, 'right Dock floating panel must open toward inline start');
170
+ assert.match(groupStyle, /max-width:\s*calc\(100vw - 40px\)/, 'floating panel must reserve the collapsed Dock width');
92
171
 
93
- console.log('Dock access state, Form isolation and size-watch cleanup checks passed.');
172
+ console.log('Dock lifecycle, RTL layout and viewport-bound floating-panel checks passed.');
@@ -18,14 +18,16 @@ theme.textContent = `
18
18
  `;
19
19
  document.head.append(theme);
20
20
 
21
- for (const nativeFirst of [true, false]) {
21
+ for (const mode of ['web', 'native-framed', 'native-frameless']) {
22
+ const nativeFirst = mode === 'native-frameless';
23
+ const nativeMode = mode !== 'web';
22
24
  for (const border of ['normal', 'thin', 'plain', 'none']) {
23
25
  const host = document.createElement('div');
24
26
  document.body.append(host);
25
27
  const app = createApp({
26
28
  render,
27
29
  data: () => ({
28
- border, isNativeNoFrameFirst: nativeFirst, flashTimer: undefined,
30
+ border, isNative: nativeMode, isNativeNoFrameFirst: nativeFirst, flashTimer: undefined,
29
31
  stateMinData: false, stateMaxData: false, taskPosition: 'bottom',
30
32
  isShow: true, isInside: false, formFocus: false, widthData: 500,
31
33
  heightData: 400, leftData: 0, topData: 0, zIndex: 1,
@@ -40,6 +42,8 @@ for (const nativeFirst of [true, false]) {
40
42
  app.component('cg-loading', { render: () => null });
41
43
  const form = app.mount(host);
42
44
  const wrap = host.querySelector('.wrap');
45
+ assert.equal(wrap.style.maxWidth, nativeMode ? '' : '100vw');
46
+ assert.equal(wrap.style.maxHeight, nativeMode ? '' : '100vh');
43
47
  const inner = host.querySelector('.inner');
44
48
  const content = host.querySelector('.content');
45
49
  const header = host.querySelector('.header');
@@ -47,6 +51,12 @@ for (const nativeFirst of [true, false]) {
47
51
  const child = document.createElement('div');
48
52
  child.className = 'child-control';
49
53
  content.append(child);
54
+ if (!nativeMode && border === 'none') {
55
+ form.leftData = 700;
56
+ form.topData = 600;
57
+ await nextTick();
58
+ assert.deepEqual([wrap.style.left, wrap.style.top], ['700px', '600px']);
59
+ }
50
60
  for (const focused of [false, true]) {
51
61
  form.formFocus = focused;
52
62
  form.stateMaxData = focused;
@@ -0,0 +1,50 @@
1
+ // Run: node test/form-viewport.mjs
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import vm from 'node:vm';
5
+ import ts from 'typescript';
6
+
7
+ let nativeMode = false;
8
+ const clickgo = {
9
+ isNative: () => nativeMode,
10
+ control: {
11
+ AbstractControl: class {
12
+ emit() {}
13
+ propInt(name) { return Number(this.props[name]); }
14
+ trigger() { return Promise.resolve(); }
15
+ },
16
+ },
17
+ native: {
18
+ restore: async () => {},
19
+ size: async () => {},
20
+ },
21
+ tool: { sleep: () => Promise.resolve() },
22
+ };
23
+ const source = await readFile(new URL('../dist/sources/control/form/code.ts', import.meta.url), 'utf8');
24
+ const compiled = ts.transpileModule(source, {
25
+ compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
26
+ }).outputText;
27
+ const exports = {};
28
+ vm.runInNewContext(compiled, {
29
+ exports, require: () => clickgo,
30
+ window: { innerWidth: 640, innerHeight: 440 },
31
+ });
32
+ const Form = exports.default;
33
+
34
+ function restore(history, mode = 'web') {
35
+ nativeMode = mode !== 'web';
36
+ const form = new Form();
37
+ form.isNativeNoFrameFirst = mode === 'native-frameless';
38
+ form.stateMaxData = true;
39
+ form.historyLocation = history;
40
+ form.element = { style: {}, removeAttribute() {} };
41
+ form.maxMethod();
42
+ return [form.widthData, form.heightData, form.leftData, form.topData];
43
+ }
44
+
45
+ assert.deepEqual(restore({ width: 900, height: 700, left: 500, top: 300 }), [900, 700, 0, 0]);
46
+ assert.deepEqual(restore({ width: 400, height: 300, left: 500, top: 300 }), [400, 300, 240, 140]);
47
+ assert.deepEqual(restore({ width: 600, height: 40, left: 40, top: 400 }), [600, 40, 40, 400]);
48
+ assert.deepEqual(restore({ width: 900, height: 700, left: 500, top: 300 }, 'native-framed'), [900, 700, 500, 300]);
49
+ assert.deepEqual(restore({ width: 900, height: 700, left: 500, top: 300 }, 'native-frameless'), [900, 700, 500, 300]);
50
+ console.log('Form restore stays visible, edge-positioned Forms stay anchored, and Native geometry is unchanged.');
@@ -364,6 +364,7 @@ const rtlCodeChecks = [
364
364
  ['dist/control/common.cgc', 'toolbar', ['getScrollInlineOffset', 'setScrollLeft']],
365
365
  ['dist/control/common.cgc', 'date', ['autoPosition', 'autoScroll']],
366
366
  ['dist/control/common.cgc', 'daterange', ['autoPosition', 'autoScroll']],
367
+ ['dist/control/common.cgc', 'dock-group', ['isRtl', 'floatMaxWidth']],
367
368
  ['dist/control/table.cgc', 'table', ['localeDirection', 'getScrollLeft', 'setScrollInlineOffset']],
368
369
  ['dist/control/desc.cgc', 'desc', ['getScrollInlineOffset', 'setScrollInlineOffset']],
369
370
  ['dist/control/iconview.cgc', 'iconview', ['isRtl']],
@@ -385,6 +386,8 @@ const rtlStyleChecks = [
385
386
  ['dist/control/common.cgc', 'list/style.css', 'dist/sources/control/list/style.css', [':dir(rtl)', 'margin-inline-end']],
386
387
  ['dist/control/common.cgc', 'tab/style.css', 'dist/sources/control/tab/style.css', ['border-inline-start-width', 'border-inline-end-width']],
387
388
  ['dist/control/common.cgc', 'timeline/style.css', 'dist/sources/control/timeline/style.css', ['border-inline-start']],
389
+ ['dist/control/common.cgc', 'dock/style.css', 'dist/sources/control/dock/style.css', [':dir(rtl)', 'border-inline-end']],
390
+ ['dist/control/common.cgc', 'dock-group/style.css', 'dist/sources/control/dock-group/style.css', ['inset-inline-start', 'max-width:calc(100vw - 40px)']],
388
391
  ['dist/control/table.cgc', 'table/style.css', 'dist/sources/control/table/style.css', ['border-inline-end', 'inset-inline-end']],
389
392
  ['dist/control/xterm.cgc', 'xterm/style.css', 'dist/sources/control/xterm/style.css', ['direction:ltr']],
390
393
  ];