nexfep 0.5.5 → 0.6.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.
package/README-CN.md CHANGED
@@ -41,7 +41,10 @@ import { Application } from "nexfep";
41
41
 
42
42
  const app = new Application();
43
43
 
44
- const window = await app.windows.createWindow(true, false);
44
+ const window = await app.windows.createWindow({
45
+ visible: true,
46
+ decoration: false,
47
+ });
45
48
 
46
49
  await window.loadHTML("<h1 nexfep-area-drag>Hello Nexfep!</h1>");
47
50
  ```
@@ -81,11 +84,37 @@ const app = new Application({ LogFilePath: "./app.log" });
81
84
  - `createLocker(appName)` — 创建应用实例锁,防止多个实例运行
82
85
  - `exit()` — 退出应用
83
86
 
87
+ ### Icon
88
+
89
+ `Icon` 用于表示图片资源,可被用作窗口图标、托盘图标等。
90
+
91
+ ```typescript
92
+ import { Icon } from "nexfep";
93
+
94
+ // 从文件路径创建
95
+ const icon = Icon.from("./icon.png");
96
+
97
+ // 从 Buffer 或 Uint8Array 创建
98
+ const icon = Icon.from(buffer);
99
+ const icon = Icon.from(uint8Array);
100
+
101
+ // 从包含 data/width/height 的对象创建
102
+ const icon = Icon.from({ data: buffer, width: 64, height: 64 });
103
+ const icon = Icon.from({ data: uint8Array, width: 64, height: 64 });
104
+ ```
105
+
106
+ **静态方法**
107
+
108
+ | 方法 | 参数 | 返回值 | 说明 |
109
+ | ------------------ | ----------------------------------------------------------------------------------------- | ------ | ---------------- |
110
+ | `Icon.from(input)` | `string` \| `Buffer` \| `Uint8Array` \| `{ data: Uint8Array \| Buffer, width?, height? }` | `Icon` | 创建一个图标实例 |
111
+
84
112
  ### Logger
85
113
 
86
114
  Logger 支持文件输出和彩色控制台输出,可通过 `app.logger` 访问。
87
115
 
88
116
  ```typescript
117
+ app.logger.clear();
89
118
  app.logger.log("Hello World");
90
119
  app.logger.error("发生错误");
91
120
  app.logger.warn("警告信息");
@@ -95,13 +124,14 @@ app.logger.debug("调试信息");
95
124
 
96
125
  **方法**
97
126
 
98
- | 方法 | 说明 |
99
- | ---------------- | -------------------- |
100
- | `log(message)` | 记录日志 |
101
- | `error(message)` | 记录错误日志(红色) |
102
- | `warn(message)` | 记录警告日志(黄色) |
103
- | `info(message)` | 记录提示日志(蓝色) |
104
- | `debug(message)` | 记录调试日志(灰色) |
127
+ | 方法 | 说明 |
128
+ | ---------------- | ------------------------------------------------- |
129
+ | `clear()` | 清空日志文件(仅在设置了`LogFilePath`参数时生效) |
130
+ | `log(message)` | 记录日志 |
131
+ | `error(message)` | 记录错误日志(红色) |
132
+ | `warn(message)` | 记录警告日志(黄色) |
133
+ | `info(message)` | 记录提示日志(蓝色) |
134
+ | `debug(message)` | 记录调试日志(灰色) |
105
135
 
106
136
  每个方法接受字符串或字符串数组作为参数。
107
137
 
@@ -145,16 +175,14 @@ locker.unlock();
145
175
  通过 `app.createTray()` 创建和管理系统托盘图标及右键菜单。
146
176
 
147
177
  ```typescript
148
- import { readFileSync } from "fs";
178
+ import { Icon } from "nexfep";
179
+
180
+ const icon = Icon.from("./icon.png");
149
181
 
150
182
  const tray = app.createTray({
151
183
  id: "my-tray",
152
184
  tooltip: "我的应用",
153
- icon: {
154
- data: readFileSync("./icon.png"),
155
- width: 32,
156
- height: 32,
157
- },
185
+ icon: icon, // Icon 实例
158
186
  menuItems: [
159
187
  { id: "show", label: "显示窗口" },
160
188
  { id: "quit", label: "退出" },
@@ -162,29 +190,19 @@ const tray = app.createTray({
162
190
  });
163
191
  ```
164
192
 
165
- `icon` 字段接受 `TrayIconImage` 对象:
166
-
167
- ```typescript
168
- interface TrayIconImage {
169
- data: Buffer; // 图片二进制数据
170
- width?: number; // 可选宽度
171
- height?: number; // 可选高度
172
- }
173
- ```
174
-
175
193
  **方法**
176
194
 
177
- | 方法 | 描述 |
178
- | -------------------------------- | ------------------------------------------------------ |
179
- | `addMenuItem(item)` | 添加菜单项 |
180
- | `removeMenuItem(id)` | 按 ID 删除菜单项 |
181
- | `setMenuItems(items)` | 替换所有菜单项 |
182
- | `setIcon(icon, width?, height?)` | 更改托盘图标(原始像素数据 `Uint8Array` / `number[]`) |
183
- | `setTooltip(tooltip)` | 更改悬停提示文本 |
184
- | `on(event, callback)` | 监听托盘事件(如 `'click'`) |
185
- | `show()` | 显示托盘图标 |
186
- | `hide()` | 隐藏托盘图标 |
187
- | `destroy()` | 销毁托盘图标 |
195
+ | 方法 | 描述 |
196
+ | --------------------- | ------------------------------ |
197
+ | `addMenuItem(item)` | 添加菜单项 |
198
+ | `removeMenuItem(id)` | 按 ID 删除菜单项 |
199
+ | `setMenuItems(items)` | 替换所有菜单项 |
200
+ | `setIcon(icon)` | 更改托盘图标,接受 `Icon` 实例 |
201
+ | `setTooltip(tooltip)` | 更改悬停提示文本 |
202
+ | `on(event, callback)` | 监听托盘事件(如 `'click'`) |
203
+ | `show()` | 显示托盘图标 |
204
+ | `hide()` | 隐藏托盘图标 |
205
+ | `destroy()` | 销毁托盘图标 |
188
206
 
189
207
  ```typescript
190
208
  tray.on("click", () => {
@@ -199,13 +217,14 @@ tray.setTooltip("Nexfep 应用");
199
217
  通过 `app.utils.notify()` 发送桌面通知。
200
218
 
201
219
  ```typescript
