@lvce-editor/menu-worker 1.6.0 → 1.7.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.
@@ -421,10 +421,10 @@ const create$4 = (method, params) => {
421
421
  };
422
422
  };
423
423
  const callbacks = Object.create(null);
424
- const set$3 = (id, fn) => {
424
+ const set$4 = (id, fn) => {
425
425
  callbacks[id] = fn;
426
426
  };
427
- const get$2 = id => {
427
+ const get$3 = id => {
428
428
  return callbacks[id];
429
429
  };
430
430
  const remove = id => {
@@ -440,7 +440,7 @@ const registerPromise = () => {
440
440
  resolve,
441
441
  promise
442
442
  } = Promise.withResolvers();
443
- set$3(id, resolve);
443
+ set$4(id, resolve);
444
444
  return {
445
445
  id,
446
446
  promise
@@ -601,14 +601,14 @@ const unwrapJsonRpcResult = responseMessage => {
601
601
  }
602
602
  throw new JsonRpcError('unexpected response message');
603
603
  };
604
- const warn = (...args) => {
604
+ const warn$1 = (...args) => {
605
605
  console.warn(...args);
606
606
  };
607
607
  const resolve = (id, response) => {
608
- const fn = get$2(id);
608
+ const fn = get$3(id);
609
609
  if (!fn) {
610
610
  console.log(response);
611
- warn(`callback ${id} may already be disposed`);
611
+ warn$1(`callback ${id} may already be disposed`);
612
612
  return;
613
613
  }
614
614
  fn(response);
@@ -1151,6 +1151,9 @@ const getKeyCodeString = keyCode => {
1151
1151
  const CtrlCmd = 1 << 11 >>> 0;
1152
1152
  const Shift = 1 << 10 >>> 0;
1153
1153
 
1154
+ const Separator$2 = 1;
1155
+ const Disabled$1 = 5;
1156
+
1154
1157
  const parseKey = rawKey => {
1155
1158
  const isCtrl = Boolean(rawKey & CtrlCmd);
1156
1159
  const isShift = Boolean(rawKey & Shift);
@@ -1166,10 +1169,10 @@ const parseKey = rawKey => {
1166
1169
  const RendererWorker = 1;
1167
1170
 
1168
1171
  const rpcs = Object.create(null);
1169
- const set$2 = (id, rpc) => {
1172
+ const set$3 = (id, rpc) => {
1170
1173
  rpcs[id] = rpc;
1171
1174
  };
1172
- const get$1 = id => {
1175
+ const get$2 = id => {
1173
1176
  return rpcs[id];
1174
1177
  };
1175
1178
 
@@ -1177,21 +1180,21 @@ const create$1 = rpcId => {
1177
1180
  return {
1178
1181
  // @ts-ignore
1179
1182
  invoke(method, ...params) {
1180
- const rpc = get$1(rpcId);
1183
+ const rpc = get$2(rpcId);
1181
1184
  // @ts-ignore
1182
1185
  return rpc.invoke(method, ...params);
1183
1186
  },
1184
1187
  // @ts-ignore
1185
1188
  invokeAndTransfer(method, ...params) {
1186
- const rpc = get$1(rpcId);
1189
+ const rpc = get$2(rpcId);
1187
1190
  // @ts-ignore
1188
1191
  return rpc.invokeAndTransfer(method, ...params);
1189
1192
  },
1190
1193
  set(rpc) {
1191
- set$2(rpcId, rpc);
1194
+ set$3(rpcId, rpc);
1192
1195
  },
1193
1196
  async dispose() {
1194
- const rpc = get$1(rpcId);
1197
+ const rpc = get$2(rpcId);
1195
1198
  await rpc.dispose();
1196
1199
  }
1197
1200
  };
@@ -1199,7 +1202,7 @@ const create$1 = rpcId => {
1199
1202
 
1200
1203
  const {
1201
1204
  invoke: invoke$1,
1202
- set: set$1} = create$1(RendererWorker);
1205
+ set: set$2} = create$1(RendererWorker);
1203
1206
 
1204
1207
  const matchesArgs = (a, b) => {
1205
1208
  if (!a && !b) {
@@ -1227,6 +1230,11 @@ const getCommandKeyBinding = (keyBindings, command, args) => {
1227
1230
  return undefined;
1228
1231
  };
1229
1232
 
1233
+ /* eslint-disable no-console */
1234
+ const warn = (...args) => {
1235
+ console.warn(...args);
1236
+ };
1237
+
1230
1238
  const invoke = async (method, ...params) => {
1231
1239
  // TODO
1232
1240
  };
@@ -2095,7 +2103,8 @@ const getVisible = (items, focusedIndex, expanded, level) => {
2095
2103
  // TODO this code seems a bit too complicated, maybe it can be simplified
2096
2104
 
2097
2105
  const state = {
2098
- menus: []};
2106
+ menus: [],
2107
+ latestTimeStamp: 0};
2099
2108
  const addMenuInternal = menu => {
2100
2109
  if (state.menus.length > 5) {
2101
2110
  throw new Error('too many menus');
@@ -2109,12 +2118,47 @@ const getCount = () => {
2109
2118
  const reset = () => {
2110
2119
  state.menus = [];
2111
2120
  };
2121
+ const get$1 = index => {
2122
+ return state.menus[index];
2123
+ };
2124
+ const set$1 = menus => {
2125
+ state.menus = menus;
2126
+ };
2112
2127
  const getAll = () => {
2113
2128
  return state.menus;
2114
2129
  };
2130
+ const setTimestamp = timestamp => {
2131
+ state.latestTimeStamp = timestamp;
2132
+ };
2133
+ const getLatestTimestamp = () => {
2134
+ return state.latestTimeStamp;
2135
+ };
2115
2136
 
2116
2137
  // TODO lazyload menuEntries and use Command.execute (maybe)
2138
+ const CONTEXT_MENU_ITEM_HEIGHT$2 = 26;
2139
+ const CONTEXT_MENU_SEPARATOR_HEIGHT$2 = 11;
2140
+ const CONTEXT_MENU_PADDING$2 = 8;
2141
+ const getMenuHeight$2 = items => {
2142
+ let height = CONTEXT_MENU_PADDING$2;
2143
+ for (const item of items) {
2144
+ switch (item.flags) {
2145
+ case Separator$1:
2146
+ height += CONTEXT_MENU_SEPARATOR_HEIGHT$2;
2147
+ break;
2148
+ default:
2149
+ height += CONTEXT_MENU_ITEM_HEIGHT$2;
2150
+ break;
2151
+ }
2152
+ }
2153
+ return height;
2154
+ };
2155
+
2156
+ // TODO lazyload menuEntries and use Command.execute (maybe)
2157
+ const MENU_WIDTH = 150;
2117
2158
  const CONTEXT_MENU_WIDTH$1 = 250;
2159
+ const getMenuWidth = () => {
2160
+ return CONTEXT_MENU_WIDTH$1;
2161
+ };
2118
2162
 
2119
2163
  // TODO handle printable letter and focus item that starts with that letter
2120
2164
 
@@ -2307,6 +2351,69 @@ const diff2 = uid => {
2307
2351
  return diff(oldState, newState);
2308
2352
  };
2309
2353
 
2354
+ const canBeFocused = item => {
2355
+ switch (item.flags) {
2356
+ case Separator$2:
2357
+ case Disabled$1:
2358
+ return false;
2359
+ default:
2360
+ return true;
2361
+ }
2362
+ };
2363
+
2364
+ const focusIndex = async (menu, index) => {
2365
+ if (menu.items.length === 0) {
2366
+ return;
2367
+ }
2368
+ const oldFocusedIndex = menu.focusedIndex;
2369
+ menu.focusedIndex = index;
2370
+ return {
2371
+ commands: [/* Menu.focusIndex */'Menu.focusIndex', /* level */menu.level, /* oldFocusedIndex */oldFocusedIndex, /* newFocusedIndex */index],
2372
+ menus: getAll()
2373
+ };
2374
+ };
2375
+
2376
+ const getCurrentMenu = () => {
2377
+ if (getCount() === 0) {
2378
+ warn('menu not available');
2379
+ }
2380
+ return getAll().at(-1);
2381
+ };
2382
+ const getIndexToFocusNextStartingAt = (items, startIndex) => {
2383
+ for (let i = startIndex; i < startIndex + items.length; i++) {
2384
+ const index = i % items.length;
2385
+ const item = items[index];
2386
+ if (canBeFocused(item)) {
2387
+ return index;
2388
+ }
2389
+ }
2390
+ return -1;
2391
+ };
2392
+ const getIndexToFocusFirst = items => {
2393
+ return getIndexToFocusNextStartingAt(items, 0);
2394
+ };
2395
+ const focusFirst = async () => {
2396
+ const menu = getCurrentMenu();
2397
+ if (getCount() === 0) {
2398
+ return;
2399
+ }
2400
+ const indexToFocus = getIndexToFocusFirst(menu.items);
2401
+ await focusIndex(menu, indexToFocus);
2402
+ };
2403
+
2404
+ const getIndexToFocusNext = menu => {
2405
+ const startIndex = menu.focusedIndex + 1;
2406
+ return getIndexToFocusNextStartingAt(menu.items, startIndex);
2407
+ };
2408
+ const focusNext = async () => {
2409
+ const menu = getCurrentMenu();
2410
+ if (menu.items.length === 0) {
2411
+ return;
2412
+ }
2413
+ const indexToFocus = getIndexToFocusNext(menu);
2414
+ await focusIndex(menu, indexToFocus);
2415
+ };
2416
+
2310
2417
  const commandsIds = ['closeMenu', 'handleClickAt', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusPrevious', 'handleClick', 'handleFocus', 'handleFocusOut', 'handleKeyArrowDown', 'handleKeyArrowLeft', 'handleKeyArrowRight', 'handleKeyArrowUp', 'handleKeyEnd', 'handleKeyEnter', 'handleKeyEscape', 'handleKeyHome', 'handleKeySpace', 'handleMenuClick', 'handleMenuMouseOver', 'handleMouseOut', 'handleMouseOver', 'handlePointerOver', 'handlePointerOut', 'toggleIndex', 'toggleMenu'];
2311
2418
 
2312
2419
  const getCommandIds = () => {
@@ -2457,6 +2564,95 @@ const handleContextMenu = state => {
2457
2564
  return state;
2458
2565
  };
2459
2566
 
2567
+ const hideSubMenus = async level => {
2568
+ if (level < getCount()) {
2569
+ set$1(getAll().slice(0, level + 1));
2570
+ return {
2571
+ commands: [/* Menu.hideSubMenu */'Menu.hideSubMenu', /* level */level + 1],
2572
+ menus: getAll()
2573
+ };
2574
+ }
2575
+ };
2576
+
2577
+ const showSubMenuAtEnter = async (level, index, enterX, enterY) => {
2578
+ // TODO delete old menus
2579
+ set$1(getAll().slice(0, level + 1));
2580
+ const parentMenu = get$1(level);
2581
+ const item = parentMenu.items[index];
2582
+ const subMenuItems = await getMenuEntries$1(item.id);
2583
+ const subMenu = addMenuInternal({
2584
+ id: item.id,
2585
+ items: subMenuItems,
2586
+ focusedIndex: -1,
2587
+ level: getCount(),
2588
+ y: parentMenu.y + index * 25,
2589
+ x: parentMenu.x + MENU_WIDTH,
2590
+ enterX,
2591
+ enterY
2592
+ });
2593
+ const width = getMenuWidth();
2594
+ const height = getMenuHeight$2(subMenuItems);
2595
+ const visible = getVisible(subMenu.items, -1, false, subMenu.level);
2596
+ const dom = getMenuVirtualDom(visible).slice(1);
2597
+ return {
2598
+ commands: [/* Menu.showMenu */'Menu.showMenu', /* x */subMenu.x, /* y */subMenu.y, /* width */width, /* height */height, /* items */subMenu.items, /* level */subMenu.level, /* parentIndex */index, /* dom */dom],
2599
+ menus: getAll()
2600
+ };
2601
+ };
2602
+ const showSubMenu = async (level, index) => {
2603
+ return showSubMenuAtEnter(level, index, -1, -1);
2604
+ };
2605
+
2606
+ /* eslint-disable @typescript-eslint/no-implied-eval */
2607
+ const MENU_DELAY_TRIANGLE = 300;
2608
+ const resolveAfterTimeout = fn => {
2609
+ setTimeout(fn, MENU_DELAY_TRIANGLE);
2610
+ };
2611
+ const handleMouseEnter = async (level, index, enterX, enterY, enterTimeStamp) => {
2612
+ setTimestamp(enterTimeStamp);
2613
+ if (level >= getCount()) {
2614
+ return;
2615
+ }
2616
+ const menu = get$1(level);
2617
+ if (menu.focusedIndex === index) {
2618
+ return;
2619
+ }
2620
+ if (level < getCount() - 1) {
2621
+ const subMenu = get$1(level + 1);
2622
+ const subMenuEnterX = subMenu.enterX;
2623
+ // TODO should check for triangle position here
2624
+ if (enterX >= subMenuEnterX) {
2625
+ await new Promise(resolveAfterTimeout);
2626
+ if (getLatestTimestamp() !== enterTimeStamp) {
2627
+ return;
2628
+ }
2629
+ }
2630
+ }
2631
+ const item = menu.items[index];
2632
+ await focusIndex(menu, index);
2633
+ switch (item.flags) {
2634
+ case /* SubMenu */4:
2635
+ await showSubMenuAtEnter(menu.level, index, enterX, enterY);
2636
+ break;
2637
+ default:
2638
+ await hideSubMenus(menu.level);
2639
+ break;
2640
+ }
2641
+ };
2642
+
2643
+ const handleMouseLeave = async () => {
2644
+ const menu = get$1(0);
2645
+ if (menu.items.length === 0) {
2646
+ return;
2647
+ }
2648
+ const oldFocusedIndex = menu.focusedIndex;
2649
+ menu.focusedIndex = -1;
2650
+ return {
2651
+ commands: [/* Menu.focusIndex */'Menu.focusIndex', /* level */menu.level, /* oldFocusedIndex */oldFocusedIndex, /* newFocusedIndex */-1],
2652
+ menus: getAll()
2653
+ };
2654
+ };
2655
+
2460
2656
  const loadContent = async (state, titleBarEntries) => {
2461
2657
  return {
2462
2658
  ...state
@@ -2584,28 +2780,34 @@ const wrapCommand = fn => {
2584
2780
  };
2585
2781
 
2586
2782
  const commandMap = {
2587
- 'Menu.getMenuEntries': getMenuEntries,
2588
- 'Menu.getMenuIds': getMenuIds,
2589
- 'Menu.handleContextMenu': handleContextMenu,
2590
- 'Menu.renderEventListeners': renderEventListeners,
2591
2783
  'Menu.diff2': diff2,
2784
+ 'Menu.focusFirst': focusFirst,
2785
+ 'Menu.focusNext': focusNext,
2592
2786
  'Menu.getCommands': getCommandIds,
2787
+ 'Menu.getHideCommands': getMenuHideCommands,
2593
2788
  'Menu.getKeyBindings': getKeyBindings,
2789
+ 'Menu.getMenuEntries': getMenuEntries,
2790
+ 'Menu.getMenuIds': getMenuIds,
2594
2791
  'Menu.getMenus': getMenus,
2792
+ 'Menu.getShowCommands': getMenuShowCommands,
2793
+ 'Menu.handleContextMenu': handleContextMenu,
2794
+ 'Menu.handleMouseEnter': handleMouseEnter,
2795
+ 'Menu.handleMouseLeave': handleMouseLeave,
2796
+ 'Menu.hideSubMenus': hideSubMenus,
2595
2797
  'Menu.loadContent': wrapCommand(loadContent),
2596
2798
  'Menu.render2': render2,
2799
+ 'Menu.renderEventListeners': renderEventListeners,
2597
2800
  'Menu.saveState': saveState,
2598
2801
  'Menu.show': show,
2599
2802
  'Menu.show2': show2,
2600
- 'Menu.getShowCommands': getMenuShowCommands,
2601
- 'Menu.getHideCommands': getMenuHideCommands
2803
+ 'Menu.showSubMenu': showSubMenu
2602
2804
  };
2603
2805
 
2604
2806
  const listen = async () => {
2605
2807
  const rpc = await WebWorkerRpcClient.create({
2606
2808
  commandMap: commandMap
2607
2809
  });
2608
- set$1(rpc);
2810
+ set$2(rpc);
2609
2811
  };
2610
2812
 
2611
2813
  const main = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/menu-worker",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Menu Worker",
5
5
  "repository": {
6
6
  "type": "git",