@flighthq/gui 0.4.1-edge.28.7f8e221

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 (96) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +17 -0
  3. package/dist/buttonController.d.ts +7 -0
  4. package/dist/buttonController.d.ts.map +1 -0
  5. package/dist/buttonController.js +83 -0
  6. package/dist/buttonController.js.map +1 -0
  7. package/dist/comboBoxController.d.ts +7 -0
  8. package/dist/comboBoxController.d.ts.map +1 -0
  9. package/dist/comboBoxController.js +46 -0
  10. package/dist/comboBoxController.js.map +1 -0
  11. package/dist/contract.d.ts +16 -0
  12. package/dist/contract.d.ts.map +1 -0
  13. package/dist/contract.js +16 -0
  14. package/dist/contract.js.map +1 -0
  15. package/dist/guiController.d.ts +24 -0
  16. package/dist/guiController.d.ts.map +1 -0
  17. package/dist/guiController.js +101 -0
  18. package/dist/guiController.js.map +1 -0
  19. package/dist/guiTestHelper.d.ts +5 -0
  20. package/dist/guiTestHelper.d.ts.map +1 -0
  21. package/dist/guiTestHelper.js +57 -0
  22. package/dist/guiTestHelper.js.map +1 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +2 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/listController.d.ts +8 -0
  28. package/dist/listController.d.ts.map +1 -0
  29. package/dist/listController.js +82 -0
  30. package/dist/listController.js.map +1 -0
  31. package/dist/progressBarController.d.ts +6 -0
  32. package/dist/progressBarController.d.ts.map +1 -0
  33. package/dist/progressBarController.js +42 -0
  34. package/dist/progressBarController.js.map +1 -0
  35. package/dist/radioGroupController.d.ts +7 -0
  36. package/dist/radioGroupController.d.ts.map +1 -0
  37. package/dist/radioGroupController.js +50 -0
  38. package/dist/radioGroupController.js.map +1 -0
  39. package/dist/scrollBarController.d.ts +7 -0
  40. package/dist/scrollBarController.d.ts.map +1 -0
  41. package/dist/scrollBarController.js +124 -0
  42. package/dist/scrollBarController.js.map +1 -0
  43. package/dist/scrollViewController.d.ts +8 -0
  44. package/dist/scrollViewController.d.ts.map +1 -0
  45. package/dist/scrollViewController.js +99 -0
  46. package/dist/scrollViewController.js.map +1 -0
  47. package/dist/sliderController.d.ts +7 -0
  48. package/dist/sliderController.d.ts.map +1 -0
  49. package/dist/sliderController.js +105 -0
  50. package/dist/sliderController.js.map +1 -0
  51. package/dist/splitPaneController.d.ts +7 -0
  52. package/dist/splitPaneController.d.ts.map +1 -0
  53. package/dist/splitPaneController.js +87 -0
  54. package/dist/splitPaneController.js.map +1 -0
  55. package/dist/tabBarController.d.ts +7 -0
  56. package/dist/tabBarController.d.ts.map +1 -0
  57. package/dist/tabBarController.js +43 -0
  58. package/dist/tabBarController.js.map +1 -0
  59. package/dist/textInputController.d.ts +9 -0
  60. package/dist/textInputController.d.ts.map +1 -0
  61. package/dist/textInputController.js +132 -0
  62. package/dist/textInputController.js.map +1 -0
  63. package/dist/toggleController.d.ts +7 -0
  64. package/dist/toggleController.d.ts.map +1 -0
  65. package/dist/toggleController.js +57 -0
  66. package/dist/toggleController.js.map +1 -0
  67. package/dist/tooltipController.d.ts +6 -0
  68. package/dist/tooltipController.d.ts.map +1 -0
  69. package/dist/tooltipController.js +62 -0
  70. package/dist/tooltipController.js.map +1 -0
  71. package/dist/treeViewController.d.ts +10 -0
  72. package/dist/treeViewController.d.ts.map +1 -0
  73. package/dist/treeViewController.js +128 -0
  74. package/dist/treeViewController.js.map +1 -0
  75. package/dist/windowController.d.ts +7 -0
  76. package/dist/windowController.d.ts.map +1 -0
  77. package/dist/windowController.js +119 -0
  78. package/dist/windowController.js.map +1 -0
  79. package/package.json +53 -0
  80. package/src/buttonController.test.ts +90 -0
  81. package/src/comboBoxController.test.ts +71 -0
  82. package/src/guiController.test.ts +162 -0
  83. package/src/guiTreeShaking.test.ts +35 -0
  84. package/src/listController.test.ts +96 -0
  85. package/src/progressBarController.test.ts +49 -0
  86. package/src/radioGroupController.test.ts +61 -0
  87. package/src/scrollBarController.test.ts +86 -0
  88. package/src/scrollViewController.test.ts +80 -0
  89. package/src/sliderController.test.ts +74 -0
  90. package/src/splitPaneController.test.ts +85 -0
  91. package/src/tabBarController.test.ts +50 -0
  92. package/src/textInputController.test.ts +93 -0
  93. package/src/toggleController.test.ts +72 -0
  94. package/src/tooltipController.test.ts +56 -0
  95. package/src/treeViewController.test.ts +105 -0
  96. package/src/windowController.test.ts +75 -0