202
- const notification = app.utils.notify("标题", "通知内容");
220
+ const notification = app.utils.notify("标题", { body: "通知内容" });
203
221
  ```
204
222
 
205
223
  **参数**
206
224
 
207
225
  - `title` — 通知标题
208
- - `body`(可选)— 通知正文
226
+ - `options`(可选)— 配置对象
227
+ - `body` — 通知正文
209
228
 
210
229
  ### 窗口池
211
230
 
@@ -218,13 +237,38 @@ const pool = app.windows;
218
237
  ### 窗口创建
219
238
 
220
239
  ```typescript
221
- const win = await pool.createWindow(true, false);
240
+ // 不传参数使用全部默认值
241
+ const win = await pool.createWindow();
242
+
243
+ // 传入部分参数
244
+ const win = await pool.createWindow({
245
+ visible: true,
246
+ title: "我的应用",
247
+ });
248
+
249
+ // 全部参数
250
+ const win = await pool.createWindow({
251
+ visible: true, // 是否立即显示,默认 true
252
+ decoration: true, // 是否使用系统装饰,默认 true
253
+ title: "我的应用", // 窗口标题,默认 "Nexfep Window"
254
+ icon: iconInstance, // 窗口图标,Icon 实例,可选
255
+ resizable: true, // 是否可调整大小,默认 true
256
+ width: 800, // 窗口宽度,默认 800
257
+ height: 600, // 窗口高度,默认 600
258
+ });
222
259
  ```
223
260
 
224
261
  **参数说明**
225
262
 
226
- - `isShow`(布尔值,默认 `true`)— 是否立即显示窗口
227
- - `isDecorated`(布尔值,默认 `true`)— 是否使用系统窗口装饰。设为 `false` 时,窗口无边框,需要自定义标题栏
263
+ | 选项 | 类型 | 默认值 | 说明 |
264
+ | ------------ | --------- | ----------------- | ------------------------------------------------------------------- |
265
+ | `visible` | `boolean` | `true` | 是否立即显示窗口 |
266
+ | `decoration` | `boolean` | `true` | 是否使用系统窗口装饰。设为 `false` 时,窗口无边框,需要自定义标题栏 |
267
+ | `title` | `string` | `"Nexfep Window"` | 窗口标题 |
268
+ | `icon` | `Icon` | 无 | 窗口图标 |
269
+ | `resizable` | `boolean` | `true` | 窗口是否可调整大小 |
270
+ | `width` | `number` | `800` | 窗口宽度(像素) |
271
+ | `height` | `number` | `600` | 窗口高度(像素) |
228
272
 
229
273
  ### 窗口操作
230
274
 
@@ -586,44 +630,47 @@ nexfep build -u 7
586
630
 
587
631
  ### WindowPool
588
632
 
589
- | 方法/属性 | 参数 | 返回值 | 说明 |
590
- | ------------------------------------- | ------------------------------------------------------------------- | ----------------- | ------------------------ |
591
- | `createWindow(isShow?, isDecorated?)` | `isShow`: boolean(默认 true), `isDecorated`: boolean(默认 true) | Promise\<Window> | 创建并获取一个窗口 |
592
- | `handle(event, callback)` | `event`: string, `callback`: (data: any) => any | 无 | 监听指定事件 |
593
- | `unhandle(event, callback)` | `event`: string, `callback`: (data: any) => any | 无 | 取消监听指定事件 |
594
- | `global` | / | Map\<string, any> | 全局变量 Map |
595
- | `closeWindow(window)` | `window`: Window | Promise\<void> | 关闭指定窗口并回收至池中 |
596
- | `onCustomMessage` | `(window: Window, data: string) => void` | 无 | 自定义消息回调函数 |
633
+ | 方法/属性 | 参数 | 返回值 | 说明 |
634
+ | --------------------------- | ----------------------------------------------- | ----------------- | ------------------------ |
635
+ | `createWindow(options?)` | 可选参数,见上文窗口创建参数说明 | Promise\<Window> | 创建并获取一个窗口 |
636
+ | `handle(event, callback)` | `event`: string, `callback`: (data: any) => any | 无 | 监听指定事件 |
637
+ | `unhandle(event, callback)` | `event`: string, `callback`: (data: any) => any | 无 | 取消监听指定事件 |
638
+ | `global` | / | Map\<string, any> | 全局变量 Map |
639
+ | `closeWindow(window)` | `window`: Window | Promise\<void> | 关闭指定窗口并回收至池中 |
640
+ | `onCustomMessage` | `(window: Window, data: string) => void` | 无 | 自定义消息回调函数 |
597
641
 
598
642
  ### Window
599
643
 
600
- | 方法/属性 | 参数 | 返回值 | 说明 |
601
- | --------------------------- | --------------------------------- | --------------------------------- | -------------------------- |
602
- | `loadURL(url)` | `url`: string — 要加载的网页地址 | Promise\<void> | 加载指定 URL |
603
- | `loadHTML(html)` | `html`: string — HTML 字符串 | Promise\<void> | 加载指定 HTML 内容 |
604
- | `show()` | 无 | void | 显示窗口 |
605
- | `hide()` | 无 | void | 隐藏窗口 |
606
- | `maximize()` | 无 | void | 最大化窗口 |
607
- | `unMaximize()` | 无 | void | 还原窗口(取消最大化) |
608
- | `minimize()` | 无 | void | 最小化窗口 |
609
- | `unMinimize()` | 无 | void | 还原窗口(取消最小化) |
610
- | `close()` | 无 | void | 关闭窗口并回收至池中 |
611
- | `setTitle(title)` | `title`: string | void | 设置窗口标题 |
612
- | `setDecorated(isDecorated)` | `isDecorated`: boolean | void | 设置窗口是否带边框和标题栏 |
613
- | `resizable(resizable)` | `resizable`: boolean | void | 设置窗口是否可调整大小 |
614
- | `setSize(width, height)` | `width`: number, `height`: number | void | 设置窗口尺寸(像素) |
615
- | `getSize()` | 无 | { width: number, height: number } | 获取窗口尺寸(像素) |
616
- | `setPosition(x, y)` | `x`: number, `y`: number | void | 设置窗口位置(像素) |
617
- | `getPosition()` | 无 | { x: number, y: number } | 获取窗口位置(像素) |
618
- | `focus()` | 无 | void | 窗口获取焦点 |
619
- | `isFocused()` | 无 | boolean | 是否有焦点 |
620
- | `isMaximized()` | 无 | boolean | 是否最大化 |
621
- | `isMinimized()` | 无 | boolean | 是否最小化 |
622
- | `toggleMaximize()` | 无 | void | 切换最大化状态 |
623
- | `toggleMinimize()` | 无 | void | 切换最小化状态 |
624
- | `openDevTools()` | 无 | void | 打开开发者工具 |
625
- | `closeDevTools()` | 无 | void | 关闭开发者工具 |
626
- | `id` | 无 | number | 窗口唯一标识,自增编号 |
644
+ | 方法/属性 | 参数 | 返回值 | 说明 |
645
+ | --------------------------------------- | ----------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------- |
646
+ | `loadURL(url)` | `url`: string — 要加载的网页地址 | Promise\<void> | 加载指定 URL |
647
+ | `loadHTML(html)` | `html`: string — HTML 字符串 | Promise\<void> | 加载指定 HTML 内容 |
648
+ | `show()` | 无 | void | 显示窗口 |
649
+ | `hide()` | 无 | void | 隐藏窗口 |
650
+ | `maximize()` | 无 | void | 最大化窗口 |
651
+ | `unMaximize()` | 无 | void | 还原窗口(取消最大化) |
652
+ | `minimize()` | 无 | void | 最小化窗口 |
653
+ | `unMinimize()` | 无 | void | 还原窗口(取消最小化) |
654
+ | `close()` | 无 | void | 关闭窗口并回收至池中 |
655
+ | `setTitle(title)` | `title`: string | void | 设置窗口标题 |
656
+ | `setDecorated(isDecorated)` | `isDecorated`: boolean | void | 设置窗口是否带边框和标题栏 |
657
+ | `setResizable(resizable)` | `resizable`: boolean | void | 设置窗口是否可调整大小 |
658
+ | `setLevel(level)` | `level`: `-1` \| `0` \| `1` | void | 设置窗口层级:-1=置底,0=正常,1=置顶 |
659
+ | `setFullScreen(isFullScreen, options?)` | `isFullScreen`: `boolean`, `options?`: `{ borderless?: boolean }` | void | 设置全屏模式。`borderless: true` 为无边框全屏,否则为独占全屏 |
660
+ | `setIcon(icon)` | `icon`: `Icon` | void | 设置窗口图标 |
661
+ | `setSize(width, height)` | `width`: number, `height`: number | void | 设置窗口尺寸(像素) |
662
+ | `getSize()` | 无 | { width: number, height: number } | 获取窗口尺寸(像素) |
663
+ | `setPosition(x, y)` | `x`: number, `y`: number | void | 设置窗口位置(像素) |
664
+ | `getPosition()` | 无 | { x: number, y: number } | 获取窗口位置(像素) |
665
+ | `focus()` | 无 | void | 窗口获取焦点 |
666
+ | `isFocused()` | 无 | boolean | 是否有焦点 |
667
+ | `isMaximized()` | 无 | boolean | 是否最大化 |
668
+ | `isMinimized()` | 无 | boolean | 是否最小化 |
669
+ | `toggleMaximize()` | 无 | void | 切换最大化状态 |
670
+ | `toggleMinimize()` | 无 | void | 切换最小化状态 |
671
+ | `openDevTools()` | 无 | void | 打开开发者工具 |
672
+ | `closeDevTools()` | 无 | void | 关闭开发者工具 |
673
+ | `id` | 无 | number | 窗口唯一标识,自增编号 |
627
674
 
628
675
  ## 开发
629
676
 
package/README.md CHANGED
@@ -41,7 +41,10 @@ import { Application } from "nexfep";
41
41
 
42
42
  const app = new Application();
43
43
 
44
- const window = await app.windows.createWindow(true, false);
44
+ const window = await app.windows.createWindow({
45
+ visible: true,
46
+ decoration: false,
47
+ });
45
48
 
46
49
  await window.loadHTML("<h1 nexfep-area-drag>Hello Nexfep!</h1>");
47
50
  ```
