quickwin 2026.5.2-3.145209

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 (83) hide show
  1. package/README.md +6 -0
  2. package/examples/pdf_preview.js +440 -0
  3. package/examples/pdf_preview.ts +470 -0
  4. package/examples/preact_demo.js +35 -0
  5. package/examples/preact_demo.tsx +49 -0
  6. package/examples/tray_demo.js +75 -0
  7. package/examples/tray_demo.tsx +79 -0
  8. package/lib/fetch.js +746 -0
  9. package/lib/fetch.ts +811 -0
  10. package/lib/polyfill.js +500 -0
  11. package/lib/polyfill.ts +454 -0
  12. package/lib/preact/hooks.js +287 -0
  13. package/lib/preact/hooks.ts +330 -0
  14. package/lib/preact/jsx-runtime.js +1 -0
  15. package/lib/preact/jsx-runtime.ts +2 -0
  16. package/lib/preact/jsx.d.ts +36 -0
  17. package/lib/preact/layout.js +153 -0
  18. package/lib/preact/layout.ts +183 -0
  19. package/lib/preact/preact.js +54 -0
  20. package/lib/preact/preact.ts +133 -0
  21. package/lib/preact/props.js +99 -0
  22. package/lib/preact/props.ts +119 -0
  23. package/lib/preact/render.js +320 -0
  24. package/lib/preact/render.ts +353 -0
  25. package/lib/websocket.js +540 -0
  26. package/lib/websocket.ts +574 -0
  27. package/package.json +32 -0
  28. package/quickwin.d.ts +657 -0
  29. package/test/add.wasm +0 -0
  30. package/test/complex.wasm +0 -0
  31. package/test/complex_imports.wasm +0 -0
  32. package/test/global_imports.wasm +0 -0
  33. package/test/import_func.wasm +0 -0
  34. package/test/imports.wasm +0 -0
  35. package/test/run.js +86 -0
  36. package/test/run.ts +90 -0
  37. package/test/sjlj.wasm +0 -0
  38. package/test/test_basic.js +7 -0
  39. package/test/test_basic.ts +9 -0
  40. package/test/test_brotli.js +48 -0
  41. package/test/test_brotli.ts +52 -0
  42. package/test/test_fetch_cache.js +131 -0
  43. package/test/test_fetch_cache.ts +141 -0
  44. package/test/test_ffi.js +157 -0
  45. package/test/test_ffi.ts +174 -0
  46. package/test/test_frame_encoding.js +128 -0
  47. package/test/test_frame_encoding.ts +132 -0
  48. package/test/test_helper.js +84 -0
  49. package/test/test_helper.ts +80 -0
  50. package/test/test_http_import.js +78 -0
  51. package/test/test_http_import.ts +74 -0
  52. package/test/test_mupdf_render.js +69 -0
  53. package/test/test_mupdf_render.ts +74 -0
  54. package/test/test_mupdf_twice.js +77 -0
  55. package/test/test_mupdf_twice.ts +81 -0
  56. package/test/test_mupdf_wasm.js +33 -0
  57. package/test/test_mupdf_wasm.ts +30 -0
  58. package/test/test_net_event.js +63 -0
  59. package/test/test_net_event.ts +59 -0
  60. package/test/test_net_fetch.js +153 -0
  61. package/test/test_net_fetch.ts +131 -0
  62. package/test/test_net_websocket.js +158 -0
  63. package/test/test_net_websocket.ts +144 -0
  64. package/test/test_polyfill.js +58 -0
  65. package/test/test_polyfill.ts +60 -0
  66. package/test/test_url.js +173 -0
  67. package/test/test_url.ts +183 -0
  68. package/test/test_wasm_basic.js +82 -0
  69. package/test/test_wasm_basic.ts +70 -0
  70. package/test/test_wasm_import_global.js +41 -0
  71. package/test/test_wasm_import_global.ts +39 -0
  72. package/test/test_wasm_sjlj.js +153 -0
  73. package/test/test_wasm_sjlj.ts +134 -0
  74. package/test/test_wasm_types.js +96 -0
  75. package/test/test_wasm_types.ts +108 -0
  76. package/test/types.wasm +0 -0
  77. package/tsconfig.json +18 -0
  78. package/vendor/mupdf-wasm/mupdf-wasm.d.ts +571 -0
  79. package/vendor/mupdf-wasm/mupdf-wasm.js +2749 -0
  80. package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
  81. package/vendor/mupdf-wasm/mupdf.d.ts +939 -0
  82. package/vendor/mupdf-wasm/mupdf.js +3317 -0
  83. package/win-mingw64.exe +0 -0