@@ -0,0 +1,56 @@
1
+ import { createGuiTestNode, emitGuiPointer } from './guiTestHelper';
2
+ import {
3
+ createTooltipController,
4
+ disposeTooltipController,
5
+ hideTooltipController,
6
+ showTooltipController,
7
+ } from './tooltipController';
8
+
9
+ describe('createTooltipController', () => {
10
+ it('shows after delay at the pointer offset and hides on exit', () => {
11
+ vi.useFakeTimers();
12
+ const content = createGuiTestNode();
13
+ const target = createGuiTestNode();
14
+ createTooltipController({ content, delay: 50, offset: { x: 3, y: 4 }, target });
15
+ emitGuiPointer(target, 'onPointerOver', { worldX: 10, worldY: 20 });
16
+ expect(content.visible).toBe(false);
17
+ vi.advanceTimersByTime(50);
18
+ expect([content.visible, content.x, content.y]).toEqual([true, 13, 24]);
19
+ emitGuiPointer(target, 'onPointerOut');
20
+ expect(content.visible).toBe(false);
21
+ vi.useRealTimers();
22
+ });
23
+ });
24
+
25
+ describe('disposeTooltipController', () => {
26
+ it('cancels delayed display', () => {
27
+ vi.useFakeTimers();
28
+ const content = createGuiTestNode();
29
+ const target = createGuiTestNode();
30
+ const controller = createTooltipController({ content, delay: 50, target });
31
+ emitGuiPointer(target, 'onPointerOver');
32
+ disposeTooltipController(controller);
33
+ vi.advanceTimersByTime(50);
34
+ expect(content.visible).toBe(false);
35
+ vi.useRealTimers();
36
+ });
37
+ });
38
+
39
+ describe('hideTooltipController', () => {
40
+ it('hides immediately', () => {
41
+ const content = createGuiTestNode();
42
+ const controller = createTooltipController({ content, target: createGuiTestNode() });
43
+ showTooltipController(controller);
44
+ hideTooltipController(controller);
45
+ expect(content.visible).toBe(false);
46
+ });
47
+ });
48
+
49
+ describe('showTooltipController', () => {
50
+ it('shows immediately when called', () => {
51
+ const content = createGuiTestNode();
52
+ const controller = createTooltipController({ content, target: createGuiTestNode() });
53
+ showTooltipController(controller);
54
+ expect(content.visible).toBe(true);
55
+ });
56
+ });
@@ -0,0 +1,105 @@
1
+ import { connectSignal } from '@flighthq/signals/contract';
2
+ import type { TreeViewControllerItem } from '@flighthq/types/contract';
3
+
4
+ import { createGuiTestNode, emitGuiKeyboard, emitGuiPointer } from './guiTestHelper';
5
+ import {
6
+ createTreeViewController,
7
+ disposeTreeViewController,
8
+ getTreeViewControllerSelectedItem,
9
+ getTreeViewControllerSignals,
10
+ isTreeViewControllerItemExpanded,
11
+ setTreeViewControllerItemExpanded,
12
+ setTreeViewControllerSelectedItem,
13
+ toggleTreeViewControllerItem,
14
+ } from './treeViewController';
15
+
16
+ function tree() {
17
+ const child: TreeViewControllerItem = { visual: createGuiTestNode() };
18
+ const root: TreeViewControllerItem = { children: [child], visual: createGuiTestNode() };
19
+ return { child, root };
20
+ }
21
+
22
+ describe('createTreeViewController', () => {
23
+ it('models expansion separately from flat ListController state', () => {
24
+ const { child, root } = tree();
25
+ const controller = createTreeViewController({ items: [root] });
26
+ expect(child.visual.visible).toBe(false);
27
+ emitGuiPointer(root.visual, 'onDoubleClick');
28
+ expect(isTreeViewControllerItemExpanded(controller, root)).toBe(true);
29
+ expect(child.visual.visible).toBe(true);
30
+ });
31
+
32
+ it('navigates hierarchy with left and right', () => {
33
+ const { child, root } = tree();
34
+ const controller = createTreeViewController({ items: [root], selectedItem: root });
35
+ emitGuiKeyboard(root.visual, 'onKeyDown', 'ArrowRight');
36
+ emitGuiKeyboard(root.visual, 'onKeyDown', 'ArrowRight');
37
+ expect(getTreeViewControllerSelectedItem(controller)).toBe(child);
38
+ });
39
+ });
40
+
41
+ describe('disposeTreeViewController', () => {
42
+ it('detaches item input', () => {
43
+ const { root } = tree();
44
+ const controller = createTreeViewController({ items: [root] });
45
+ disposeTreeViewController(controller);
46
+ emitGuiPointer(root.visual, 'onClick');
47
+ expect(getTreeViewControllerSelectedItem(controller)).toBeNull();
48
+ });
49
+ });
50
+
51
+ describe('getTreeViewControllerSelectedItem', () => {
52
+ it('returns configured selection', () => {
53
+ const { root } = tree();
54
+ expect(getTreeViewControllerSelectedItem(createTreeViewController({ items: [root], selectedItem: root }))).toBe(
55
+ root,
56
+ );
57
+ });
58
+ });
59
+
60
+ describe('getTreeViewControllerSignals', () => {
61
+ it('emits activation separately from expansion', () => {
62
+ const { root } = tree();
63
+ const controller = createTreeViewController({ items: [root] });
64
+ let activated = false;
65
+ connectSignal(getTreeViewControllerSignals(controller).onActivate, () => (activated = true));
66
+ emitGuiPointer(root.visual, 'onDoubleClick');
67
+ expect(activated).toBe(true);
68
+ });
69
+ });
70
+
71
+ describe('isTreeViewControllerItemExpanded', () => {
72
+ it('reads authored initial expansion', () => {
73
+ const { root } = tree();
74
+ root.expanded = true;
75
+ expect(isTreeViewControllerItemExpanded(createTreeViewController({ items: [root] }), root)).toBe(true);
76
+ });
77
+ });
78
+
79
+ describe('setTreeViewControllerItemExpanded', () => {
80
+ it('ignores leaves', () => {
81
+ const { child, root } = tree();
82
+ const controller = createTreeViewController({ items: [root] });
83
+ setTreeViewControllerItemExpanded(controller, child, true);
84
+ expect(isTreeViewControllerItemExpanded(controller, child)).toBe(false);
85
+ });
86
+ });
87
+
88
+ describe('setTreeViewControllerSelectedItem', () => {
89
+ it('rejects foreign items', () => {
90
+ const { root } = tree();
91
+ const controller = createTreeViewController({ items: [root] });
92
+ setTreeViewControllerSelectedItem(controller, { visual: createGuiTestNode() });
93
+ expect(getTreeViewControllerSelectedItem(controller)).toBeNull();
94
+ });
95
+ });
96
+
97
+ describe('toggleTreeViewControllerItem', () => {
98
+ it('toggles expansion in both directions', () => {
99
+ const { root } = tree();
100
+ const controller = createTreeViewController({ items: [root] });
101
+ toggleTreeViewControllerItem(controller, root);
102
+ toggleTreeViewControllerItem(controller, root);
103
+ expect(isTreeViewControllerItemExpanded(controller, root)).toBe(false);
104
+ });
105
+ });
@@ -0,0 +1,75 @@
1
+ import { connectSignal } from '@flighthq/signals/contract';
2
+
3
+ import { createButtonController } from './buttonController';
4
+ import { createGuiTestNode, emitGuiPointer } from './guiTestHelper';
5
+ import {
6
+ createWindowController,
7
+ disposeWindowController,
8
+ getWindowControllerSignals,
9
+ setWindowControllerPosition,
10
+ setWindowControllerSize,
11
+ } from './windowController';
12
+
13
+ describe('createWindowController', () => {
14
+ it('moves from a title bar and resizes from a handle', () => {
15
+ const frame = createGuiTestNode(200, 100);
16
+ const titleBar = createGuiTestNode();
17
+ const resizeHandle = createGuiTestNode();
18
+ createWindowController({ frame, resizeHandle, titleBar });
19
+ emitGuiPointer(titleBar, 'onPointerDown', { worldX: 10, worldY: 10 });
20
+ emitGuiPointer(titleBar, 'onPointerMove', { worldX: 30, worldY: 40 });
21
+ expect([frame.x, frame.y]).toEqual([20, 30]);
22
+ emitGuiPointer(resizeHandle, 'onPointerDown', { worldX: 0, worldY: 0 });
23
+ emitGuiPointer(resizeHandle, 'onPointerMove', { worldX: 100, worldY: 50 });
24
+ expect([frame.scaleX, frame.scaleY]).toEqual([1.5, 1.5]);
25
+ });
26
+
27
+ it('forwards a composed close button', () => {
28
+ const closeNode = createGuiTestNode();
29
+ const controller = createWindowController({
30
+ closeButton: createButtonController({ upState: closeNode }),
31
+ frame: createGuiTestNode(),
32
+ });
33
+ let closed = false;
34
+ connectSignal(getWindowControllerSignals(controller).onClose, () => (closed = true));
35
+ emitGuiPointer(closeNode, 'onClick');
36
+ expect(closed).toBe(true);
37
+ });
38
+ });
39
+
40
+ describe('disposeWindowController', () => {
41
+ it('detaches title dragging', () => {
42
+ const frame = createGuiTestNode();
43
+ const titleBar = createGuiTestNode();
44
+ const controller = createWindowController({ frame, titleBar });
45
+ disposeWindowController(controller);
46
+ emitGuiPointer(titleBar, 'onPointerDown', { worldX: 0 });
47
+ emitGuiPointer(titleBar, 'onPointerMove', { worldX: 20 });
48
+ expect(frame.x).toBe(0);
49
+ });
50
+ });
51
+
52
+ describe('getWindowControllerSignals', () => {
53
+ it('returns stable signals', () => {
54
+ const controller = createWindowController({ frame: createGuiTestNode() });
55
+ expect(getWindowControllerSignals(controller)).toBe(getWindowControllerSignals(controller));
56
+ });
57
+ });
58
+
59
+ describe('setWindowControllerPosition', () => {
60
+ it('sets the frame transform', () => {
61
+ const frame = createGuiTestNode();
62
+ const controller = createWindowController({ frame });
63
+ setWindowControllerPosition(controller, 4, 5);
64
+ expect([frame.x, frame.y]).toEqual([4, 5]);
65
+ });
66
+ });
67
+
68
+ describe('setWindowControllerSize', () => {
69
+ it('honors minimum dimensions', () => {
70
+ const frame = createGuiTestNode(100, 100);
71
+ const controller = createWindowController({ frame, minimumHeight: 50, minimumWidth: 50 });
72
+ setWindowControllerSize(controller, 10, 20);
73
+ expect([frame.scaleX, frame.scaleY]).toEqual([0.5, 0.5]);
74
+ });
75
+ });