@@ -81,11 +84,37 @@ const app = new Application({ LogFilePath: "./app.log" });
81
84
  - `createLocker(appName)` — Create an application instance lock to prevent multiple instances
82
85
  - `exit()` — Exit the application
83
86
 
87
+ ### Icon
88
+
89
+ `Icon` represents an image resource that can be used as a window icon, tray icon, etc.
90
+
91
+ ```typescript
92
+ import { Icon } from "nexfep";
93
+
94
+ // Create from file path
95
+ const icon = Icon.from("./icon.png");
96
+
97
+ // Create from Buffer or Uint8Array
98
+ const icon = Icon.from(buffer);
99
+ const icon = Icon.from(uint8Array);
100
+
101
+ // Create from an object containing data/width/height
102
+ const icon = Icon.from({ data: buffer, width: 64, height: 64 });
103
+ const icon = Icon.from({ data: uint8Array, width: 64, height: 64 });
104
+ ```
105
+
106
+ **Static Methods**
107
+
108
+ | Method | Parameters | Return Value | Description |
109
+ | ------------------ | ----------------------------------------------------------------------------------------- | ------------ | ------------------------ |
110
+ | `Icon.from(input)` | `string` \| `Buffer` \| `Uint8Array` \| `{ data: Uint8Array \| Buffer, width?, height? }` | `Icon` | Creates an icon instance |
111
+
84
112
  ### Logger
85
113
 
86
114
  The logger supports both file output and colored console output. It can be accessed via `app.logger`.
87
115
 
88
116
  ```typescript
117
+ app.logger.clear();
89
118
  app.logger.log("Hello World");
90
119
  app.logger.error("An error occurred");
91
120
  app.logger.warn("Warning message");
@@ -95,13 +124,14 @@ app.logger.debug("Debug message");
95
124
 
96
125
  **Methods**
97
126
 
98
- | Method | Description |
99
- | ---------------- | ------------------------------ |
100
- | `log(message)` | Log a message |
101
- | `error(message)` | Log an error message (red) |
102
- | `warn(message)` | Log a warning message (yellow) |
103
- | `info(message)` | Log an info message (blue) |
104
- | `debug(message)` | Log a debug message (gray) |
127
+ | Method | Description |
128
+ | ---------------- | ------------------------------------------------------------------------------ |
129
+ | `clear()` | Clear the log file (only takes effect when the `LogFilePath` parameter is set) |
130
+ | `log(message)` | Log a message |
131
+ | `error(message)` | Log an error message (red) |
132
+ | `warn(message)` | Log a warning message (yellow) |
133
+ | `info(message)` | Log an info message (blue) |
134
+ | `debug(message)` | Log a debug message (gray) |
105
135
 
106
136
  Each method accepts either a string or an array of strings.
107
137
 
@@ -143,16 +173,14 @@ locker.unlock();
143
173
  Create and manage system tray icons with context menus via `app.createTray()`.
144
174
 
145
175
  ```typescript
