clickgo 6.7.2 → 6.8.1

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 (44) hide show
  1. package/AGENTS.md +14 -0
  2. package/dist/app/demo.cga +0 -0
  3. package/dist/app/task.cga +0 -0
  4. package/dist/clickgo.d.ts +21 -0
  5. package/dist/control/common.cgc +0 -0
  6. package/dist/control/desktop.cgc +0 -0
  7. package/dist/control/form.cgc +0 -0
  8. package/dist/control/iconview.cgc +0 -0
  9. package/dist/control/jodit.cgc +0 -0
  10. package/dist/control/property.cgc +0 -0
  11. package/dist/control/task.cgc +0 -0
  12. package/dist/control/tuieditor.cgc +0 -0
  13. package/dist/global.css +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/lib/control.d.ts +69 -0
  16. package/dist/lib/core.d.ts +37 -1
  17. package/dist/lib/dom.d.ts +15 -1
  18. package/dist/lib/form.d.ts +43 -1
  19. package/dist/lib/task.d.ts +59 -2
  20. package/dist/lib/tool.d.ts +14 -1
  21. package/dist/theme/modern-light.cgt +0 -0
  22. package/dist/theme/modern.cgt +0 -0
  23. package/dist/theme/software-dark.cgt +0 -0
  24. package/dist/theme/software-light.cgt +0 -0
  25. package/doc/clickgo-rag.md +2399 -934
  26. package/package.json +12 -3
  27. package/test/core-module-loading.mjs +169 -0
  28. package/test/desktop.mjs +715 -0
  29. package/test/dom-style.mjs +261 -0
  30. package/test/form-launcher.mjs +102 -0
  31. package/test/form-native-regions.mjs +115 -0
  32. package/test/form-notify.mjs +90 -0
  33. package/test/form-viewport.mjs +79 -2
  34. package/test/iconview.mjs +70 -0
  35. package/test/jodit-lifecycle.mjs +212 -0
  36. package/test/rtl-archive.mjs +1 -1
  37. package/test/scroll.mjs +145 -0
  38. package/test/task-package-loading.mjs +94 -0
  39. package/test/task-tray.mjs +331 -0
  40. package/test/tool-assets.mjs +64 -0
  41. package/test/tuieditor-locale.mjs +175 -0
  42. package/test/vflow.mjs +122 -0
  43. package/dist/theme/compact-dark.cgt +0 -0
  44. package/dist/theme/compact-light.cgt +0 -0
