defuss-desktop 0.0.2 → 0.0.3
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/dist/index.cjs +83 -77
- package/dist/index.d.cts +13 -13
- package/dist/index.d.mts +13 -13
- package/dist/index.mjs +83 -77
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -46,7 +46,9 @@ class WindowManager {
|
|
|
46
46
|
windows = [];
|
|
47
47
|
constructor() {
|
|
48
48
|
defuss.$(() => {
|
|
49
|
-
desktopManager
|
|
49
|
+
if (desktopManager?.onResize) {
|
|
50
|
+
desktopManager.onResize(defussRuntime.debounce(this.onDesktopResized.bind(this), 50));
|
|
51
|
+
}
|
|
50
52
|
});
|
|
51
53
|
}
|
|
52
54
|
onDesktopResized(dimensions) {
|
|
@@ -290,6 +292,11 @@ function Window({
|
|
|
290
292
|
}
|
|
291
293
|
}) {
|
|
292
294
|
let isDragging = false;
|
|
295
|
+
let dragPointerId = null;
|
|
296
|
+
let dragStartMouse = { x: 0, y: 0 };
|
|
297
|
+
let dragStartWin = { x: 0, y: 0 };
|
|
298
|
+
let lastWin = { x, y };
|
|
299
|
+
let capturedTitleBar = null;
|
|
293
300
|
const initialWindowState = windowManager.addWindow({
|
|
294
301
|
id,
|
|
295
302
|
title,
|
|
@@ -301,7 +308,7 @@ function Window({
|
|
|
301
308
|
minimizable,
|
|
302
309
|
maximizable
|
|
303
310
|
});
|
|
304
|
-
|
|
311
|
+
lastWin = { x: initialWindowState.x, y: initialWindowState.y };
|
|
305
312
|
ref.state = {
|
|
306
313
|
onClose: () => {
|
|
307
314
|
console.log("Window closed");
|
|
@@ -315,15 +322,9 @@ function Window({
|
|
|
315
322
|
console.log("Window maximized");
|
|
316
323
|
onMaximize();
|
|
317
324
|
},
|
|
318
|
-
minimize: () =>
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
maximize: () => {
|
|
322
|
-
windowManager.maximizeWindow(initialWindowState.id);
|
|
323
|
-
},
|
|
324
|
-
restore: () => {
|
|
325
|
-
windowManager.restoreWindow(initialWindowState.id);
|
|
326
|
-
},
|
|
325
|
+
minimize: () => windowManager.minimizeWindow(initialWindowState.id),
|
|
326
|
+
maximize: () => windowManager.maximizeWindow(initialWindowState.id),
|
|
327
|
+
restore: () => windowManager.restoreWindow(initialWindowState.id),
|
|
327
328
|
close: () => {
|
|
328
329
|
console.log("Closing window");
|
|
329
330
|
windowManager.closeWindow(initialWindowState.id);
|
|
@@ -334,45 +335,67 @@ function Window({
|
|
|
334
335
|
windowManager.updateWindow(initialWindowState.id, newState);
|
|
335
336
|
},
|
|
336
337
|
250
|
|
337
|
-
// 1/4 second throttle
|
|
338
338
|
);
|
|
339
|
-
const
|
|
339
|
+
const onWindowMouseDown = (_event) => windowManager.setActiveWindow(initialWindowState.id);
|
|
340
|
+
const getCurrentWinPos = () => {
|
|
341
|
+
const el = ref.current;
|
|
342
|
+
if (!el) return { x: lastWin.x, y: lastWin.y };
|
|
343
|
+
const left = Number.parseFloat(el.style.left);
|
|
344
|
+
const top = Number.parseFloat(el.style.top);
|
|
345
|
+
return {
|
|
346
|
+
x: Number.isFinite(left) ? left : el.offsetLeft,
|
|
347
|
+
y: Number.isFinite(top) ? top : el.offsetTop
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
const stopDragging = (event) => {
|
|
340
351
|
if (!isDragging) return;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (currentOffset) {
|
|
347
|
-
const newX = currentOffset.left + deltaX;
|
|
348
|
-
const newY = currentOffset.top + deltaY;
|
|
349
|
-
updateWindowState({ x: newX, y: newY });
|
|
350
|
-
await win.css({
|
|
351
|
-
left: `${newX}px`,
|
|
352
|
-
top: `${newY}px`
|
|
353
|
-
});
|
|
352
|
+
if (event && capturedTitleBar && typeof capturedTitleBar.releasePointerCapture === "function" && dragPointerId === event.pointerId) {
|
|
353
|
+
try {
|
|
354
|
+
capturedTitleBar.releasePointerCapture(event.pointerId);
|
|
355
|
+
} catch {
|
|
356
|
+
}
|
|
354
357
|
}
|
|
355
|
-
|
|
358
|
+
isDragging = false;
|
|
359
|
+
dragPointerId = null;
|
|
360
|
+
capturedTitleBar = null;
|
|
361
|
+
windowManager.updateWindow(initialWindowState.id, { x: lastWin.x, y: lastWin.y });
|
|
356
362
|
};
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
+
const onTitlePointerDown = (event) => {
|
|
364
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
365
|
+
const target = event.target;
|
|
366
|
+
if (target?.tagName === "BUTTON") return;
|
|
367
|
+
const titleBarEl = target?.closest?.(".title-bar");
|
|
368
|
+
if (!titleBarEl) return;
|
|
369
|
+
windowManager.setActiveWindow(initialWindowState.id);
|
|
363
370
|
isDragging = true;
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
371
|
+
dragPointerId = event.pointerId;
|
|
372
|
+
capturedTitleBar = titleBarEl;
|
|
373
|
+
dragStartMouse = { x: event.clientX, y: event.clientY };
|
|
374
|
+
dragStartWin = getCurrentWinPos();
|
|
375
|
+
if (typeof titleBarEl.setPointerCapture === "function") {
|
|
376
|
+
titleBarEl.setPointerCapture(event.pointerId);
|
|
377
|
+
}
|
|
370
378
|
event.preventDefault();
|
|
371
379
|
};
|
|
372
|
-
const
|
|
373
|
-
isDragging
|
|
374
|
-
|
|
375
|
-
|
|
380
|
+
const onTitlePointerMove = (event) => {
|
|
381
|
+
if (!isDragging) return;
|
|
382
|
+
if (dragPointerId !== null && event.pointerId !== dragPointerId) return;
|
|
383
|
+
const newX = dragStartWin.x + (event.clientX - dragStartMouse.x);
|
|
384
|
+
const newY = dragStartWin.y + (event.clientY - dragStartMouse.y);
|
|
385
|
+
lastWin = { x: newX, y: newY };
|
|
386
|
+
const el = ref.current;
|
|
387
|
+
if (el) {
|
|
388
|
+
el.style.left = `${newX}px`;
|
|
389
|
+
el.style.top = `${newY}px`;
|
|
390
|
+
}
|
|
391
|
+
updateWindowState({ x: newX, y: newY });
|
|
392
|
+
event.preventDefault();
|
|
393
|
+
};
|
|
394
|
+
const onTitlePointerUp = (event) => {
|
|
395
|
+
stopDragging(event);
|
|
396
|
+
};
|
|
397
|
+
const onTitlePointerCancel = (event) => {
|
|
398
|
+
stopDragging(event);
|
|
376
399
|
};
|
|
377
400
|
const onWindowMounted = () => {
|
|
378
401
|
windowManager.updateWindow(initialWindowState.id, {
|
|
@@ -380,17 +403,18 @@ function Window({
|
|
|
380
403
|
ref
|
|
381
404
|
});
|
|
382
405
|
windowManager.setActiveWindow(initialWindowState.id);
|
|
406
|
+
defuss.$(document).on("blur", () => stopDragging());
|
|
407
|
+
defuss.$(document).on("visibilitychange", () => {
|
|
408
|
+
if (document.hidden) stopDragging();
|
|
409
|
+
});
|
|
383
410
|
};
|
|
384
411
|
const onCloseClick = () => windowManager.closeWindow(initialWindowState.id);
|
|
385
|
-
const onMaximizeClick =
|
|
412
|
+
const onMaximizeClick = () => {
|
|
386
413
|
const currentState = windowManager.getWindow(initialWindowState.id);
|
|
387
|
-
if (currentState?.maximized)
|
|
388
|
-
|
|
389
|
-
} else {
|
|
390
|
-
windowManager.maximizeWindow(initialWindowState.id);
|
|
391
|
-
}
|
|
414
|
+
if (currentState?.maximized) windowManager.restoreWindow(initialWindowState.id);
|
|
415
|
+
else windowManager.maximizeWindow(initialWindowState.id);
|
|
392
416
|
};
|
|
393
|
-
const onMinimizeClick =
|
|
417
|
+
const onMinimizeClick = () => {
|
|
394
418
|
windowManager.minimizeWindow(initialWindowState.id);
|
|
395
419
|
};
|
|
396
420
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -412,36 +436,18 @@ function Window({
|
|
|
412
436
|
{
|
|
413
437
|
class: "title-bar",
|
|
414
438
|
onMount: onWindowMounted,
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
439
|
+
onPointerDown: onTitlePointerDown,
|
|
440
|
+
onPointerMove: onTitlePointerMove,
|
|
441
|
+
onPointerUp: onTitlePointerUp,
|
|
442
|
+
onPointerCancel: onTitlePointerCancel,
|
|
443
|
+
onDblClick: onMaximizeClick,
|
|
444
|
+
style: { touchAction: "none" },
|
|
418
445
|
children: [
|
|
419
446
|
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "title-bar-text", children: title }),
|
|
420
447
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { class: "title-bar-controls", children: [
|
|
421
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
type: "button",
|
|
425
|
-
"aria-label": "Minimize",
|
|
426
|
-
onClick: onMinimizeClick
|
|
427
|
-
}
|
|
428
|
-
),
|
|
429
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
430
|
-
"button",
|
|
431
|
-
{
|
|
432
|
-
type: "button",
|
|
433
|
-
"aria-label": "Maximize",
|
|
434
|
-
onClick: onMaximizeClick
|
|
435
|
-
}
|
|
436
|
-
),
|
|
437
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
438
|
-
"button",
|
|
439
|
-
{
|
|
440
|
-
type: "button",
|
|
441
|
-
"aria-label": "Close",
|
|
442
|
-
onClick: onCloseClick
|
|
443
|
-
}
|
|
444
|
-
)
|
|
448
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-label": "Minimize", onClick: onMinimizeClick }),
|
|
449
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-label": "Maximize", onClick: onMaximizeClick }),
|
|
450
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-label": "Close", onClick: onCloseClick })
|
|
445
451
|
] })
|
|
446
452
|
]
|
|
447
453
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as defuss from 'defuss';
|
|
2
|
-
import { Props, CallChainImpl, Dequery,
|
|
2
|
+
import { Props, CallChainImpl, Dequery, Ref } from 'defuss';
|
|
3
3
|
|
|
4
|
-
declare function Desktop({ ref }: Props):
|
|
4
|
+
declare function Desktop({ ref }: Props<HTMLDivElement>): JSX.Element;
|
|
5
5
|
|
|
6
|
-
interface ButtonProps extends Props {
|
|
6
|
+
interface ButtonProps extends Props<HTMLButtonElement> {
|
|
7
7
|
onClick?: () => void;
|
|
8
8
|
disabled?: boolean;
|
|
9
9
|
}
|
|
10
|
-
declare function Button({ onClick, disabled, children, ref, }: ButtonProps):
|
|
10
|
+
declare function Button({ onClick, disabled, children, ref, }: ButtonProps): JSX.Element;
|
|
11
11
|
|
|
12
|
-
interface LogonScreenProps extends Props {
|
|
12
|
+
interface LogonScreenProps extends Props<HTMLDivElement> {
|
|
13
13
|
cDriveBasePath?: string;
|
|
14
14
|
showGuestUser?: boolean;
|
|
15
15
|
onTurnOffComputer?: () => void;
|
|
@@ -20,7 +20,7 @@ type LoginForm = {
|
|
|
20
20
|
username: string;
|
|
21
21
|
password: string;
|
|
22
22
|
};
|
|
23
|
-
declare const LogonScreen: ({ cDriveBasePath, showGuestUser, onTurnOffComputer, onGuestLogon, onUserLogonSubmit, ref, }: LogonScreenProps) =>
|
|
23
|
+
declare const LogonScreen: ({ cDriveBasePath, showGuestUser, onTurnOffComputer, onGuestLogon, onUserLogonSubmit, ref, }: LogonScreenProps) => JSX.Element;
|
|
24
24
|
|
|
25
25
|
interface DefussAppConfig {
|
|
26
26
|
name: string;
|
|
@@ -85,16 +85,16 @@ declare class DesktopManager {
|
|
|
85
85
|
}
|
|
86
86
|
declare const desktopManager: DesktopManager;
|
|
87
87
|
|
|
88
|
-
interface ShellProps extends Props {
|
|
88
|
+
interface ShellProps extends Props<HTMLDivElement> {
|
|
89
89
|
desktopConfig: CreateDesktopOptions;
|
|
90
90
|
}
|
|
91
|
-
declare function Shell({ ref, desktopConfig, }: ShellProps):
|
|
91
|
+
declare function Shell({ ref, desktopConfig, }: ShellProps): JSX.Element;
|
|
92
92
|
|
|
93
|
-
declare const Taskbar: () =>
|
|
93
|
+
declare const Taskbar: () => JSX.Element;
|
|
94
94
|
|
|
95
|
-
declare const StartButton: () =>
|
|
95
|
+
declare const StartButton: () => JSX.Element;
|
|
96
96
|
|
|
97
|
-
declare const StartMenu: () =>
|
|
97
|
+
declare const StartMenu: () => JSX.Element;
|
|
98
98
|
|
|
99
99
|
declare class DequeryWithWindowManager<NT> extends CallChainImpl<NT, DequeryWithWindowManager<NT> & Dequery<NT>> {
|
|
100
100
|
createDesktopApp(options: DefussAppConfig): PromiseLike<DefussApp>;
|
|
@@ -107,7 +107,7 @@ declare class DequeryWithWindowManager<NT> extends CallChainImpl<NT, DequeryWith
|
|
|
107
107
|
* @param options - Optional dequery options
|
|
108
108
|
* @returns Extended dequery instance with createWindow and createTaskbar methods
|
|
109
109
|
*/
|
|
110
|
-
declare const $: <NT = defuss.
|
|
110
|
+
declare const $: <NT = defuss.NodeType>(selectorRefOrEl: string | defuss.NodeType | defuss.Ref<defuss.NodeType, any> | defuss.RenderInput | Function, options?: (defuss.DequeryOptions<NT> & JSX.HTMLAttributesLowerCase<defuss.DOMElement> & JSX.HTMLAttributesLowerCase<defuss.DOMElement> & {
|
|
111
111
|
html?: string;
|
|
112
112
|
text?: string;
|
|
113
113
|
}) | undefined) => DequeryWithWindowManager<unknown>;
|
|
@@ -142,7 +142,7 @@ interface CreateWindowOptions {
|
|
|
142
142
|
interface WindowState {
|
|
143
143
|
id: string;
|
|
144
144
|
el: HTMLElement;
|
|
145
|
-
ref: Ref<WindowRefState>;
|
|
145
|
+
ref: Ref<HTMLElement, WindowRefState>;
|
|
146
146
|
title: string;
|
|
147
147
|
icon: string;
|
|
148
148
|
width: number;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as defuss from 'defuss';
|
|
2
|
-
import { Props, CallChainImpl, Dequery,
|
|
2
|
+
import { Props, CallChainImpl, Dequery, Ref } from 'defuss';
|
|
3
3
|
|
|
4
|
-
declare function Desktop({ ref }: Props):
|
|
4
|
+
declare function Desktop({ ref }: Props<HTMLDivElement>): JSX.Element;
|
|
5
5
|
|
|
6
|
-
interface ButtonProps extends Props {
|
|
6
|
+
interface ButtonProps extends Props<HTMLButtonElement> {
|
|
7
7
|
onClick?: () => void;
|
|
8
8
|
disabled?: boolean;
|
|
9
9
|
}
|
|
10
|
-
declare function Button({ onClick, disabled, children, ref, }: ButtonProps):
|
|
10
|
+
declare function Button({ onClick, disabled, children, ref, }: ButtonProps): JSX.Element;
|
|
11
11
|
|
|
12
|
-
interface LogonScreenProps extends Props {
|
|
12
|
+
interface LogonScreenProps extends Props<HTMLDivElement> {
|
|
13
13
|
cDriveBasePath?: string;
|
|
14
14
|
showGuestUser?: boolean;
|
|
15
15
|
onTurnOffComputer?: () => void;
|
|
@@ -20,7 +20,7 @@ type LoginForm = {
|
|
|
20
20
|
username: string;
|
|
21
21
|
password: string;
|
|
22
22
|
};
|
|
23
|
-
declare const LogonScreen: ({ cDriveBasePath, showGuestUser, onTurnOffComputer, onGuestLogon, onUserLogonSubmit, ref, }: LogonScreenProps) =>
|
|
23
|
+
declare const LogonScreen: ({ cDriveBasePath, showGuestUser, onTurnOffComputer, onGuestLogon, onUserLogonSubmit, ref, }: LogonScreenProps) => JSX.Element;
|
|
24
24
|
|
|
25
25
|
interface DefussAppConfig {
|
|
26
26
|
name: string;
|
|
@@ -85,16 +85,16 @@ declare class DesktopManager {
|
|
|
85
85
|
}
|
|
86
86
|
declare const desktopManager: DesktopManager;
|
|
87
87
|
|
|
88
|
-
interface ShellProps extends Props {
|
|
88
|
+
interface ShellProps extends Props<HTMLDivElement> {
|
|
89
89
|
desktopConfig: CreateDesktopOptions;
|
|
90
90
|
}
|
|
91
|
-
declare function Shell({ ref, desktopConfig, }: ShellProps):
|
|
91
|
+
declare function Shell({ ref, desktopConfig, }: ShellProps): JSX.Element;
|
|
92
92
|
|
|
93
|
-
declare const Taskbar: () =>
|
|
93
|
+
declare const Taskbar: () => JSX.Element;
|
|
94
94
|
|
|
95
|
-
declare const StartButton: () =>
|
|
95
|
+
declare const StartButton: () => JSX.Element;
|
|
96
96
|
|
|
97
|
-
declare const StartMenu: () =>
|
|
97
|
+
declare const StartMenu: () => JSX.Element;
|
|
98
98
|
|
|
99
99
|
declare class DequeryWithWindowManager<NT> extends CallChainImpl<NT, DequeryWithWindowManager<NT> & Dequery<NT>> {
|
|
100
100
|
createDesktopApp(options: DefussAppConfig): PromiseLike<DefussApp>;
|
|
@@ -107,7 +107,7 @@ declare class DequeryWithWindowManager<NT> extends CallChainImpl<NT, DequeryWith
|
|
|
107
107
|
* @param options - Optional dequery options
|
|
108
108
|
* @returns Extended dequery instance with createWindow and createTaskbar methods
|
|
109
109
|
*/
|
|
110
|
-
declare const $: <NT = defuss.
|
|
110
|
+
declare const $: <NT = defuss.NodeType>(selectorRefOrEl: string | defuss.NodeType | defuss.Ref<defuss.NodeType, any> | defuss.RenderInput | Function, options?: (defuss.DequeryOptions<NT> & JSX.HTMLAttributesLowerCase<defuss.DOMElement> & JSX.HTMLAttributesLowerCase<defuss.DOMElement> & {
|
|
111
111
|
html?: string;
|
|
112
112
|
text?: string;
|
|
113
113
|
}) | undefined) => DequeryWithWindowManager<unknown>;
|
|
@@ -142,7 +142,7 @@ interface CreateWindowOptions {
|
|
|
142
142
|
interface WindowState {
|
|
143
143
|
id: string;
|
|
144
144
|
el: HTMLElement;
|
|
145
|
-
ref: Ref<WindowRefState>;
|
|
145
|
+
ref: Ref<HTMLElement, WindowRefState>;
|
|
146
146
|
title: string;
|
|
147
147
|
icon: string;
|
|
148
148
|
width: number;
|
package/dist/index.mjs
CHANGED
|
@@ -44,7 +44,9 @@ class WindowManager {
|
|
|
44
44
|
windows = [];
|
|
45
45
|
constructor() {
|
|
46
46
|
$$1(() => {
|
|
47
|
-
desktopManager
|
|
47
|
+
if (desktopManager?.onResize) {
|
|
48
|
+
desktopManager.onResize(debounce(this.onDesktopResized.bind(this), 50));
|
|
49
|
+
}
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
onDesktopResized(dimensions) {
|
|
@@ -288,6 +290,11 @@ function Window({
|
|
|
288
290
|
}
|
|
289
291
|
}) {
|
|
290
292
|
let isDragging = false;
|
|
293
|
+
let dragPointerId = null;
|
|
294
|
+
let dragStartMouse = { x: 0, y: 0 };
|
|
295
|
+
let dragStartWin = { x: 0, y: 0 };
|
|
296
|
+
let lastWin = { x, y };
|
|
297
|
+
let capturedTitleBar = null;
|
|
291
298
|
const initialWindowState = windowManager.addWindow({
|
|
292
299
|
id,
|
|
293
300
|
title,
|
|
@@ -299,7 +306,7 @@ function Window({
|
|
|
299
306
|
minimizable,
|
|
300
307
|
maximizable
|
|
301
308
|
});
|
|
302
|
-
|
|
309
|
+
lastWin = { x: initialWindowState.x, y: initialWindowState.y };
|
|
303
310
|
ref.state = {
|
|
304
311
|
onClose: () => {
|
|
305
312
|
console.log("Window closed");
|
|
@@ -313,15 +320,9 @@ function Window({
|
|
|
313
320
|
console.log("Window maximized");
|
|
314
321
|
onMaximize();
|
|
315
322
|
},
|
|
316
|
-
minimize: () =>
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
maximize: () => {
|
|
320
|
-
windowManager.maximizeWindow(initialWindowState.id);
|
|
321
|
-
},
|
|
322
|
-
restore: () => {
|
|
323
|
-
windowManager.restoreWindow(initialWindowState.id);
|
|
324
|
-
},
|
|
323
|
+
minimize: () => windowManager.minimizeWindow(initialWindowState.id),
|
|
324
|
+
maximize: () => windowManager.maximizeWindow(initialWindowState.id),
|
|
325
|
+
restore: () => windowManager.restoreWindow(initialWindowState.id),
|
|
325
326
|
close: () => {
|
|
326
327
|
console.log("Closing window");
|
|
327
328
|
windowManager.closeWindow(initialWindowState.id);
|
|
@@ -332,45 +333,67 @@ function Window({
|
|
|
332
333
|
windowManager.updateWindow(initialWindowState.id, newState);
|
|
333
334
|
},
|
|
334
335
|
250
|
|
335
|
-
// 1/4 second throttle
|
|
336
336
|
);
|
|
337
|
-
const
|
|
337
|
+
const onWindowMouseDown = (_event) => windowManager.setActiveWindow(initialWindowState.id);
|
|
338
|
+
const getCurrentWinPos = () => {
|
|
339
|
+
const el = ref.current;
|
|
340
|
+
if (!el) return { x: lastWin.x, y: lastWin.y };
|
|
341
|
+
const left = Number.parseFloat(el.style.left);
|
|
342
|
+
const top = Number.parseFloat(el.style.top);
|
|
343
|
+
return {
|
|
344
|
+
x: Number.isFinite(left) ? left : el.offsetLeft,
|
|
345
|
+
y: Number.isFinite(top) ? top : el.offsetTop
|
|
346
|
+
};
|
|
347
|
+
};
|
|
348
|
+
const stopDragging = (event) => {
|
|
338
349
|
if (!isDragging) return;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (currentOffset) {
|
|
345
|
-
const newX = currentOffset.left + deltaX;
|
|
346
|
-
const newY = currentOffset.top + deltaY;
|
|
347
|
-
updateWindowState({ x: newX, y: newY });
|
|
348
|
-
await win.css({
|
|
349
|
-
left: `${newX}px`,
|
|
350
|
-
top: `${newY}px`
|
|
351
|
-
});
|
|
350
|
+
if (event && capturedTitleBar && typeof capturedTitleBar.releasePointerCapture === "function" && dragPointerId === event.pointerId) {
|
|
351
|
+
try {
|
|
352
|
+
capturedTitleBar.releasePointerCapture(event.pointerId);
|
|
353
|
+
} catch {
|
|
354
|
+
}
|
|
352
355
|
}
|
|
353
|
-
|
|
356
|
+
isDragging = false;
|
|
357
|
+
dragPointerId = null;
|
|
358
|
+
capturedTitleBar = null;
|
|
359
|
+
windowManager.updateWindow(initialWindowState.id, { x: lastWin.x, y: lastWin.y });
|
|
354
360
|
};
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
+
const onTitlePointerDown = (event) => {
|
|
362
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
363
|
+
const target = event.target;
|
|
364
|
+
if (target?.tagName === "BUTTON") return;
|
|
365
|
+
const titleBarEl = target?.closest?.(".title-bar");
|
|
366
|
+
if (!titleBarEl) return;
|
|
367
|
+
windowManager.setActiveWindow(initialWindowState.id);
|
|
361
368
|
isDragging = true;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
369
|
+
dragPointerId = event.pointerId;
|
|
370
|
+
capturedTitleBar = titleBarEl;
|
|
371
|
+
dragStartMouse = { x: event.clientX, y: event.clientY };
|
|
372
|
+
dragStartWin = getCurrentWinPos();
|
|
373
|
+
if (typeof titleBarEl.setPointerCapture === "function") {
|
|
374
|
+
titleBarEl.setPointerCapture(event.pointerId);
|
|
375
|
+
}
|
|
368
376
|
event.preventDefault();
|
|
369
377
|
};
|
|
370
|
-
const
|
|
371
|
-
isDragging
|
|
372
|
-
|
|
373
|
-
|
|
378
|
+
const onTitlePointerMove = (event) => {
|
|
379
|
+
if (!isDragging) return;
|
|
380
|
+
if (dragPointerId !== null && event.pointerId !== dragPointerId) return;
|
|
381
|
+
const newX = dragStartWin.x + (event.clientX - dragStartMouse.x);
|
|
382
|
+
const newY = dragStartWin.y + (event.clientY - dragStartMouse.y);
|
|
383
|
+
lastWin = { x: newX, y: newY };
|
|
384
|
+
const el = ref.current;
|
|
385
|
+
if (el) {
|
|
386
|
+
el.style.left = `${newX}px`;
|
|
387
|
+
el.style.top = `${newY}px`;
|
|
388
|
+
}
|
|
389
|
+
updateWindowState({ x: newX, y: newY });
|
|
390
|
+
event.preventDefault();
|
|
391
|
+
};
|
|
392
|
+
const onTitlePointerUp = (event) => {
|
|
393
|
+
stopDragging(event);
|
|
394
|
+
};
|
|
395
|
+
const onTitlePointerCancel = (event) => {
|
|
396
|
+
stopDragging(event);
|
|
374
397
|
};
|
|
375
398
|
const onWindowMounted = () => {
|
|
376
399
|
windowManager.updateWindow(initialWindowState.id, {
|
|
@@ -378,17 +401,18 @@ function Window({
|
|
|
378
401
|
ref
|
|
379
402
|
});
|
|
380
403
|
windowManager.setActiveWindow(initialWindowState.id);
|
|
404
|
+
$$1(document).on("blur", () => stopDragging());
|
|
405
|
+
$$1(document).on("visibilitychange", () => {
|
|
406
|
+
if (document.hidden) stopDragging();
|
|
407
|
+
});
|
|
381
408
|
};
|
|
382
409
|
const onCloseClick = () => windowManager.closeWindow(initialWindowState.id);
|
|
383
|
-
const onMaximizeClick =
|
|
410
|
+
const onMaximizeClick = () => {
|
|
384
411
|
const currentState = windowManager.getWindow(initialWindowState.id);
|
|
385
|
-
if (currentState?.maximized)
|
|
386
|
-
|
|
387
|
-
} else {
|
|
388
|
-
windowManager.maximizeWindow(initialWindowState.id);
|
|
389
|
-
}
|
|
412
|
+
if (currentState?.maximized) windowManager.restoreWindow(initialWindowState.id);
|
|
413
|
+
else windowManager.maximizeWindow(initialWindowState.id);
|
|
390
414
|
};
|
|
391
|
-
const onMinimizeClick =
|
|
415
|
+
const onMinimizeClick = () => {
|
|
392
416
|
windowManager.minimizeWindow(initialWindowState.id);
|
|
393
417
|
};
|
|
394
418
|
return /* @__PURE__ */ jsxs(
|
|
@@ -410,36 +434,18 @@ function Window({
|
|
|
410
434
|
{
|
|
411
435
|
class: "title-bar",
|
|
412
436
|
onMount: onWindowMounted,
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
437
|
+
onPointerDown: onTitlePointerDown,
|
|
438
|
+
onPointerMove: onTitlePointerMove,
|
|
439
|
+
onPointerUp: onTitlePointerUp,
|
|
440
|
+
onPointerCancel: onTitlePointerCancel,
|
|
441
|
+
onDblClick: onMaximizeClick,
|
|
442
|
+
style: { touchAction: "none" },
|
|
416
443
|
children: [
|
|
417
444
|
/* @__PURE__ */ jsx("div", { class: "title-bar-text", children: title }),
|
|
418
445
|
/* @__PURE__ */ jsxs("div", { class: "title-bar-controls", children: [
|
|
419
|
-
/* @__PURE__ */ jsx(
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
type: "button",
|
|
423
|
-
"aria-label": "Minimize",
|
|
424
|
-
onClick: onMinimizeClick
|
|
425
|
-
}
|
|
426
|
-
),
|
|
427
|
-
/* @__PURE__ */ jsx(
|
|
428
|
-
"button",
|
|
429
|
-
{
|
|
430
|
-
type: "button",
|
|
431
|
-
"aria-label": "Maximize",
|
|
432
|
-
onClick: onMaximizeClick
|
|
433
|
-
}
|
|
434
|
-
),
|
|
435
|
-
/* @__PURE__ */ jsx(
|
|
436
|
-
"button",
|
|
437
|
-
{
|
|
438
|
-
type: "button",
|
|
439
|
-
"aria-label": "Close",
|
|
440
|
-
onClick: onCloseClick
|
|
441
|
-
}
|
|
442
|
-
)
|
|
446
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Minimize", onClick: onMinimizeClick }),
|
|
447
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Maximize", onClick: onMaximizeClick }),
|
|
448
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Close", onClick: onCloseClick })
|
|
443
449
|
] })
|
|
444
450
|
]
|
|
445
451
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "defuss-desktop",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"defuss": "
|
|
57
|
-
"defuss-runtime": "
|
|
58
|
-
"defuss-transval": "
|
|
56
|
+
"defuss": "workspace:*",
|
|
57
|
+
"defuss-runtime": "workspace:*",
|
|
58
|
+
"defuss-transval": "workspace:*"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@vitest/coverage-v8": "^4.0.17",
|
|
@@ -65,4 +65,4 @@
|
|
|
65
65
|
"typescript": "^5.9.3",
|
|
66
66
|
"vitest": "^4.0.17"
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|