146
- import { readFileSync } from "fs";
176
+ import { Icon } from "nexfep";
177
+
178
+ const icon = Icon.from("./icon.png");
147
179
 
148
180
  const tray = app.createTray({
149
181
  id: "my-tray",
150
182
  tooltip: "My App",
151
- icon: {
152
- data: readFileSync("./icon.png"),
153
- width: 32,
154
- height: 32,
155
- },
183
+ icon: icon, // Icon instance
156
184
  menuItems: [
157
185
  { id: "show", label: "Show Window" },
158
186
  { id: "quit", label: "Quit" },
@@ -160,29 +188,19 @@ const tray = app.createTray({
160
188
  });
161
189
  ```
162
190
 
163
- The `icon` field accepts a `TrayIconImage` object:
164
-
165
- ```typescript
166
- interface TrayIconImage {
167
- data: Buffer; // Image binary data
168
- width?: number; // Optional width
169
- height?: number; // Optional height
170
- }
171
- ```
172
-
173
191
  **Methods**
174
192
 
175
- | Method | Description |
176
- | -------------------------------- | ------------------------------------------------------------------ |
177
- | `addMenuItem(item)` | Add a menu item |
178
- | `removeMenuItem(id)` | Remove a menu item by ID |
179
- | `setMenuItems(items)` | Replace all menu items |
180
- | `setIcon(icon, width?, height?)` | Change the tray icon (raw pixel data as `Uint8Array` / `number[]`) |
181
- | `setTooltip(tooltip)` | Change the tooltip text |
182
- | `on(event, callback)` | Listen for tray events (e.g. `'click'`) |
183
- | `show()` | Show the tray icon |
184
- | `hide()` | Hide the tray icon |
185
- | `destroy()` | Destroy the tray icon |
193
+ | Method | Description |
194
+ | --------------------- | ------------------------------------------------ |
195
+ | `addMenuItem(item)` | Add a menu item |
196
+ | `removeMenuItem(id)` | Remove a menu item by ID |
197
+ | `setMenuItems(items)` | Replace all menu items |
198
+ | `setIcon(icon)` | Change the tray icon, accepts an `Icon` instance |
199
+ | `setTooltip(tooltip)` | Change the tooltip text |
200
+ | `on(event, callback)` | Listen for tray events (e.g. `'click'`) |
201
+ | `show()` | Show the tray icon |
202
+ | `hide()` | Hide the tray icon |
203
+ | `destroy()` | Destroy the tray icon |
186
204
 
187
205
  ```typescript
188
206
  tray.on("click", () => {
@@ -197,13 +215,14 @@ tray.setTooltip("Nexfep App");
197
215
  Send desktop notifications via `app.utils.notify()`.
198
216
 
199
217
  ```typescript
200
- const notification = app.utils.notify("Title", "Notification body");
218
+ const notification = app.utils.notify("Title", { body: "Notification body" });
201
219
  ```
202
220
 
203
221
  **Parameters**
204
222
 
205
223
  - `title` — Notification title
206
- - `body` (optional) — Notification body text
224
+ - `options` (optional) — Configuration object
225
+ - `body` — Notification body text
207
226
 
208
227
  ### Window Pool
209
228
 
@@ -216,13 +235,38 @@ const pool = app.windows;
216
235
  ### Window Creation
217
236
 
218
237
  ```typescript
219
- const win = await pool.createWindow(true, false);
238
+ // Use all defaults by omitting parameters
239
+ const win = await pool.createWindow();
240
+
241
+ // Pass partial parameters
242
+ const win = await pool.createWindow({
243
+ visible: true,
244
+ title: "My App",
245
+ });
246
+
247
+ // All parameters
248
+ const win = await pool.createWindow({
249
+ visible: true, // Whether to show immediately, default true
250
+ decoration: true, // Whether to use system decorations, default true
251
+ title: "My App", // Window title, default "Nexfep Window"
252
+ icon: iconInstance, // Window icon, Icon instance, optional
253
+ resizable: true, // Whether the window is resizable, default true
254
+ width: 800, // Window width, default 800
255
+ height: 600, // Window height, default 600
256
+ });
220
257
  ```
221
258
 
222
259
  **Parameters**
223
260
 
224
- - `isShow` (boolean, default `true`) — Whether to immediately show the window
225
- - `isDecorated` (boolean, default `true`) — Whether to use system window decorations. When set to `false`, the window has no border and requires a custom title bar
261
+ | Option | Type | Default | Description |
262
+ | ------------ | --------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- |
263
+ | `visible` | `boolean` | `true` | Whether to immediately show the window |
264
+ | `decoration` | `boolean` | `true` | Whether to use system window decorations. When `false`, the window has no border and requires a custom title bar |
265
+ | `title` | `string` | `"Nexfep Window"` | Window title |
266
+ | `icon` | `Icon` | none | Window icon |
267
+ | `resizable` | `boolean` | `true` | Whether the window is resizable |
268
+ | `width` | `number` | `800` | Window width in pixels |
269
+ | `height` | `number` | `600` | Window height in pixels |
226
270
 
227
271
  ### Window Operations
228
272
 
@@ -584,44 +628,47 @@ Please do not include the outer `metadata` field, just the internal fields. Like
584
628
 
585
629
  ### WindowPool
586
630
 
587
- | Method/Property | Parameters | Return Value | Description |
588
- | ------------------------------------- | ----------------------------------------------------------------------- | ----------------- | ------------------------------------------------------ |
589
- | `createWindow(isShow?, isDecorated?)` | `isShow`: boolean (default true), `isDecorated`: boolean (default true) | Promise\<Window> | Creates and returns a window |
590
- | `handle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Listens for the specified event |
591
- | `unhandle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Removes the specified event listener |
592
- | `global` | / | Map\<string, any> | A global variable map |
593
- | `closeWindow(window)` | `window`: Window | Promise\<void> | Closes the specified window and returns it to the pool |
594
- | `onCustomMessage` | `(window: Window, data: string) => void` | None | Custom message callback |
631
+ | Method/Property | Parameters | Return Value | Description |
632
+ | --------------------------- | ------------------------------------------------------ | ----------------- | ------------------------------------------------------ |
633
+ | `createWindow(options?)` | Optional parameters, see Window Creation section above | Promise\<Window> | Creates and returns a window |
634
+ | `handle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Listens for the specified event |
635
+ | `unhandle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Removes the specified event listener |
636
+ | `global` | / | Map\<string, any> | A global variable map |
637
+ | `closeWindow(window)` | `window`: Window | Promise\<void> | Closes the specified window and returns it to the pool |
638
+ | `onCustomMessage` | `(window: Window, data: string) => void` | None | Custom message callback |
595
639
 
596
640
  ### Window
597
641
 
598
- | Method/Property | Parameters | Return Value | Description |
599
- | --------------------------- | --------------------------------- | --------------------------------- | ------------------------------------------------- |
600
- | `loadURL(url)` | `url`: string — URL to load | Promise\<void> | Loads the specified URL |
601
- | `loadHTML(html)` | `html`: string — HTML string | Promise\<void> | Loads the specified HTML content |
602
- | `show()` | None | void | Shows the window |
603
- | `hide()` | None | void | Hides the window |
604
- | `maximize()` | None | void | Maximizes the window |
605
- | `unMaximize()` | None | void | Restores the window (cancels maximize) |
606
- | `minimize()` | None | void | Minimizes the window |
607
- | `unMinimize()` | None | void | Restores the window (cancels minimize) |
608
- | `close()` | None | void | Closes the window and returns to pool |
609
- | `setTitle(title)` | `title`: string | void | Sets the window title |
610
- | `setDecorated(isDecorated)` | `isDecorated`: boolean | void | Sets whether the window has borders and title bar |
611
- | `resizable(resizable)` | `resizable`: boolean | void | Sets whether the window is resizable |
612
- | `setSize(width, height)` | `width`: number, `height`: number | void | Sets the window size in pixels |
613
- | `getSize()` | None | { width: number, height: number } | Gets the window size in pixels |
614
- | `setPosition(x, y)` | `x`: number, `y`: number | void | Sets the window position in pixels |
615
- | `getPosition()` | None | { x: number, y: number } | Gets the window position in pixels |
616
- | `isMaximized()` | None | boolean | Whether the window is maximized |
617
- | `isMinimized()` | None | boolean | Whether the window is minimized |
618
- | `toggleMaximize()` | None | void | Toggles the window maximized state |
619
- | `toggleMinimize()` | None | void | Toggles the window minimized state |
620
- | `isFocused()` | None | boolean | Whether the window has focused |
621
- | `focus()` | None | void | Focuses the window |
622
- | `openDevTools()` | None | void | Opens developer tools |
623
- | `closeDevTools()` | None | void | Closes developer tools |
624
- | `id` | None | number | Unique window identifier, auto-incrementing |
642
+ | Method/Property | Parameters | Return Value | Description |
643
+ | --------------------------------------- | ----------------------------------------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------- |
644
+ | `loadURL(url)` | `url`: string — URL to load | Promise\<void> | Loads the specified URL |
645
+ | `loadHTML(html)` | `html`: string — HTML string | Promise\<void> | Loads the specified HTML content |
646
+ | `show()` | None | void | Shows the window |
647
+ | `hide()` | None | void | Hides the window |
648
+ | `maximize()` | None | void | Maximizes the window |
649
+ | `unMaximize()` | None | void | Restores the window (cancels maximize) |
650
+ | `minimize()` | None | void | Minimizes the window |
651
+ | `unMinimize()` | None | void | Restores the window (cancels minimize) |
652
+ | `close()` | None | void | Closes the window and returns to pool |
653
+ | `setTitle(title)` | `title`: string | void | Sets the window title |
654
+ | `setDecorated(isDecorated)` | `isDecorated`: boolean | void | Sets whether the window has borders and title bar |
655
+ | `setResizable(resizable)` | `resizable`: boolean | void | Sets whether the window is resizable |
656
+ | `setLevel(level)` | `level`: `-1` \| `0` \| `1` | void | Sets window level: -1=bottom, 0=normal, 1=top |
657
+ | `setFullScreen(isFullScreen, options?)` | `isFullScreen`: `boolean`, `options?`: `{ borderless?: boolean }` | void | Sets fullscreen mode. `borderless: true` for borderless fullscreen, otherwise exclusive fullscreen |
658
+ | `setIcon(icon)` | `icon`: `Icon` | void | Sets the window icon |
659
+ | `setSize(width, height)` | `width`: number, `height`: number | void | Sets the window size in pixels |
660
+ | `getSize()` | None | { width: number, height: number } | Gets the window size in pixels |
661
+ | `setPosition(x, y)` | `x`: number, `y`: number | void | Sets the window position in pixels |
662
+ | `getPosition()` | None | { x: number, y: number } | Gets the window position in pixels |
663
+ | `focus()` | None | void | Focuses the window |
664
+ | `isFocused()` | None | boolean | Whether the window has focus |
665
+ | `isMaximized()` | None | boolean | Whether the window is maximized |
666
+ | `isMinimized()` | None | boolean | Whether the window is minimized |
667
+ | `toggleMaximize()` | None | void | Toggles the window maximized state |
668
+ | `toggleMinimize()` | None | void | Toggles the window minimized state |
669
+ | `openDevTools()` | None | void | Opens developer tools |
670
+ | `closeDevTools()` | None | void | Closes developer tools |
671
+ | `id` | None | number | Unique window identifier, auto-incrementing |
625
672
 
626
673
  ## Development
627
674
 
@@ -1,23 +1,23 @@
1
- export {}
1
+ export {};
2
2
 
3
3
  declare global {
4
4
  interface Window {
5
- tell: (to: number, message: string, data?: any) => void
6
- broadcast: (message: string, data?: any) => void
7
- invoke: (event: string, data?: any) => Promise<any>
8
- close: () => void
9
- minimize: () => void
10
- unminimize: () => void
11
- toggleMaximize: () => void
12
- toggleMinimize: () => void
13
- maximize: () => void
14
- unmaximize: () => void
15
- setTitle: (title: string) => void
16
- openDevTools: () => void
17
- closeDevTools: () => void
18
- setGlobal: (name: string, value: any) => void
19
- getGlobal: (name: string) => Promise<any>
20
- id: number
21
- isNexfepLoadDone: boolean
5
+ tell: (to: number, message: string, data?: any) => void;
6
+ broadcast: (message: string, data?: any) => void;
7
+ invoke: (event: string, data?: any) => Promise<any>;
8
+ close: () => void;
9
+ minimize: () => void;
10
+ unminimize: () => void;
11
+ toggleMaximize: () => void;
12
+ toggleMinimize: () => void;
13
+ maximize: () => void;
14
+ unmaximize: () => void;
15
+ setTitle: (title: string) => void;
16
+ openDevTools: () => void;
17
+ closeDevTools: () => void;
18
+ setGlobal: (name: string, value: any) => void;
19
+ getGlobal: (name: string) => Promise<any>;
20
+ id: number;
21
+ isNexfepLoadDone: boolean;
22
22
  }
23
- }
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexfep",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "A desktop application framework based on @webviewjs/webview",
5
5
  "keywords": [
6
6
  "@webviewjs/webview",
@@ -20,12 +20,6 @@
20
20
  "bin": {
21
21
  "nexfep": "cli/index.mjs"
22
22
  },
23
- "typesVersions": {
24
- "*": {
25
- ".": ["./index.d.ts"],
26
- "frontend": ["./frontend/index.d.ts"]
27
- }
28
- },
29
23
  "files": [
30
24
  "index.js",
31
25
  "index.d.ts",
@@ -47,10 +41,22 @@
47
41
  "src/Logger.d.ts",
48
42
  "src/SingleInstance.js",
49
43
  "src/SingleInstance.d.ts",
44
+ "src/Icon.js",
45
+ "src/Icon.d.ts",
50
46
  "frontend/index.d.ts"
51
47
  ],
52
48
  "type": "module",
53
49
  "main": "./index.js",
50
+ "typesVersions": {
51
+ "*": {
52
+ ".": [
53
+ "./index.d.ts"
54
+ ],
55
+ "frontend": [
56
+ "./frontend/index.d.ts"
57
+ ]
58
+ }
59
+ },
54
60
  "scripts": {
55
61
  "compile": "tsc",
56
62
  "fmt": "oxfmt --check",
@@ -1,12 +1,15 @@
1
- import { Application as WebviewApplication, TrayIconImage, Notification } from "@webviewjs/webview";
1
+ import { Application as WebviewApplication, Notification } from "@webviewjs/webview";
2
2
  import { WindowPool } from "./WindowManager.js";
3
3
  import { Tray } from "./Tray.js";
4
4
  import { Logger } from "./Logger.js";
5
5
  import { Locker } from "./SingleInstance.js";
6
+ import { Icon } from "./Icon.js";
6
7
  declare class __Utils {
7
8
  app: WebviewApplication;
8
9
  constructor(app: WebviewApplication);
9
- notify(title: string, body?: string): Notification;
10
+ notify(title: string, options?: {
11
+ body?: string;
12
+ }): Notification;
10
13
  }
11
14
  declare class Application {
12
15
  app: WebviewApplication;
@@ -20,7 +23,7 @@ declare class Application {
20
23
  createTray(options: {
21
24
  id: string;
22
25
  tooltip: string;
23
- icon: TrayIconImage | undefined;
26
+ icon?: Icon;
24
27
  menuItems: Array<{
25
28
  id: string;
26
29
  label: string;
@@ -29,4 +32,4 @@ declare class Application {
29
32
  createLocker(appName: string): Locker;
30
33
  exit(): void;
31
34
  }
32
- export { Application };
35
+ export { Application, Icon };
@@ -3,13 +3,14 @@ import { WindowPool } from "./WindowManager.js";
3
3
  import { Tray } from "./Tray.js";
4
4
  import { Logger } from "./Logger.js";
5
5
  import { Locker } from "./SingleInstance.js";
6
+ import { Icon } from "./Icon.js";
6
7
  class __Utils {
7
8
  app;
8
9
  constructor(app) {
9
10
  this.app = app;
10
11
  }
11
- notify(title, body) {
12
- const notification = new Notification(title, { body });
12
+ notify(title, options) {
13
+ const notification = new Notification(title, { body: options?.body });
13
14
  return notification;
14
15
  }
15
16
  }
@@ -39,4 +40,4 @@ class Application {
39
40
  this.app.exit();
40
41
  }
41
42
  }
42
- export { Application };
43
+ export { Application, Icon };
package/src/Icon.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { TrayIconImage } from "@webviewjs/webview";
2
+ declare class Icon {
3
+ data: Uint8Array;
4
+ width?: number;
5
+ height?: number;
6
+ constructor(data: Uint8Array, width?: number, height?: number);
7
+ static from(input: string | Buffer | Uint8Array | {
8
+ data: Uint8Array;
9
+ width?: number;
10
+ height?: number;
11
+ } | {
12
+ data: Buffer;
13
+ width?: number;
14
+ height?: number;
15
+ }): Icon;
16
+ toTrayIconImage(): TrayIconImage;
17
+ toBuffer(): Buffer;
18
+ }
19
+ export { Icon };
package/src/Icon.js ADDED
@@ -0,0 +1,36 @@
1
+ import fs from "fs";
2
+ class Icon {
3
+ data;
4
+ width;
5
+ height;
6
+ constructor(data, width, height) {
7
+ this.data = data;
8
+ this.width = width;
9
+ this.height = height;
10
+ }
11
+ static from(input) {
12
+ if (typeof input === "string") {
13
+ return new Icon(new Uint8Array(fs.readFileSync(input)));
14
+ }
15
+ else if (input instanceof Uint8Array) {
16
+ return new Icon(input);
17
+ }
18
+ else if (input instanceof Buffer) {
19
+ return new Icon(new Uint8Array(input));
20
+ }
21
+ else if (typeof input === "object" && input.data instanceof Uint8Array) {
22
+ return new Icon(input.data, input.width, input.height);
23
+ }
24
+ else if (typeof input === "object" && input.data instanceof Buffer) {
25
+ return new Icon(new Uint8Array(input.data), input.width, input.height);
26
+ }
27
+ throw new Error("Unsupported input type");
28
+ }
29
+ toTrayIconImage() {
30
+ return { data: Buffer.from(this.data), width: this.width, height: this.height };
31
+ }
32
+ toBuffer() {
33
+ return Buffer.from(this.data);
34
+ }
35
+ }
36
+ export { Icon };
package/src/Logger.d.ts CHANGED
@@ -8,5 +8,6 @@ declare class Logger {
8
8
  warn(args: string[] | string): void;
9
9
  info(args: string[] | string): void;
10
10
  debug(args: string[] | string): void;
11
+ clear(): void;
11
12
  }
12
13
  export { Logger };
package/src/Logger.js CHANGED
@@ -16,7 +16,6 @@ class Logger {
16
16
  let styleArgIndex = 1;
17
17
  let result = "";
18
18
  let currentAnsiStyle = "";
19
- // 命名前景色映射
20
19
  const fgColors = {
21
20
  black: "\x1b[30m",
22
21
  red: "\x1b[31m",
@@ -36,7 +35,6 @@ class Logger {
36
35
  lightcyan: "\x1b[96m",
37
36
  lightwhite: "\x1b[97m",
38
37
  };
39
- // 命名背景色映射
40
38
  const bgColors = {
41
39
  black: "\x1b[40m",
42
40
  red: "\x1b[41m",
@@ -47,7 +45,6 @@ class Logger {
47
45
  cyan: "\x1b[46m",
48
46
  white: "\x1b[47m",
49
47
  };
50
- // 文字样式:加粗、斜体、下划线
51
48
  const textStyles = {
52
49
  bold: "\x1b[1m",
53
50
  "font-weight:bold": "\x1b[1m",
@@ -57,14 +54,11 @@ class Logger {
57
54
  "text-decoration:underline": "\x1b[4m",
58
55
  none: RESET,
59
56
  };
60
- /** hex/rgb 转 ANSI 24位真彩色 */
61
57
  function colorToAnsi(colorVal, isBg = false) {
62
58
  let val = colorVal.trim().toLowerCase();
63
- // 命名色
64
59
  const colorMap = isBg ? bgColors : fgColors;
65
60
  if (colorMap[val])
66
61
  return colorMap[val];
67
- // hex #fff #ffffff
68
62
  const hexReg = /^#([0-9a-f]{3}|[0-9a-f]{6})$/;
69
63
  if (hexReg.test(val)) {
70
64
  let hex = val.replace("#", "");
@@ -78,7 +72,6 @@ class Logger {
78
72
  const b = parseInt(hex.slice(4, 6), 16);
79
73
  return isBg ? `\x1b[48;2;${r};${g};${b}m` : `\x1b[38;2;${r};${g};${b}m`;
80
74
  }
81
- // rgb(r,g,b)
82
75
  const rgbReg = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;
83
76
  const rgbMatch = val.match(rgbReg);
84
77
  if (rgbMatch) {
@@ -87,7 +80,6 @@ class Logger {
87
80
  }
88
81
  return "";
89
82
  }
90
- /** 解析CSS样式字符串为ANSI序列 */
91
83
  function parseColorStyle(styleStr) {
92
84
  if (!styleStr)
93
85
  return RESET;
@@ -100,17 +92,14 @@ class Logger {
100
92
  const [prop, ...rest] = rule.split(":");
101
93
  const propKey = prop.trim().toLowerCase();
102
94
  const value = rest.join(":").trim().toLowerCase();
103
- // 文字样式
104
95
  if (textStyles[`${propKey}:${value}`] || textStyles[value]) {
105
96
  ansi += textStyles[`${propKey}:${value}`] ?? textStyles[value];
106
97
  continue;
107
98
  }
108
- // 前景色
109
99
  if (propKey === "color") {
110
100
  ansi += colorToAnsi(value, false);
111
101
  continue;
112
102
  }
113
- // 背景色
114
103
  if (propKey === "background" || propKey === "background-color") {
115
104
  ansi += colorToAnsi(value, true);
116
105
  continue;
@@ -120,7 +109,6 @@ class Logger {
120
109
  }
121
110
  for (const segment of parts) {
122
111
  if (segment === "%c") {
123
- // 取出下一个样式参数,参数不足则重置样式
124
112
  const styleStr = args[styleArgIndex];
125
113
  styleArgIndex++;
126
114
  currentAnsiStyle = parseColorStyle(String(styleStr ?? ""));
@@ -136,10 +124,8 @@ class Logger {
136
124
  }
137
125
  }
138
126
  }
139
- // 全局末尾统一重置,防止后续日志被染色
140
127
  if (currentAnsiStyle)
141
128
  result += RESET;
142
- // 剩余非样式参数直接拼接
143
129
  const extraArgs = args.slice(styleArgIndex);
144
130
  if (extraArgs.length) {
145
131
  result += " " + extraArgs.map(String).join(" ");
@@ -192,5 +178,10 @@ class Logger {
192
178
  this.__printLog(0, "Debug", [args], "\x1b[90m", "\x1b[0m");
193
179
  }
194
180
  }
181
+ clear() {
182
+ if (this.logFilePath) {
183
+ fs.writeFileSync(this.logFilePath, "");
184
+ }
185
+ }
195
186
  }
196
187
  export { Logger };
package/src/Tray.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { Application, TrayIcon, TrayIconImage } from "@webviewjs/webview";
1
+ import { Application, TrayIcon } from "@webviewjs/webview";
2
+ import { Icon } from "./Icon.js";
2
3
  declare class Tray {
3
4
  app: Application;
4
5
  tray: TrayIcon;
@@ -10,7 +11,7 @@ declare class Tray {
10
11
  constructor(app: Application, options: {
11
12
  id: string;
12
13
  tooltip: string;
13
- icon: TrayIconImage | undefined;
14
+ icon?: Icon;
14
15
  menuItems: Array<{
15
16
  id: string;
16
17
  label: string;
@@ -26,7 +27,7 @@ declare class Tray {
26
27
  id: string;
27
28
  label: string;
28
29
  }>): void;
29
- setIcon(icon: Uint8Array<ArrayBuffer | SharedArrayBuffer> | number[], width?: number | null | undefined, height?: number | null | undefined): void;
30
+ setIcon(icon: Icon): void;
30
31
  on(event: string, callback: (event: any) => void): void;
31
32
  setTooltip(tooltip: string): void;
32
33
  hide(): void;
package/src/Tray.js CHANGED
@@ -10,7 +10,7 @@ class Tray {
10
10
  this.tray = app.createTrayIcon({
11
11
  id: options.id,
12
12
  tooltip: options.tooltip,
13
- icon: options.icon,
13
+ icon: options.icon?.toTrayIconImage(),
14
14
  menu: {
15
15
  items: this.menuItems,
16
16
  },
@@ -36,9 +36,9 @@ class Tray {
36
36
  this.menuItems = items;
37
37
  this.tray.setMenu({ items: this.menuItems });
38
38
  }
39
- setIcon(icon, width, height) {
39
+ setIcon(icon) {
40
40
  this.__ErrorWhenDestroyed();
41
- this.tray.setIcon(icon, width, height);
41
+ this.tray.setIcon(icon.data, icon.width, icon.height);
42
42
  }
43
43
  on(event, callback) {
44
44
  this.__ErrorWhenDestroyed();
@@ -1,5 +1,6 @@
1
1
  import { Application, BrowserWindow, Webview } from "@webviewjs/webview";
2
2
  import { Logger } from "./Logger.js";
3
+ import { Icon } from "./Icon.js";
3
4
  declare class Window {
4
5
  window: BrowserWindow;
5
6
  webview: Webview;
@@ -9,9 +10,13 @@ declare class Window {
9
10
  id: number;
10
11
  private myPool;
11
12
  constructor(window: BrowserWindow, webview: Webview, id: number, myPool: WindowPool);
13
+ setLevel(level: -1 | 0 | 1): void;
14
+ setFullScreen(isFullScreen: boolean, options?: {
15
+ borderless?: boolean;
16
+ }): void;
12
17
  setDecorated(isDecorated: boolean): void;
13
18
  setTitle(title: string): void;
14
- resizable(resizable: boolean): void;
19
+ setResizable(resizable: boolean): void;
15
20
  maximize(): void;
16
21
  minimize(): void;
17
22
  unMaximize(): void;
@@ -22,6 +27,7 @@ declare class Window {
22
27
  toggleMinimize(): void;
23
28
  openDevTools(): void;
24
29
  closeDevTools(): void;
30
+ setIcon(icon: Icon): void;
25
31
  setSize(width: number, height: number): void;
26
32
  getSize(): import("@webviewjs/webview").Dimensions;
27
33
  setPosition(x: number, y: number): void;
@@ -51,7 +57,15 @@ declare class WindowPool {
51
57
  __injectCode(window: Window, code: string): Promise<void>;
52
58
  __injectControlFunctions(windowObj: Window): Promise<void>;
53
59
  __createNewWindowObj(): Promise<Window>;
54
- createWindow(isShow?: boolean, isDecorated?: boolean): Promise<Window>;
60
+ createWindow(options?: {
61
+ visible?: boolean;
62
+ decoration?: boolean;
63
+ title?: string;
64
+ icon?: Icon;
65
+ resizable?: boolean;
66
+ width?: number;
67
+ height?: number;
68
+ }): Promise<Window>;
55
69
  closeWindow(window: Window): Promise<void>;
56
70
  handle(event: string, callback: (data: any) => any): Promise<void>;
57
71
  unhandle(event: string, callback: (data: any) => any): Promise<void>;
@@ -19,6 +19,36 @@ class Window {
19
19
  this.isDecorated = false;
20
20
  this.id = id;
21
21
  }
22
+ setLevel(level) {
23
+ if (level == -1) {
24
+ this.window.setAlwaysOnTop(false);
25
+ this.window.setAlwaysOnBottom(true);
26
+ return;
27
+ }
28
+ else if (level == 0) {
29
+ this.window.setAlwaysOnTop(false);
30
+ this.window.setAlwaysOnBottom(false);
31
+ return;
32
+ }
33
+ else if (level == 1) {
34
+ this.window.setAlwaysOnTop(true);
35
+ this.window.setAlwaysOnBottom(false);
36
+ return;
37
+ }
38
+ }
39
+ setFullScreen(isFullScreen, options) {
40
+ if (isFullScreen) {
41
+ if (options?.borderless) {
42
+ this.window.setFullscreen(1);
43
+ }
44
+ else {
45
+ this.window.setFullscreen(0);
46
+ }
47
+ }
48
+ else {
49
+ this.window.setFullscreen(null);
50
+ }
51
+ }
22
52
  setDecorated(isDecorated) {
23
53
  this.window.setDecorations(isDecorated);
24
54
  this.isDecorated = isDecorated;
@@ -26,7 +56,7 @@ class Window {
26
56
  setTitle(title) {
27
57
  this.window.setTitle(title);
28
58
  }
29
- resizable(resizable) {
59
+ setResizable(resizable) {
30
60
  this.window.setResizable(resizable);
31
61
  }
32
62
  maximize() {
@@ -69,6 +99,9 @@ class Window {
69
99
  closeDevTools() {
70
100
  this.webview.closeDevtools();
71
101
  }
102
+ setIcon(icon) {
103
+ this.window.setWindowIcon(icon.data, icon.width, icon.height);
104
+ }
72
105
  setSize(width, height) {
73
106
  this.window.setSize(width, height);
74
107
  }
@@ -325,7 +358,7 @@ class WindowPool {
325
358
  return await new Promise((resolve) => {
326
359
  setImmediate(() => {
327
360
  const window = this.app.createBrowserWindow({
328
- title: "Nexfep",
361
+ title: "Nexfep Window",
329
362
  visible: false,
330
363
  focused: false,
331
364
  });
@@ -444,16 +477,22 @@ class WindowPool {
444
477
  });
445
478
  });
446
479
  }
447
- async createWindow(isShow = true, isDecorated = true) {
480
+ async createWindow(options) {
448
481
  const window = this.windows.find((w) => w.isOpen === false) || (await this.__createNewWindowObj());
449
482
  this.freeWindowCount--;
450
483
  if (window) {
451
484
  window.isOpen = true;
452
- window.isShow = isShow;
453
- window.setDecorated(isDecorated);
454
- if (isShow) {
485
+ window.isShow = options?.visible ?? true;
486
+ window.setDecorated(options?.decoration ?? true);
487
+ if (options?.visible ?? true) {
455
488
  window.show();
456
489
  }
490
+ window.setTitle(options?.title ?? "Nexfep Window");
491
+ if (options?.icon) {
492
+ window.setIcon(options?.icon);
493
+ }
494
+ window.setResizable(options?.resizable ?? true);
495
+ window.setSize(options?.width ?? 800, options?.height ?? 600);
457
496
  }
458
497
  if (this.freeWindowCount == 0) {
459
498
  this.__createNewWindowObj();