package/test/vflow.mjs ADDED
@@ -0,0 +1,122 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFile } from 'node:fs/promises';
3
+ import vm from 'node:vm';
4
+ import { JSDOM } from 'jsdom';
5
+ import ts from 'typescript';
6
+ import { getClassPrototype, lang } from '../dist/lib/tool.js';
7
+
8
+ const dom = new JSDOM('<!doctype html><html><body></body></html>');
9
+ for (const name of ['window', 'document', 'Element', 'HTMLElement', 'SVGElement', 'Node']) {
10
+ Object.defineProperty(globalThis, name, { configurable: true, value: dom.window[name] });
11
+ }
12
+ Object.defineProperties(HTMLElement.prototype, {
13
+ offsetWidth: { configurable: true, get: () => 80 },
14
+ offsetHeight: { configurable: true, get: () => 20 },
15
+ });
16
+ const { createApp, reactive, nextTick, h } = await import('vue');
17
+ const state = reactive({ locale: 'en', direction: 'h', count: 2 });
18
+ const errors = [];
19
+ const watched = [];
20
+ process.on('unhandledRejection', error => { errors.push(error); });
21
+
22
+ // Keep the framework's computed $el access and component-root mounting order.
23
+ class AbstractControl {
24
+ get element() { return this.$el; }
25
+ get locale() { return state.locale; }
26
+ get localeDirection() { return lang.getDirection(this.locale); }
27
+ nextTick() { return this.$nextTick(); }
28
+ watch(...args) { return this.$watch(...args); }
29
+ emit(...args) { this.$emit(...args); }
30
+ propInt(name) { return parseInt(this.props[name]); }
31
+ }
32
+ const clickgo = {
33
+ control: { AbstractControl },
34
+ dom: {
35
+ isRtl: el => el instanceof Element && dom.window.getComputedStyle(el).direction === 'rtl',
36
+ watchStyle: (el, names, callback, immediate) => {
37
+ assert.ok(el instanceof HTMLElement && el.isConnected, 'style watcher needs a mounted element');
38
+ watched.push(el);
39
+ if (immediate) {
40
+ for (const name of names) callback(name, name === 'font' ? '13px sans-serif' : '0px');
41
+ }
42
+ },
43
+ watchSize() {},
44
+ unwatchSize() {},
45
+ },
46
+ };
47
+ const source = await readFile(new URL('../dist/sources/control/vflow/code.ts', import.meta.url), 'utf8');
48
+ const exports = {};
49
+ vm.runInNewContext(ts.transpileModule(source, {
50
+ compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
51
+ }).outputText, { exports, require: () => clickgo });
52
+ const instance = new exports.default();
53
+ const prototype = getClassPrototype(instance);
54
+ const layout = await readFile(new URL('../dist/sources/control/vflow/layout.html', import.meta.url), 'utf8');
55
+ const Flow = {
56
+ template: '<div><slot /></div>',
57
+ mounted() { this.$emit('clientwidth', 200); this.$emit('clientheight', 100); },
58
+ };
59
+ const Vflow = {
60
+ template: layout,
61
+ components: { 'cg-flow': Flow },
62
+ props: Object.fromEntries(Object.entries(instance.props).map(([name, value]) => [name, {
63
+ default: () => structuredClone(value),
64
+ }])),
65
+ emits: instance.emits,
66
+ data: () => Object.fromEntries(Object.entries(instance).filter(([name]) => !['props', 'emits'].includes(name))),
67
+ computed: prototype.access,
68
+ methods: prototype.method,
69
+ created() { this.props = this.$props; },
70
+ async mounted() { await this.$nextTick(); this.onMounted(); },
71
+ };
72
+ const host = document.createElement('div');
73
+ document.body.append(host);
74
+ const app = createApp({
75
+ render() {
76
+ return h('div', { dir: lang.getDirection(state.locale) }, [
77
+ h(Vflow, { ref: 'flow', data: state.count, direction: state.direction }, {
78
+ default: item => h('span', `Line ${item.row}`),
79
+ }),
80
+ ]);
81
+ },
82
+ });
83
+ app.config.errorHandler = error => { errors.push(error); };
84
+ const root = app.mount(host);
85
+
86
+ /** --- Drain Vue render, mount and deferred item-size work. --- */
87
+ async function flush() {
88
+ for (let i = 0; i < 10; ++i) await nextTick();
89
+ await new Promise(resolve => setImmediate(resolve));
90
+ assert.deepEqual(errors, [], 'Vflow must mount/update without runtime errors');
91
+ }
92
+ await flush();
93
+ assert.equal(watched.length, 1);
94
+ assert.equal(root.$refs.flow.element, host.querySelector('[direction]'));
95
+ assert.equal(root.$refs.flow.length, 160);
96
+ assert.equal(root.$refs.flow.isRtl, false);
97
+ assert.equal(host.querySelector('.item').style.left, '0px');
98
+ state.count = 102;
99
+ await flush();
100
+ assert.equal(root.$refs.flow.pos.length, 102);
101
+ assert.ok(host.querySelectorAll('.item').length < 102, 'only visible items are rendered');
102
+ state.locale = 'ar';
103
+ await flush();
104
+ assert.equal(root.$refs.flow.isRtl, true);
105
+ assert.equal(host.querySelector('.item').style.left, '');
106
+ assert.equal(host.querySelector('.item').style.right, '0px');
107
+ state.direction = 'v';
108
+ await flush();
109
+ assert.equal(root.$refs.flow.isRtl, false);
110
+ assert.equal(root.$refs.flow.length, 2040);
111
+ state.count = 0;
112
+ await flush();
113
+ assert.equal(root.$refs.flow.pos.length, 0);
114
+ state.count = 2;
115
+ state.direction = 'h';
116
+ state.locale = 'en';
117
+ await flush();
118
+ assert.equal(root.$refs.flow.length, 160);
119
+ assert.equal(host.querySelector('.item').style.left, '0px');
120
+ app.unmount();
121
+ await flush();
122
+ console.log('Vflow real Vue mount, virtualization, data/direction updates and live RTL switching passed.');
Binary file
Binary file