@@ -0,0 +1,153 @@
1
+ import * as ffi from 'ffi';
2
+ import * as win from 'win';
3
+ import * as gui from 'gui';
4
+ import { HWND_PROP, STYLE_PROP, RENDERED_VNODE_PROP, isVNode, getChildren } from './render.js';
5
+ import { moveWindow } from './props.js';
6
+ const scaleFactor = gui.GetScaleFactor();
7
+ const FFI_PTR = ffi.FFI_TYPE_POINTER;
8
+ const FFI_S32 = ffi.FFI_TYPE_SINT32;
9
+ const FFI_U32 = ffi.FFI_TYPE_UINT32;
10
+ const FFI_U64 = ffi.FFI_TYPE_UINT64;
11
+ const _user32 = win.LoadLibrary('user32.dll');
12
+ const GetClientRect_proc = _user32 ? win.GetProcAddress(_user32, 'GetClientRect') : 0;
13
+ function getClientSize(hwnd) {
14
+ if (!GetClientRect_proc)
15
+ return { w: 0, h: 0 };
16
+ const rectBuf = new ArrayBuffer(16);
17
+ const ok = ffi.ffiCall(GetClientRect_proc, [FFI_U64, FFI_PTR], [hwnd, rectBuf], FFI_U32);
18
+ if (!ok)
19
+ return { w: 0, h: 0 };
20
+ const dv = new DataView(rectBuf);
21
+ return { w: dv.getInt32(8, true), h: dv.getInt32(12, true) };
22
+ }
23
+ function resolveSize(val, available) {
24
+ if (val === undefined)
25
+ return -1;
26
+ if (typeof val === 'number')
27
+ return Math.floor(val * scaleFactor);
28
+ if (typeof val === 'string' && val.endsWith('%')) {
29
+ const pct = parseFloat(val);
30
+ if (!isNaN(pct))
31
+ return Math.floor(available * pct / 100);
32
+ }
33
+ return -1;
34
+ }
35
+ const DEFAULT_SIZES = {
36
+ button: Math.floor(24 * scaleFactor), edit: Math.floor(24 * scaleFactor),
37
+ static: Math.floor(20 * scaleFactor), checkbox: Math.floor(24 * scaleFactor),
38
+ groupbox: Math.floor(48 * scaleFactor), combobox: Math.floor(200 * scaleFactor),
39
+ listbox: Math.floor(100 * scaleFactor), progressbar: Math.floor(24 * scaleFactor),
40
+ };
41
+ function getDefaultChildSize(vnode) {
42
+ const ctrlType = typeof vnode.props === 'object' ? vnode.props?.type : undefined;
43
+ return DEFAULT_SIZES[ctrlType] ?? Math.floor(30 * scaleFactor);
44
+ }
45
+ function getLayoutChildren(vnode) {
46
+ const result = [];
47
+ if (vnode.type !== 'w')
48
+ return result;
49
+ for (const child of getChildren(vnode)) {
50
+ if (!isVNode(child))
51
+ continue;
52
+ const childHwnd = child[HWND_PROP];
53
+ if (childHwnd) {
54
+ result.push({ hwnd: childHwnd, style: child[STYLE_PROP] || {}, vnode: child });
55
+ }
56
+ }
57
+ return result;
58
+ }
59
+ function layoutNode(hwnd, vnode, availableRect) {
60
+ if (!isVNode(vnode) || vnode.type !== 'w')
61
+ return;
62
+ const style = vnode[STYLE_PROP] || {};
63
+ const dir = style.flexDirection || 'column';
64
+ const gap = Math.floor((style.gap || 0) * scaleFactor);
65
+ const padding = Math.floor((style.padding || 0) * scaleFactor);
66
+ const margin = Math.floor((style.margin || 0) * scaleFactor);
67
+ const fixedW = resolveSize(style.width, availableRect.w);
68
+ const fixedH = resolveSize(style.height, availableRect.h);
69
+ const nodeW = fixedW >= 0 ? fixedW : availableRect.w - margin * 2;
70
+ const nodeH = fixedH >= 0 ? fixedH : availableRect.h - margin * 2;
71
+ const nodeX = availableRect.x + margin;
72
+ const nodeY = availableRect.y + margin;
73
+ moveWindow(hwnd, nodeX, nodeY, nodeW, nodeH);
74
+ const children = getLayoutChildren(vnode);
75
+ if (children.length === 0)
76
+ return;
77
+ const isRow = dir === 'row';
78
+ const totalGap = gap * Math.max(0, children.length - 1);
79
+ const mainSize = (isRow ? nodeW : nodeH) - padding * 2 - totalGap;
80
+ const crossSize = (isRow ? nodeH : nodeW) - padding * 2;
81
+ let totalFlex = 0;
82
+ let fixedMainTotal = 0;
83
+ for (const child of children) {
84
+ const fg = child.style.flexGrow || 0;
85
+ const fixedMain = isRow
86
+ ? resolveSize(child.style.width, mainSize)
87
+ : resolveSize(child.style.height, mainSize);
88
+ if (fg > 0) {
89
+ totalFlex += fg;
90
+ }
91
+ else if (fixedMain >= 0) {
92
+ fixedMainTotal += fixedMain;
93
+ }
94
+ else {
95
+ fixedMainTotal += getDefaultChildSize(child.vnode);
96
+ }
97
+ }
98
+ const flexUnit = totalFlex > 0 ? Math.max(0, mainSize - fixedMainTotal) / totalFlex : 0;
99
+ let offset = 0;
100
+ for (const child of children) {
101
+ const fg = child.style.flexGrow || 0;
102
+ let childMain;
103
+ if (fg > 0) {
104
+ childMain = Math.floor(fg * flexUnit);
105
+ }
106
+ else {
107
+ const fixed = isRow
108
+ ? resolveSize(child.style.width, mainSize)
109
+ : resolveSize(child.style.height, mainSize);
110
+ childMain = fixed >= 0 ? fixed : getDefaultChildSize(child.vnode);
111
+ }
112
+ const childCross = isRow
113
+ ? resolveSize(child.style.height, crossSize)
114
+ : resolveSize(child.style.width, crossSize);
115
+ const actualCross = childCross >= 0 ? childCross : crossSize;
116
+ const childMargin = Math.floor((child.style.margin || 0) * scaleFactor);
117
+ const relX = isRow ? padding + offset : padding + childMargin;
118
+ const relY = isRow ? padding + childMargin : padding + offset;
119
+ const cw = isRow ? childMain : actualCross - childMargin * 2;
120
+ const ch = isRow ? actualCross - childMargin * 2 : childMain;
121
+ moveWindow(child.hwnd, relX, relY, Math.max(cw, 0), Math.max(ch, 0));
122
+ if (isVNode(child.vnode) && child.vnode.type === 'w') {
123
+ layoutNode(child.hwnd, child.vnode, { x: relX, y: relY, w: Math.max(cw, 0), h: Math.max(ch, 0) });
124
+ }
125
+ offset += childMain + gap;
126
+ }
127
+ }
128
+ function resolveToElementVNode(vnode) {
129
+ if (!isVNode(vnode))
130
+ return null;
131
+ if (vnode.type === 'w')
132
+ return vnode;
133
+ if (typeof vnode.type === 'function') {
134
+ const rendered = vnode[RENDERED_VNODE_PROP];
135
+ if (rendered && isVNode(rendered)) {
136
+ return resolveToElementVNode(rendered);
137
+ }
138
+ }
139
+ return null;
140
+ }
141
+ export function layout(rootHwnd, vnode) {
142
+ const clientSize = getClientSize(rootHwnd);
143
+ if (clientSize.w <= 0 || clientSize.h <= 0)
144
+ return;
145
+ const targetVNode = resolveToElementVNode(vnode);
146
+ if (!targetVNode)
147
+ return;
148
+ const targetHwnd = targetVNode[HWND_PROP];
149
+ if (!targetHwnd)
150
+ return;
151
+ moveWindow(targetHwnd, 0, 0, clientSize.w, clientSize.h);
152
+ layoutNode(targetHwnd, targetVNode, { x: 0, y: 0, w: clientSize.w, h: clientSize.h });
153
+ }
@@ -0,0 +1,183 @@
1
+ import * as ffi from 'ffi'
2
+ import * as win from 'win'
3
+ import * as gui from 'gui'
4
+ import { HWND_PROP, STYLE_PROP, CHILDREN_HWNDS_PROP, RENDERED_VNODE_PROP, isVNode, getChildren, type VNode } from './render.js'
5
+ import { moveWindow } from './props.js'
6
+
7
+ const scaleFactor = gui.GetScaleFactor()
8
+
9
+ const FFI_PTR = ffi.FFI_TYPE_POINTER
10
+ const FFI_S32 = ffi.FFI_TYPE_SINT32
11
+ const FFI_U32 = ffi.FFI_TYPE_UINT32
12
+ const FFI_U64 = ffi.FFI_TYPE_UINT64
13
+
14
+ const _user32 = win.LoadLibrary('user32.dll')
15
+ const GetClientRect_proc = _user32 ? win.GetProcAddress(_user32, 'GetClientRect') : 0
16
+
17
+ export interface LayoutStyle {
18
+ flexDirection?: 'row' | 'column'
19
+ justifyContent?: string
20
+ alignItems?: string
21
+ flexGrow?: number
22
+ width?: number | string
23
+ height?: number | string
24
+ padding?: number
25
+ margin?: number
26
+ gap?: number
27
+ }
28
+
29
+ interface LayoutRect {
30
+ x: number
31
+ y: number
32
+ w: number
33
+ h: number
34
+ }
35
+
36
+ function getClientSize(hwnd: number): { w: number; h: number } {
37
+ if (!GetClientRect_proc) return { w: 0, h: 0 }
38
+ const rectBuf = new ArrayBuffer(16)
39
+ const ok = ffi.ffiCall(GetClientRect_proc, [FFI_U64, FFI_PTR], [hwnd, rectBuf], FFI_U32) as number
40
+ if (!ok) return { w: 0, h: 0 }
41
+ const dv = new DataView(rectBuf)
42
+ return { w: dv.getInt32(8, true), h: dv.getInt32(12, true) }
43
+ }
44
+
45
+ function resolveSize(val: number | string | undefined, available: number): number {
46
+ if (val === undefined) return -1
47
+ if (typeof val === 'number') return Math.floor(val * scaleFactor)
48
+ if (typeof val === 'string' && val.endsWith('%')) {
49
+ const pct = parseFloat(val)
50
+ if (!isNaN(pct)) return Math.floor(available * pct / 100)
51
+ }
52
+ return -1
53
+ }
54
+
55
+ const DEFAULT_SIZES: Record<string, number> = {
56
+ button: Math.floor(24 * scaleFactor), edit: Math.floor(24 * scaleFactor),
57
+ static: Math.floor(20 * scaleFactor), checkbox: Math.floor(24 * scaleFactor),
58
+ groupbox: Math.floor(48 * scaleFactor), combobox: Math.floor(200 * scaleFactor),
59
+ listbox: Math.floor(100 * scaleFactor), progressbar: Math.floor(24 * scaleFactor),
60
+ }
61
+
62
+ function getDefaultChildSize(vnode: VNode): number {
63
+ const ctrlType = typeof vnode.props === 'object' ? vnode.props?.type : undefined
64
+ return DEFAULT_SIZES[ctrlType as string] ?? Math.floor(30 * scaleFactor)
65
+ }
66
+
67
+ function getLayoutChildren(vnode: VNode): { hwnd: number; style: LayoutStyle; vnode: VNode }[] {
68
+ const result: { hwnd: number; style: LayoutStyle; vnode: VNode }[] = []
69
+ if (vnode.type !== 'w') return result
70
+
71
+ for (const child of getChildren(vnode)) {
72
+ if (!isVNode(child)) continue
73
+ const childHwnd = child[HWND_PROP] as number | undefined
74
+ if (childHwnd) {
75
+ result.push({ hwnd: childHwnd, style: (child[STYLE_PROP] as LayoutStyle) || {}, vnode: child })
76
+ }
77
+ }
78
+ return result
79
+ }
80
+
81
+ function layoutNode(hwnd: number, vnode: VNode, availableRect: LayoutRect): void {
82
+ if (!isVNode(vnode) || vnode.type !== 'w') return
83
+
84
+ const style = (vnode[STYLE_PROP] as LayoutStyle) || {}
85
+ const dir = style.flexDirection || 'column'
86
+ const gap = Math.floor((style.gap || 0) * scaleFactor)
87
+ const padding = Math.floor((style.padding || 0) * scaleFactor)
88
+ const margin = Math.floor((style.margin || 0) * scaleFactor)
89
+
90
+ const fixedW = resolveSize(style.width, availableRect.w)
91
+ const fixedH = resolveSize(style.height, availableRect.h)
92
+ const nodeW = fixedW >= 0 ? fixedW : availableRect.w - margin * 2
93
+ const nodeH = fixedH >= 0 ? fixedH : availableRect.h - margin * 2
94
+
95
+ const nodeX = availableRect.x + margin
96
+ const nodeY = availableRect.y + margin
97
+ moveWindow(hwnd, nodeX, nodeY, nodeW, nodeH)
98
+
99
+ const children = getLayoutChildren(vnode)
100
+ if (children.length === 0) return
101
+
102
+ const isRow = dir === 'row'
103
+ const totalGap = gap * Math.max(0, children.length - 1)
104
+ const mainSize = (isRow ? nodeW : nodeH) - padding * 2 - totalGap
105
+ const crossSize = (isRow ? nodeH : nodeW) - padding * 2
106
+
107
+ let totalFlex = 0
108
+ let fixedMainTotal = 0
109
+ for (const child of children) {
110
+ const fg = child.style.flexGrow || 0
111
+ const fixedMain = isRow
112
+ ? resolveSize(child.style.width, mainSize)
113
+ : resolveSize(child.style.height, mainSize)
114
+ if (fg > 0) {
115
+ totalFlex += fg
116
+ } else if (fixedMain >= 0) {
117
+ fixedMainTotal += fixedMain
118
+ } else {
119
+ fixedMainTotal += getDefaultChildSize(child.vnode)
120
+ }
121
+ }
122
+
123
+ const flexUnit = totalFlex > 0 ? Math.max(0, mainSize - fixedMainTotal) / totalFlex : 0
124
+
125
+ let offset = 0
126
+ for (const child of children) {
127
+ const fg = child.style.flexGrow || 0
128
+ let childMain: number
129
+ if (fg > 0) {
130
+ childMain = Math.floor(fg * flexUnit)
131
+ } else {
132
+ const fixed = isRow
133
+ ? resolveSize(child.style.width, mainSize)
134
+ : resolveSize(child.style.height, mainSize)
135
+ childMain = fixed >= 0 ? fixed : getDefaultChildSize(child.vnode)
136
+ }
137
+
138
+ const childCross = isRow
139
+ ? resolveSize(child.style.height, crossSize)
140
+ : resolveSize(child.style.width, crossSize)
141
+ const actualCross = childCross >= 0 ? childCross : crossSize
142
+
143
+ const childMargin = Math.floor((child.style.margin || 0) * scaleFactor)
144
+ const relX = isRow ? padding + offset : padding + childMargin
145
+ const relY = isRow ? padding + childMargin : padding + offset
146
+ const cw = isRow ? childMain : actualCross - childMargin * 2
147
+ const ch = isRow ? actualCross - childMargin * 2 : childMain
148
+
149
+ moveWindow(child.hwnd, relX, relY, Math.max(cw, 0), Math.max(ch, 0))
150
+
151
+ if (isVNode(child.vnode) && child.vnode.type === 'w') {
152
+ layoutNode(child.hwnd, child.vnode, { x: relX, y: relY, w: Math.max(cw, 0), h: Math.max(ch, 0) })
153
+ }
154
+
155
+ offset += childMain + gap
156
+ }
157
+ }
158
+
159
+ function resolveToElementVNode(vnode: VNode): VNode | null {
160
+ if (!isVNode(vnode)) return null
161
+ if (vnode.type === 'w') return vnode
162
+ if (typeof vnode.type === 'function') {
163
+ const rendered = vnode[RENDERED_VNODE_PROP]
164
+ if (rendered && isVNode(rendered)) {
165
+ return resolveToElementVNode(rendered)
166
+ }
167
+ }
168
+ return null
169
+ }
170
+
171
+ export function layout(rootHwnd: number, vnode: any): void {
172
+ const clientSize = getClientSize(rootHwnd)
173
+ if (clientSize.w <= 0 || clientSize.h <= 0) return
174
+
175
+ const targetVNode = resolveToElementVNode(vnode)
176
+ if (!targetVNode) return
177
+
178
+ const targetHwnd = targetVNode[HWND_PROP] as number
179
+ if (!targetHwnd) return
180
+
181
+ moveWindow(targetHwnd, 0, 0, clientSize.w, clientSize.h)
182
+ layoutNode(targetHwnd, targetVNode, { x: 0, y: 0, w: clientSize.w, h: clientSize.h })
183
+ }
@@ -0,0 +1,54 @@
1
+ // Minimal Preact - VNode creation + Options
2
+ // Based on https://github.com/preactjs/preact (src/create-element.js, src/options.js, src/constants.js)
3
+ // DOM dependencies removed - for custom renderers only
4
+ let vnodeId = 0;
5
+ export const options = {};
6
+ export function createElement(type, props, ...children) {
7
+ let normalizedProps = {};
8
+ let key = null;
9
+ let ref = null;
10
+ if (props != null) {
11
+ for (const i in props) {
12
+ if (i === 'key')
13
+ key = props[i] ?? null;
14
+ else if (i === 'ref' && typeof type !== 'function')
15
+ ref = props[i] ?? null;
16
+ else
17
+ normalizedProps[i] = props[i];
18
+ }
19
+ }
20
+ if (children.length > 0) {
21
+ normalizedProps.children = children.length === 1 ? children[0] : children;
22
+ }
23
+ return createVNode(type, normalizedProps, key, ref, null);
24
+ }
25
+ export function createVNode(type, props, key, ref, original) {
26
+ const vnode = {
27
+ type,
28
+ props: props,
29
+ key,
30
+ ref,
31
+ _children: [],
32
+ _parent: null,
33
+ _depth: 0,
34
+ _dom: null,
35
+ _component: null,
36
+ constructor: undefined,
37
+ _original: original == null ? ++vnodeId : original,
38
+ _index: -1,
39
+ _flags: 0,
40
+ };
41
+ if (original == null && options.vnode)
42
+ options.vnode(vnode);
43
+ return vnode;
44
+ }
45
+ export function createRef() {
46
+ return { current: null };
47
+ }
48
+ export function Fragment(props) {
49
+ return props.children;
50
+ }
51
+ export function isValidElement(vnode) {
52
+ return vnode != null && vnode.constructor === undefined;
53
+ }
54
+ export const h = createElement;
@@ -0,0 +1,133 @@
1
+ // Minimal Preact - VNode creation + Options
2
+ // Based on https://github.com/preactjs/preact (src/create-element.js, src/options.js, src/constants.js)
3
+ // DOM dependencies removed - for custom renderers only
4
+
5
+ let vnodeId = 0
6
+
7
+ export type Key = string | number | null
8
+
9
+ export interface Ref<T = any> {
10
+ current: T | null
11
+ }
12
+
13
+ export type ComponentChild = VNode<any> | string | number | boolean | null | undefined
14
+ export type ComponentChildren = ComponentChild[] | ComponentChild
15
+
16
+ export type FunctionComponent<P = {}> = {
17
+ (props: P, context?: any): VNode<any> | null
18
+ defaultProps?: Partial<P>
19
+ displayName?: string
20
+ }
21
+
22
+ export type ComponentType<P = {}> = FunctionComponent<P>
23
+
24
+ export interface VNode<P = any> {
25
+ type: string | ComponentType<P>
26
+ props: P & { children?: ComponentChildren }
27
+ key: Key
28
+ ref: Ref<any>
29
+ _children: VNode[]
30
+ _parent: VNode | null
31
+ _depth: number
32
+ _dom: unknown
33
+ _component: Component<{}, {}> | null
34
+ constructor: undefined
35
+ _original: number
36
+ _index: number
37
+ _flags: number
38
+ _mask?: number[]
39
+ }
40
+
41
+ export interface Component<P = {}, S = {}> {
42
+ props: P
43
+ context: Record<string, unknown>
44
+ _vnode: VNode | null
45
+ _renderCallbacks: Array<() => void>
46
+ _parentDom: unknown
47
+ __hooks: { _list: any[]; _pendingEffects: any[] } | null
48
+ _forceUpdate(): void
49
+ }
50
+
51
+ export interface Options {
52
+ vnode?(vnode: VNode): void
53
+ _diff?(vnode: VNode): void
54
+ _render?(vnode: VNode): void
55
+ diffed?(vnode: VNode): void
56
+ _commit?(vnode: VNode, commitQueue: Component[]): void
57
+ unmount?(vnode: VNode): void
58
+ _root?(vnode: VNode, parentDom: unknown): void
59
+ _catchError?(error: unknown, vnode: VNode, oldVNode?: VNode): unknown
60
+ debounceRendering?(cb: () => void): void
61
+ requestAnimationFrame?: ((cb: () => void) => void) | null
62
+ useDebugValue?(value: unknown): void
63
+ _hook?(component: Component, index: number, type: number): void
64
+ _skipEffects?: boolean
65
+ }
66
+
67
+ export const options: Options = {}
68
+
69
+ export function createElement<P extends Record<string, any> = {}>(
70
+ type: string | ComponentType<P>,
71
+ props: (P & { key?: Key; ref?: Ref }) | null,
72
+ ...children: ComponentChildren[]
73
+ ): VNode<P> {
74
+ let normalizedProps: Record<string, any> = {}
75
+ let key: Key = null
76
+ let ref: Ref | null = null
77
+
78
+ if (props != null) {
79
+ for (const i in props) {
80
+ if (i === 'key') key = props[i] ?? null
81
+ else if (i === 'ref' && typeof type !== 'function') ref = props[i] ?? null
82
+ else normalizedProps[i] = props[i]
83
+ }
84
+ }
85
+
86
+ if (children.length > 0) {
87
+ normalizedProps.children = children.length === 1 ? children[0] : children
88
+ }
89
+
90
+ return createVNode(type, normalizedProps as P, key, ref!, null)
91
+ }
92
+
93
+ export function createVNode<P = {}>(
94
+ type: string | ComponentType<P>,
95
+ props: P,
96
+ key: Key,
97
+ ref: Ref,
98
+ original: number | null
99
+ ): VNode<P> {
100
+ const vnode: VNode<P> = {
101
+ type,
102
+ props: props as VNode<P>['props'],
103
+ key,
104
+ ref,
105
+ _children: [],
106
+ _parent: null,
107
+ _depth: 0,
108
+ _dom: null,
109
+ _component: null,
110
+ constructor: undefined,
111
+ _original: original == null ? ++vnodeId : original,
112
+ _index: -1,
113
+ _flags: 0,
114
+ }
115
+
116
+ if (original == null && options.vnode) options.vnode(vnode)
117
+
118
+ return vnode
119
+ }
120
+
121
+ export function createRef<T = null>(): Ref<T> {
122
+ return { current: null }
123
+ }
124
+
125
+ export function Fragment<P extends { children?: ComponentChildren }>(props: P): ComponentChildren {
126
+ return props.children
127
+ }
128
+
129
+ export function isValidElement(vnode: unknown): vnode is VNode {
130
+ return vnode != null && (vnode as any).constructor === undefined
131
+ }
132
+
133
+ export const h = createElement
@@ -0,0 +1,99 @@
1
+ import * as gui from 'gui';
2
+ import * as ffi from 'ffi';
3
+ import * as win from 'win';
4
+ const FFI_PTR = ffi.FFI_TYPE_POINTER;
5
+ const FFI_S32 = ffi.FFI_TYPE_SINT32;
6
+ const FFI_U32 = ffi.FFI_TYPE_UINT32;
7
+ const FFI_U64 = ffi.FFI_TYPE_UINT64;
8
+ const _user32 = win.LoadLibrary('user32.dll');
9
+ const MoveWindow_proc = _user32 ? win.GetProcAddress(_user32, 'MoveWindow') : 0;
10
+ const EnableWindow_proc = _user32 ? win.GetProcAddress(_user32, 'EnableWindow') : 0;
11
+ const ShowWindow_proc = _user32 ? win.GetProcAddress(_user32, 'ShowWindow') : 0;
12
+ const SendMessageW_proc = _user32 ? win.GetProcAddress(_user32, 'SendMessageW') : 0;
13
+ const DestroyWindow_proc = _user32 ? win.GetProcAddress(_user32, 'DestroyWindow') : 0;
14
+ const SW_HIDE = 0 /* gui.ShowWindowCmd.HIDE */;
15
+ const SW_SHOW = 5 /* gui.ShowWindowCmd.SHOW */;
16
+ const BM_GETCHECK = 240 /* gui.ButtonMsg.GETCHECK */;
17
+ const BM_SETCHECK = 241 /* gui.ButtonMsg.SETCHECK */;
18
+ const BST_CHECKED = 1 /* gui.ButtonCheckState.CHECKED */;
19
+ const BST_UNCHECKED = 0 /* gui.ButtonCheckState.UNCHECKED */;
20
+ const EM_SETCUEBANNER = 5377 /* gui.EditMsg.SETCUEBANNER */;
21
+ const EM_SETPASSWORDCHAR = 204 /* gui.EditMsg.SETPASSWORDCHAR */;
22
+ const CB_ADDSTRING = 323 /* gui.ComboBoxMsg.ADDSTRING */;
23
+ const LB_ADDSTRING = 384 /* gui.LbMsg.ADDSTRING */;
24
+ const PBM_SETRANGE32 = 1030 /* gui.ProgressMsg.SETRANGE32 */;
25
+ const PBM_SETPOS = 1026 /* gui.ProgressMsg.SETPOS */;
26
+ export function applyProps(hwnd, props, vnode) {
27
+ if (props.text !== undefined) {
28
+ gui.SetWindowText(hwnd, props.text);
29
+ }
30
+ if (props.value !== undefined) {
31
+ gui.SetWindowText(hwnd, props.value);
32
+ }
33
+ if (props.disabled !== undefined && EnableWindow_proc) {
34
+ ffi.ffiCall(EnableWindow_proc, [FFI_U64, FFI_U32], [hwnd, props.disabled ? 0 : 1], FFI_U32);
35
+ }
36
+ if (props.visible !== undefined && ShowWindow_proc) {
37
+ ffi.ffiCall(ShowWindow_proc, [FFI_U64, FFI_S32], [hwnd, props.visible ? SW_SHOW : SW_HIDE], FFI_U32);
38
+ }
39
+ if (props.onEvent !== undefined && vnode) {
40
+ const h = hwnd;
41
+ const oldProc = vnode._oldProc || gui.GetWindowLongPtr(h, -4 /* gui.Gwlp.WNDPROC */);
42
+ vnode._oldProc = oldProc;
43
+ gui.SetWindowProc(h, (hw, msg, wParam, lParam) => {
44
+ const cb = vnode.props?.onEvent;
45
+ if (cb)
46
+ cb({ hwnd: hw, msg, wParam, lParam });
47
+ return gui.CallWindowProc(oldProc, hw, msg, wParam, lParam);
48
+ });
49
+ }
50
+ if (props.placeholder !== undefined && SendMessageW_proc) {
51
+ ffi.ffiCall(SendMessageW_proc, [FFI_U64, FFI_S32, FFI_U32, FFI_PTR], [hwnd, EM_SETCUEBANNER, 0, strToWide(props.placeholder)], FFI_U64);
52
+ }
53
+ if (props.password !== undefined && SendMessageW_proc) {
54
+ ffi.ffiCall(SendMessageW_proc, [FFI_U64, FFI_U64, FFI_U64, FFI_U64], [hwnd, EM_SETPASSWORDCHAR, props.password ? 42 : 0, 0], FFI_U64);
55
+ }
56
+ if (props.checked !== undefined && SendMessageW_proc) {
57
+ ffi.ffiCall(SendMessageW_proc, [FFI_U64, FFI_U64, FFI_U64, FFI_U64], [hwnd, BM_SETCHECK, props.checked ? BST_CHECKED : BST_UNCHECKED, 0], FFI_U64);
58
+ }
59
+ if (props.items && SendMessageW_proc) {
60
+ const msg = props.type === 'combobox' ? CB_ADDSTRING : LB_ADDSTRING;
61
+ for (const item of props.items) {
62
+ ffi.ffiCall(SendMessageW_proc, [FFI_U64, FFI_S32, FFI_U32, FFI_PTR], [hwnd, msg, 0, strToWide(item)], FFI_U64);
63
+ }
64
+ }
65
+ if (props.max !== undefined && SendMessageW_proc) {
66
+ ffi.ffiCall(SendMessageW_proc, [FFI_U64, FFI_U64, FFI_U64, FFI_U64], [hwnd, PBM_SETRANGE32, 0, props.max], FFI_U64);
67
+ }
68
+ if (props.value !== undefined && props.type === 'progressbar' && SendMessageW_proc) {
69
+ ffi.ffiCall(SendMessageW_proc, [FFI_U64, FFI_U64, FFI_U64, FFI_U64], [hwnd, PBM_SETPOS, Number(props.value), 0], FFI_U64);
70
+ }
71
+ }
72
+ const wideCache = new Map();
73
+ const MAX_WIDE_CACHE = 50;
74
+ function strToWide(str) {
75
+ const cached = wideCache.get(str);
76
+ if (cached)
77
+ return cached;
78
+ const buf = new ArrayBuffer((str.length + 1) * 2);
79
+ const dv = new DataView(buf);
80
+ for (let i = 0; i < str.length; i++)
81
+ dv.setUint16(i * 2, str.charCodeAt(i), true);
82
+ if (wideCache.size >= MAX_WIDE_CACHE) {
83
+ const key = wideCache.keys().next().value;
84
+ if (key !== undefined)
85
+ wideCache.delete(key);
86
+ }
87
+ wideCache.set(str, buf);
88
+ return buf;
89
+ }
90
+ export function moveWindow(hwnd, x, y, w, h) {
91
+ if (!MoveWindow_proc)
92
+ return;
93
+ ffi.ffiCall(MoveWindow_proc, [FFI_U64, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32], [hwnd, x, y, w, h, 1], FFI_U32);
94
+ }
95
+ export function destroyWindow(hwnd) {
96
+ if (!DestroyWindow_proc)
97
+ return false;
98
+ return !!ffi.ffiCall(DestroyWindow_proc, [FFI_U64], [hwnd], FFI_U32);
99
+ }