@lvce-editor/title-bar-worker 1.5.0 → 1.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.
@@ -1354,10 +1354,15 @@ const getMenuVirtualDom = menuItems => {
1354
1354
  };
1355
1355
 
1356
1356
  const HandleClick = 'handleClick';
1357
+ const HandleClickMinimize = 'handleClickMinimize';
1358
+ const HandleClickToggleClose = 'handleClickToggleClose';
1359
+ const HandleClickToggleMaximize = 'handleClickToggleMaximize';
1357
1360
  const HandleFocusIn = 'handleFocusIn';
1358
1361
  const HandleFocusOut = 'handleFocusOut';
1359
1362
  const HandlePointerOut = 'handlePointerOut';
1360
1363
  const HandlePointerOver = 'handlePointerOver';
1364
+ const HandleMenuClick = 'handleMenuClick';
1365
+ const HandleMenuMouseOver = 'handleMenuMouseOver';
1361
1366
 
1362
1367
  const getItemVirtualDom = item => {
1363
1368
  // @ts-ignore
@@ -1600,7 +1605,8 @@ const doRender = async uid => {
1600
1605
  return commands;
1601
1606
  };
1602
1607
 
1603
- const commandsIds = ['closeMenu', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusPrevious', 'handleKeyArrowDown', 'handleKeyArrowLeft', 'handleKeyArrowRight', 'handleKeyArrowUp', 'handleKeyEnd', 'handleKeyEnter', 'handleKeyEscape', 'handleKeyHome', 'handleKeySpace', 'handleMenuClick', 'handleMenuMouseOver', 'handleMouseOver', 'handleMouseOut', 'toggleIndex', 'toggleMenu', 'handleClick', 'handleFocus'];
1608
+ const commandsIds = ['closeMenu', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusPrevious', 'handleClick', 'handleFocus', 'handleKeyArrowDown', 'handleKeyArrowLeft', 'handleKeyArrowRight', 'handleKeyArrowUp', 'handleKeyEnd', 'handleKeyEnter', 'handleKeyEscape', 'handleKeyHome', 'handleKeySpace', 'handleMenuClick', 'handleMenuMouseOver', 'handleMouseOut', 'handleMouseOver', 'handlePointerOver', 'handlePointerOut', 'toggleIndex', 'toggleMenu'];
1609
+
1604
1610
  const getCommandIds = () => {
1605
1611
  return commandsIds;
1606
1612
  };
@@ -2288,6 +2294,248 @@ const handleContextMenu = state => {
2288
2294
  return state;
2289
2295
  };
2290
2296
 
2297
+ const getTitleBarIndexFromPosition = (titleBarEntries, x, y) => {
2298
+ let currentX = 0;
2299
+ for (let i = 0; i < titleBarEntries.length; i++) {
2300
+ const entry = titleBarEntries[i];
2301
+ const entryWidth = entry.width;
2302
+ if (x >= currentX && x < currentX + entryWidth) {
2303
+ return i;
2304
+ }
2305
+ currentX += entryWidth;
2306
+ }
2307
+ return -1;
2308
+ };
2309
+
2310
+ const getTotalWidth = entries => {
2311
+ let total = 0;
2312
+ for (const entry of entries) {
2313
+ total += entry.width;
2314
+ }
2315
+ return total;
2316
+ };
2317
+
2318
+ // TODO lazyload menuEntries and use Command.execute (maybe)
2319
+ const CONTEXT_MENU_ITEM_HEIGHT = 26;
2320
+ const CONTEXT_MENU_SEPARATOR_HEIGHT = 11;
2321
+ const CONTEXT_MENU_PADDING = 8;
2322
+ const getMenuHeight = items => {
2323
+ let height = CONTEXT_MENU_PADDING;
2324
+ for (const item of items) {
2325
+ switch (item.flags) {
2326
+ case Separator:
2327
+ height += CONTEXT_MENU_SEPARATOR_HEIGHT;
2328
+ break;
2329
+ default:
2330
+ height += CONTEXT_MENU_ITEM_HEIGHT;
2331
+ break;
2332
+ }
2333
+ }
2334
+ return height;
2335
+ };
2336
+
2337
+ // TODO lazyload menuEntries and use Command.execute (maybe)
2338
+ const MENU_WIDTH = 150;
2339
+ const CONTEXT_MENU_WIDTH = 250;
2340
+ const getMenuWidth = () => {
2341
+ return CONTEXT_MENU_WIDTH;
2342
+ };
2343
+
2344
+ // TODO difference between focusing with mouse or keyboard
2345
+ // with mouse -> open submenu
2346
+ // with keyboard -> don't open submenu, only focus
2347
+
2348
+ const getIndexToFocusNextStartingAt = (items, startIndex) => {
2349
+ for (let i = startIndex; i < startIndex + items.length; i++) {
2350
+ const index = i % items.length;
2351
+ const item = items[index];
2352
+ if (canBeFocused(item)) {
2353
+ return index;
2354
+ }
2355
+ }
2356
+ return -1;
2357
+ };
2358
+ const getIndexToFocusFirst = items => {
2359
+ return getIndexToFocusNextStartingAt(items, 0);
2360
+ };
2361
+ const getIndexToFocusLast = items => {
2362
+ return getIndexToFocusPreviousStartingAt(items, items.length - 1);
2363
+ };
2364
+
2365
+ // TODO this code seems a bit too complicated, maybe it can be simplified
2366
+ const getIndexToFocusPreviousStartingAt = (items, startIndex) => {
2367
+ for (let i = startIndex; i > startIndex - items.length; i--) {
2368
+ const index = (i + items.length) % items.length;
2369
+ const item = items[index];
2370
+ if (canBeFocused(item)) {
2371
+ return index;
2372
+ }
2373
+ }
2374
+ return -1;
2375
+ };
2376
+ const getIndexToFocusPrevious = menu => {
2377
+ const startIndex = menu.focusedIndex === -1 ? menu.items.length - 1 : menu.focusedIndex - 1;
2378
+ return getIndexToFocusPreviousStartingAt(menu.items, startIndex);
2379
+ };
2380
+ const canBeFocused = item => {
2381
+ switch (item.flags) {
2382
+ case Separator:
2383
+ case Disabled:
2384
+ return false;
2385
+ default:
2386
+ return true;
2387
+ }
2388
+ };
2389
+ const getIndexToFocusNext = menu => {
2390
+ const startIndex = menu.focusedIndex + 1;
2391
+ return getIndexToFocusNextStartingAt(menu.items, startIndex);
2392
+ };
2393
+
2394
+ // TODO handle printable letter and focus item that starts with that letter
2395
+
2396
+ // TODO pageup / pagedown keys
2397
+
2398
+ // TODO more tests
2399
+
2400
+ const menus = [MenuEntriesEdit, MenuEntriesFile, MenuEntriesGo, MenuEntriesHelp, MenuEntriesRun, MenuEntriesSelection, MenuEntriesTerminal, MenuEntriesTitleBar, MenuEntriesView, MenuEntriesOpenRecent];
2401
+ const getMenus = () => {
2402
+ return menus;
2403
+ };
2404
+ const getModule = id => {
2405
+ for (const module of menus) {
2406
+ if (module.id === id) {
2407
+ return module;
2408
+ }
2409
+ }
2410
+ return undefined;
2411
+ };
2412
+ const getMenuEntries = async (id, ...args) => {
2413
+ try {
2414
+ const module = getModule(id);
2415
+ // @ts-ignore
2416
+ const inject = module.inject || [];
2417
+ // @ts-ignore
2418
+ return module.getMenuEntries(...args);
2419
+ } catch (error) {
2420
+ throw new VError(error, `Failed to load menu entries for id ${id}`);
2421
+ }
2422
+ };
2423
+
2424
+ const openMenuAtIndex = async (state, index, shouldBeFocused) => {
2425
+ const {
2426
+ titleBarEntries,
2427
+ titleBarHeight,
2428
+ x
2429
+ } = state;
2430
+ // TODO race conditions
2431
+ // TODO send renderer process
2432
+ // 1. open menu, items to show
2433
+ // 2. focus menu
2434
+ const titleBarEntry = titleBarEntries[index];
2435
+ const {
2436
+ id
2437
+ } = titleBarEntry;
2438
+ const items = await getMenuEntries(id);
2439
+ const relevantEntries = titleBarEntries.slice(0, index);
2440
+ const totalWidths = getTotalWidth(relevantEntries);
2441
+ const offset = totalWidths;
2442
+ // TODO race condition: another menu might already be open at this point
2443
+
2444
+ const menuX = x + offset;
2445
+ const menuY = titleBarHeight;
2446
+ const width = getMenuWidth();
2447
+ const height = getMenuHeight(items);
2448
+ const menuFocusedIndex = shouldBeFocused ? getIndexToFocusNextStartingAt(items, 0) : -1;
2449
+ const menu = {
2450
+ id,
2451
+ items,
2452
+ focusedIndex: menuFocusedIndex,
2453
+ level: 0,
2454
+ x: menuX,
2455
+ y: menuY,
2456
+ width,
2457
+ height
2458
+ };
2459
+ const menus = [menu];
2460
+ return {
2461
+ ...state,
2462
+ isMenuOpen: true,
2463
+ focusedIndex: index,
2464
+ menus
2465
+ };
2466
+ };
2467
+
2468
+ const focusIndex = async (state, index) => {
2469
+ object(state);
2470
+ number(index);
2471
+ const {
2472
+ isMenuOpen,
2473
+ focusedIndex
2474
+ } = state;
2475
+ if (index === focusedIndex) {
2476
+ return state;
2477
+ }
2478
+ if (isMenuOpen) {
2479
+ return openMenuAtIndex(state, index, /* focus */false);
2480
+ }
2481
+ return {
2482
+ ...state,
2483
+ focusedIndex: index
2484
+ };
2485
+ };
2486
+
2487
+ const handleMouseOutMenuClosed = state => {
2488
+ return focusIndex(state, -1);
2489
+ };
2490
+
2491
+ const handleMouseOutMenuOpen = state => {
2492
+ return state;
2493
+ };
2494
+
2495
+ const ifElse = (menuOpenFunction, menuClosedFunction) => {
2496
+ const ifElseFunction = (state, ...args) => {
2497
+ const {
2498
+ isMenuOpen
2499
+ } = state;
2500
+ if (isMenuOpen) {
2501
+ return menuOpenFunction(state, ...args);
2502
+ }
2503
+ return menuClosedFunction(state, ...args);
2504
+ };
2505
+ return ifElseFunction;
2506
+ };
2507
+
2508
+ const handleMouseOut = ifElse(handleMouseOutMenuOpen, handleMouseOutMenuClosed);
2509
+
2510
+ const handlePointerOut = (state, clientX, clientY) => {
2511
+ const index = getTitleBarIndexFromPosition(state.titleBarEntries, clientX - state.x);
2512
+ if (index === -1) {
2513
+ return state;
2514
+ }
2515
+ return handleMouseOut(state, index);
2516
+ };
2517
+
2518
+ const handleMouseOverMenuClosed = (state, index) => {
2519
+ return focusIndex(state, index);
2520
+ };
2521
+
2522
+ const handleMouseOverMenuOpen = async (state, index) => {
2523
+ if (index === -1) {
2524
+ return state;
2525
+ }
2526
+ return focusIndex(state, index);
2527
+ };
2528
+
2529
+ const handleMouseOver = ifElse(handleMouseOverMenuOpen, handleMouseOverMenuClosed);
2530
+
2531
+ const handlePointerOver = (state, clientX, clientY) => {
2532
+ const index = getTitleBarIndexFromPosition(state.titleBarEntries, clientX - state.x);
2533
+ if (index === -1) {
2534
+ return state;
2535
+ }
2536
+ return handleMouseOver(state, index);
2537
+ };
2538
+
2291
2539
  const getFontString = (fontWeight, fontSize, fontFamily) => {
2292
2540
  return `${fontWeight} ${fontSize}px ${fontFamily}`;
2293
2541
  };
@@ -2380,40 +2628,37 @@ const loadContent = async (state, titleBarEntries) => {
2380
2628
  };
2381
2629
  };
2382
2630
 
2383
- const menus = [MenuEntriesEdit, MenuEntriesFile, MenuEntriesGo, MenuEntriesHelp, MenuEntriesRun, MenuEntriesSelection, MenuEntriesTerminal, MenuEntriesTitleBar, MenuEntriesView, MenuEntriesOpenRecent];
2384
- const getMenus = () => {
2385
- return menus;
2386
- };
2387
- const getModule = id => {
2388
- for (const module of menus) {
2389
- if (module.id === id) {
2390
- return module;
2391
- }
2392
- }
2393
- return undefined;
2394
- };
2395
- const getMenuEntries = async (id, ...args) => {
2396
- try {
2397
- const module = getModule(id);
2398
- // @ts-ignore
2399
- const inject = module.inject || [];
2400
- // @ts-ignore
2401
- return module.getMenuEntries(...args);
2402
- } catch (error) {
2403
- throw new VError(error, `Failed to load menu entries for id ${id}`);
2404
- }
2405
- };
2406
-
2407
2631
  const renderEventListeners = () => {
2408
2632
  return [{
2409
- name: 'handleClickMinimize',
2633
+ name: HandleClickMinimize,
2410
2634
  params: ['handleClickMinimize']
2411
2635
  }, {
2412
- name: 'handleClickClose',
2636
+ name: HandleClickToggleClose,
2413
2637
  params: ['handleClickClose']
2414
2638
  }, {
2415
- name: 'handleClickToggleMaximize',
2639
+ name: HandleClickToggleMaximize,
2416
2640
  params: ['handleClickToggleMaximize']
2641
+ }, {
2642
+ name: HandleFocusIn,
2643
+ params: ['handlefocus']
2644
+ }, {
2645
+ name: HandleMenuClick,
2646
+ params: ['handleMenuClick', 'event.clientX', 'event.clientY']
2647
+ }, {
2648
+ name: HandleMenuMouseOver,
2649
+ params: ['handleMenuMouseOver', 'event.clientX', 'event.clientY']
2650
+ }, {
2651
+ name: HandleClick,
2652
+ params: ['handleClick', 'event.button', 'event.clientX', 'event.clientY']
2653
+ }, {
2654
+ name: HandlePointerOut,
2655
+ params: ['handlePointerOut', 'event.clientX', 'event.clientY']
2656
+ }, {
2657
+ name: HandlePointerOver,
2658
+ params: ['handlePointerOver', 'event.clientX', 'event.clientY']
2659
+ }, {
2660
+ name: HandleFocusOut,
2661
+ params: ['handleFocusOut', 'event.clientX', 'event.clientY'] // TODO maybe check relatedTarget
2417
2662
  }];
2418
2663
  };
2419
2664
 
@@ -2476,155 +2721,6 @@ const previous = (items, index) => {
2476
2721
  return index === 0 ? items.length - 1 : index - 1;
2477
2722
  };
2478
2723
 
2479
- const getTotalWidth = entries => {
2480
- let total = 0;
2481
- for (const entry of entries) {
2482
- total += entry.width;
2483
- }
2484
- return total;
2485
- };
2486
-
2487
- // TODO lazyload menuEntries and use Command.execute (maybe)
2488
- const CONTEXT_MENU_ITEM_HEIGHT = 26;
2489
- const CONTEXT_MENU_SEPARATOR_HEIGHT = 11;
2490
- const CONTEXT_MENU_PADDING = 8;
2491
- const getMenuHeight = items => {
2492
- let height = CONTEXT_MENU_PADDING;
2493
- for (const item of items) {
2494
- switch (item.flags) {
2495
- case Separator:
2496
- height += CONTEXT_MENU_SEPARATOR_HEIGHT;
2497
- break;
2498
- default:
2499
- height += CONTEXT_MENU_ITEM_HEIGHT;
2500
- break;
2501
- }
2502
- }
2503
- return height;
2504
- };
2505
-
2506
- // TODO lazyload menuEntries and use Command.execute (maybe)
2507
- const MENU_WIDTH = 150;
2508
- const CONTEXT_MENU_WIDTH = 250;
2509
- const getMenuWidth = () => {
2510
- return CONTEXT_MENU_WIDTH;
2511
- };
2512
-
2513
- // TODO difference between focusing with mouse or keyboard
2514
- // with mouse -> open submenu
2515
- // with keyboard -> don't open submenu, only focus
2516
-
2517
- const getIndexToFocusNextStartingAt = (items, startIndex) => {
2518
- for (let i = startIndex; i < startIndex + items.length; i++) {
2519
- const index = i % items.length;
2520
- const item = items[index];
2521
- if (canBeFocused(item)) {
2522
- return index;
2523
- }
2524
- }
2525
- return -1;
2526
- };
2527
- const getIndexToFocusFirst = items => {
2528
- return getIndexToFocusNextStartingAt(items, 0);
2529
- };
2530
- const getIndexToFocusLast = items => {
2531
- return getIndexToFocusPreviousStartingAt(items, items.length - 1);
2532
- };
2533
-
2534
- // TODO this code seems a bit too complicated, maybe it can be simplified
2535
- const getIndexToFocusPreviousStartingAt = (items, startIndex) => {
2536
- for (let i = startIndex; i > startIndex - items.length; i--) {
2537
- const index = (i + items.length) % items.length;
2538
- const item = items[index];
2539
- if (canBeFocused(item)) {
2540
- return index;
2541
- }
2542
- }
2543
- return -1;
2544
- };
2545
- const getIndexToFocusPrevious = menu => {
2546
- const startIndex = menu.focusedIndex === -1 ? menu.items.length - 1 : menu.focusedIndex - 1;
2547
- return getIndexToFocusPreviousStartingAt(menu.items, startIndex);
2548
- };
2549
- const canBeFocused = item => {
2550
- switch (item.flags) {
2551
- case Separator:
2552
- case Disabled:
2553
- return false;
2554
- default:
2555
- return true;
2556
- }
2557
- };
2558
- const getIndexToFocusNext = menu => {
2559
- const startIndex = menu.focusedIndex + 1;
2560
- return getIndexToFocusNextStartingAt(menu.items, startIndex);
2561
- };
2562
-
2563
- // TODO handle printable letter and focus item that starts with that letter
2564
-
2565
- // TODO pageup / pagedown keys
2566
-
2567
- // TODO more tests
2568
-
2569
- const openMenuAtIndex = async (state, index, shouldBeFocused) => {
2570
- const {
2571
- titleBarEntries,
2572
- titleBarHeight,
2573
- x
2574
- } = state;
2575
- // TODO race conditions
2576
- // TODO send renderer process
2577
- // 1. open menu, items to show
2578
- // 2. focus menu
2579
- const titleBarEntry = titleBarEntries[index];
2580
- const {
2581
- id
2582
- } = titleBarEntry;
2583
- const items = await getMenuEntries(id);
2584
- const relevantEntries = titleBarEntries.slice(0, index);
2585
- const totalWidths = getTotalWidth(relevantEntries);
2586
- const offset = totalWidths;
2587
- // TODO race condition: another menu might already be open at this point
2588
-
2589
- const menuX = x + offset;
2590
- const menuY = titleBarHeight;
2591
- const width = getMenuWidth();
2592
- const height = getMenuHeight(items);
2593
- const menuFocusedIndex = shouldBeFocused ? getIndexToFocusNextStartingAt(items, 0) : -1;
2594
- const menu = {
2595
- id,
2596
- items,
2597
- focusedIndex: menuFocusedIndex,
2598
- level: 0,
2599
- x: menuX,
2600
- y: menuY,
2601
- width,
2602
- height
2603
- };
2604
- const menus = [menu];
2605
- return {
2606
- ...state,
2607
- isMenuOpen: true,
2608
- focusedIndex: index,
2609
- menus
2610
- };
2611
- };
2612
-
2613
- const focusIndex = async (state, index) => {
2614
- object(state);
2615
- number(index);
2616
- const {
2617
- isMenuOpen
2618
- } = state;
2619
- if (isMenuOpen) {
2620
- return openMenuAtIndex(state, index, /* focus */false);
2621
- }
2622
- return {
2623
- ...state,
2624
- focusedIndex: index
2625
- };
2626
- };
2627
-
2628
2724
  const focusFirst = state => {
2629
2725
  const indexToFocus = first();
2630
2726
  return focusIndex(state, indexToFocus);
@@ -2662,7 +2758,7 @@ const focusPrevious = state => {
2662
2758
 
2663
2759
  const LeftClick = 0;
2664
2760
 
2665
- const toggleIndex = (state, index) => {
2761
+ const toggleIndex = async (state, index) => {
2666
2762
  const {
2667
2763
  isMenuOpen,
2668
2764
  focusedIndex
@@ -2673,7 +2769,7 @@ const toggleIndex = (state, index) => {
2673
2769
  return openMenuAtIndex(state, index, /* focus */false);
2674
2770
  };
2675
2771
 
2676
- const handleClick = (state, button, index) => {
2772
+ const handleClick = async (state, button, index) => {
2677
2773
  if (button !== LeftClick) {
2678
2774
  return state;
2679
2775
  }
@@ -2724,19 +2820,6 @@ const handleKeyArrowDownMenuOpen = state => {
2724
2820
  };
2725
2821
  };
2726
2822
 
2727
- const ifElse = (menuOpenFunction, menuClosedFunction) => {
2728
- const ifElseFunction = (state, ...args) => {
2729
- const {
2730
- isMenuOpen
2731
- } = state;
2732
- if (isMenuOpen) {
2733
- return menuOpenFunction(state, ...args);
2734
- }
2735
- return menuClosedFunction(state, ...args);
2736
- };
2737
- return ifElseFunction;
2738
- };
2739
-
2740
2823
  const handleKeyArrowDown = ifElse(handleKeyArrowDownMenuOpen, handleKeyArrowDownMenuClosed);
2741
2824
 
2742
2825
  const handleKeyArrowLeftMenuClosed = state => {
@@ -3061,29 +3144,6 @@ const handleMenuMouseOver = async (state, level, index) => {
3061
3144
  };
3062
3145
  };
3063
3146
 
3064
- const handleMouseOutMenuClosed = state => {
3065
- return focusIndex(state, -1);
3066
- };
3067
-
3068
- const handleMouseOutMenuOpen = state => {
3069
- return state;
3070
- };
3071
-
3072
- const handleMouseOut = ifElse(handleMouseOutMenuOpen, handleMouseOutMenuClosed);
3073
-
3074
- const handleMouseOverMenuClosed = (state, index) => {
3075
- return focusIndex(state, index);
3076
- };
3077
-
3078
- const handleMouseOverMenuOpen = async (state, index) => {
3079
- if (index === -1) {
3080
- return state;
3081
- }
3082
- return focusIndex(state, index);
3083
- };
3084
-
3085
- const handleMouseOver = ifElse(handleMouseOverMenuOpen, handleMouseOverMenuClosed);
3086
-
3087
3147
  const toggleMenu = state => {
3088
3148
  const {
3089
3149
  isMenuOpen
@@ -3132,8 +3192,10 @@ const commandMap = {
3132
3192
  'TitleBarMenuBar.handleKeyArrowLeft': wrapCommand(handleKeyArrowLeft),
3133
3193
  'TitleBarMenuBar.handleKeyArrowRight': wrapCommand(handleKeyArrowRight),
3134
3194
  'TitleBarMenuBar.handleKeyArrowUp': wrapCommand(handleKeyArrowUp),
3195
+ 'TitleBarMenuBar.handlePointerOver': wrapCommand(handlePointerOver),
3135
3196
  'TitleBarMenuBar.handleKeyEnd': wrapCommand(handleKeyEnd),
3136
3197
  'TitleBarMenuBar.handleKeyEnter': wrapCommand(handleKeyEnter),
3198
+ 'TitleBarMenuBar.handlePointerOut': wrapCommand(handlePointerOut),
3137
3199
  'TitleBarMenuBar.handleKeyEscape': wrapCommand(handleKeyEscape),
3138
3200
  'TitleBarMenuBar.handleKeyHome': wrapCommand(handleKeyHome),
3139
3201
  'TitleBarMenuBar.handleKeySpace': wrapCommand(handleKeySpace),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/title-bar-worker",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Title Bar Worker",
5
5
  "repository": {
6
6
  "type": "git",