@inboxsdk/core 0.2.29-alpha.3 → 0.2.29-alpha.5

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 (24) hide show
  1. package/inboxsdk.js +34 -33
  2. package/inboxsdk.js.map +1 -1
  3. package/package.json +2 -1
  4. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-app-menu-item.d.ts.map +1 -1
  5. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-app-menu-item.js +3 -4
  6. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.d.ts +1 -1
  7. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.d.ts.map +1 -1
  8. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.js +14 -4
  9. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.d.ts +5 -1
  10. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.d.ts.map +1 -1
  11. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.js +32 -20
  12. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.d.ts +2 -0
  13. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.d.ts.map +1 -1
  14. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.js +17 -12
  15. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.d.ts +4 -12
  16. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.d.ts.map +1 -1
  17. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.js +30 -18
  18. package/src/platform-implementation-js/namespaces/app-menu.d.ts +15 -4
  19. package/src/platform-implementation-js/namespaces/app-menu.d.ts.map +1 -1
  20. package/src/platform-implementation-js/views/app-menu-item-view.d.ts.map +1 -1
  21. package/src/platform-implementation-js/views/app-menu-item-view.js +81 -27
  22. package/src/platform-implementation-js/views/collapsible-panel-view.d.ts +8 -7
  23. package/src/platform-implementation-js/views/collapsible-panel-view.d.ts.map +1 -1
  24. package/src/platform-implementation-js/views/collapsible-panel-view.js +104 -52
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inboxsdk/core",
3
- "version": "0.2.29-alpha.3",
3
+ "version": "0.2.29-alpha.5",
4
4
  "description": "Library for building browser extensions for Gmail",
5
5
  "main": "inboxsdk.js",
6
6
  "author": "Streak",
@@ -31,6 +31,7 @@
31
31
  "@types/kefir": "^3.8.6",
32
32
  "@types/node": "*",
33
33
  "asap": "^2.0.3",
34
+ "fast-deep-equal": "^3.1.3",
34
35
  "kefir-cast": "^3.3.0",
35
36
  "sha.js": "^2.4.0",
36
37
  "tag-tree": "^1.0.0",
@@ -1 +1 @@
1
- {"version":3,"file":"add-app-menu-item.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-app-menu-item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAI1C,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,kBAAkB,EAAE,qBAAqB,6CAuB1C"}
1
+ {"version":3,"file":"add-app-menu-item.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-app-menu-item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAI1C,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,kBAAkB,EAAE,qBAAqB,6CAyB1C"}
@@ -3,12 +3,11 @@ import GmailElementGetter from '../gmail-element-getter';
3
3
  import Logger from '../../../lib/logger';
4
4
  export async function addAppMenuItem(driver, menuItemDescriptor) {
5
5
  const appMenuInjectionContainer = await GmailElementGetter.getAppMenuAsync();
6
- const gmailAppMenuItemView = new GmailAppMenuItemView(driver);
7
- gmailAppMenuItemView.setMenuItemDescriptor(menuItemDescriptor);
6
+ const gmailAppMenuItemView = new GmailAppMenuItemView(driver, menuItemDescriptor);
8
7
  try {
9
- if (!appMenuInjectionContainer || !gmailAppMenuItemView.element)
8
+ if (!appMenuInjectionContainer)
10
9
  return;
11
- const siblingElement = menuItemDescriptor.insertIndex
10
+ const siblingElement = Number.isInteger(menuItemDescriptor.insertIndex)
12
11
  ? appMenuInjectionContainer.childNodes[menuItemDescriptor.insertIndex] ??
13
12
  null
14
13
  : null;
@@ -1,5 +1,5 @@
1
1
  import { AppMenuItemPanelDescriptor } from '../../../namespaces/app-menu';
2
2
  import { CollapsiblePanelView } from '../../../views/collapsible-panel-view';
3
3
  import GmailDriver from '../gmail-driver';
4
- export declare function addCollapsiblePanel(driver: GmailDriver, panelDescriptor: AppMenuItemPanelDescriptor): Promise<CollapsiblePanelView | undefined>;
4
+ export declare function addCollapsiblePanel(driver: GmailDriver, panelDescriptor: AppMenuItemPanelDescriptor, insertIndex?: number): Promise<CollapsiblePanelView | undefined>;
5
5
  //# sourceMappingURL=add-collapsible-panel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"add-collapsible-panel.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAI1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,0BAA0B,6CAgB5C"}
1
+ {"version":3,"file":"add-collapsible-panel.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAI1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,0BAA0B,EAC3C,WAAW,CAAC,EAAE,MAAM,6CAmCrB"}
@@ -3,16 +3,26 @@ import GmailElementGetter from '../gmail-element-getter';
3
3
  import waitFor from '../../../lib/wait-for';
4
4
  import Logger from '../../../lib/logger';
5
5
  import { CollapsiblePanelView } from '../../../views/collapsible-panel-view';
6
- export async function addCollapsiblePanel(driver, panelDescriptor) {
6
+ export async function addCollapsiblePanel(driver, panelDescriptor, insertIndex) {
7
7
  const injectionContainer = await waitForAppMenuParentReady();
8
- const collapsiblePanelView = new CollapsiblePanelView(driver);
9
- collapsiblePanelView.panelDescriptor = panelDescriptor;
8
+ const collapsiblePanelView = new CollapsiblePanelView(driver, panelDescriptor);
10
9
  if (!injectionContainer || !collapsiblePanelView.element)
11
10
  return;
12
11
  const appMenu = await GmailElementGetter.getAppMenuAsync();
13
12
  if (!appMenu)
14
13
  return;
15
- appMenu.insertAdjacentElement('afterend', collapsiblePanelView.element);
14
+ const panelNodes = injectionContainer.querySelectorAll(CollapsiblePanelView.elementSelectors.NATIVE) ?? [];
15
+ const siblingElement = Number.isInteger(insertIndex)
16
+ ? panelNodes[insertIndex] ?? null
17
+ : null;
18
+ if (siblingElement) {
19
+ siblingElement.insertAdjacentElement('beforebegin', collapsiblePanelView.element);
20
+ }
21
+ else {
22
+ [...panelNodes]
23
+ .at(-1)
24
+ ?.insertAdjacentElement('afterend', collapsiblePanelView.element);
25
+ }
16
26
  return collapsiblePanelView;
17
27
  }
18
28
  const waitForAppMenuParentReady = once(async () => {
@@ -1,2 +1,6 @@
1
- export default function trackGmailStyles(): void;
1
+ export declare const stylesStream: import("kefir-bus").Bus<{
2
+ type: 'theme';
3
+ isDarkMode: boolean;
4
+ }, unknown>;
5
+ export default function trackGmailStyles(): Promise<void>;
2
6
  //# sourceMappingURL=track-gmail-styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"track-gmail-styles.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.ts"],"names":[],"mappings":"AAsDA,MAAM,CAAC,OAAO,UAAU,gBAAgB,SAwDvC"}
1
+ {"version":3,"file":"track-gmail-styles.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.ts"],"names":[],"mappings":"AAyDA,eAAO,MAAM,YAAY;UACf,OAAO;gBAAc,OAAO;WAEnC,CAAC;AAEJ,wBAA8B,gBAAgB,kBAmE7C"}
@@ -1,3 +1,4 @@
1
+ import kefirBus from 'kefir-bus';
1
2
  import Logger from '../../../lib/logger';
2
3
  import waitFor from '../../../lib/wait-for';
3
4
  import GmailElementGetter from '../gmail-element-getter';
@@ -21,10 +22,11 @@ function getDensity() {
21
22
  return 'compact';
22
23
  }
23
24
  }
25
+ const navItemSelector = '.aio';
24
26
  function isDarkTheme() {
25
27
  // get the color of the left-nav-menu entries to determine whether Gmail is
26
28
  // in dark theme mode.
27
- const navItem = document.querySelector('.aio');
29
+ const navItem = document.querySelector(navItemSelector);
28
30
  if (!navItem) {
29
31
  Logger.error(new Error('Failed to find nav item'));
30
32
  return false;
@@ -45,7 +47,8 @@ function isDarkTheme() {
45
47
  }
46
48
  return r > 128;
47
49
  }
48
- export default function trackGmailStyles() {
50
+ export const stylesStream = kefirBus();
51
+ export default async function trackGmailStyles() {
49
52
  if (document.head.hasAttribute('data-inboxsdk-gmail-style-tracker') ||
50
53
  GmailElementGetter.isStandalone()) {
51
54
  return;
@@ -71,25 +74,34 @@ export default function trackGmailStyles() {
71
74
  else {
72
75
  document.body.classList.remove('inboxsdk__gmail_dark_theme');
73
76
  }
77
+ stylesStream.emit({
78
+ type: 'theme',
79
+ isDarkMode: newDarkTheme,
80
+ });
74
81
  }
75
82
  }
76
- waitFor(() => document.querySelector('.TO .TN') && document.querySelector('.aio'))
77
- .then(() => {
78
- // Gmail changes an inline <style> sheet when the display density changes.
79
- // Watch for changes to all <style> elements.
80
- const observer = new MutationObserver(checkStyles);
81
- const options = {
82
- characterData: true,
83
- childList: true,
84
- };
85
- Array.from(document.styleSheets).forEach((sheet) => {
86
- if (sheet.ownerNode.tagName == 'STYLE') {
87
- observer.observe(sheet.ownerNode, options);
88
- }
89
- });
90
- checkStyles();
91
- })
92
- .catch((err) => {
83
+ try {
84
+ await waitFor(() => document.querySelector('.TO .TN') &&
85
+ document.querySelector(navItemSelector));
86
+ }
87
+ catch (err) {
93
88
  Logger.error(err);
94
- });
89
+ return;
90
+ }
91
+ // Gmail changes an inline <style> sheet when the display density changes.
92
+ // Watch for changes to all <style> elements.
93
+ const observer = new MutationObserver(checkStyles);
94
+ const options = {
95
+ characterData: true,
96
+ childList: true,
97
+ };
98
+ for (const sheet of document.styleSheets) {
99
+ if (!(sheet.ownerNode instanceof Element)) {
100
+ continue;
101
+ }
102
+ if (sheet.ownerNode.tagName == 'STYLE') {
103
+ observer.observe(sheet.ownerNode, options);
104
+ }
105
+ }
106
+ checkStyles();
95
107
  }
@@ -21,6 +21,8 @@ declare const GmailElementGetter: {
21
21
  getAppMenuAsync: () => Promise<HTMLElement | undefined>;
22
22
  isAppBurgerMenuOpen(): boolean;
23
23
  getAppMenuContainer(): HTMLElement | null;
24
+ getAppMenu(): HTMLElement | null;
25
+ getAppHeader(): HTMLElement | null;
24
26
  getSeparateSectionNavItemMenuInjectionContainer(): HTMLElement | null;
25
27
  getSameSectionNavItemMenuInjectionContainer(): HTMLElement | null;
26
28
  getRowListElements(): HTMLElement[];
@@ -1 +1 @@
1
- {"version":3,"file":"gmail-element-getter.d.ts","sourceRoot":"","sources":["../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAA+B,EAC7B,mBAAmB,EACpB,MAAM,yCAAyC,CAAC;AAUjD,QAAA,MAAM,kBAAkB;yBACD,WAAW,GAAG,IAAI;uCAcJ,WAAW,GAAG,IAAI;kDAKP,WAAW,GAAG,IAAI;+CAKrB,WAAW,GAAG,IAAI;wBAIzC,WAAW,GAAG,IAAI;iCAOT,WAAW,GAAG,IAAI;gCAInB,WAAW,GAAG,SAAS,GAAG,IAAI;2CA8BnB,WAAW,GAAG,IAAI;iDAIZ,MAAM,UAAU,CAC3D,mBAAmB,EACnB,KAAK,CACN;uBAgBkB,WAAW,GAAG,IAAI;kCAIP,WAAW,GAAG,IAAI;+BAOrB,WAAW,GAAG,IAAI;0CAIP,WAAW,GAAG,IAAI;+BAI7B,WAAW,GAAG,IAAI;+CAQrC,GAAG,KACR,MAAM,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC;qBAItB,WAAW,GAAG,IAAI;+BAOR,OAAO;;;;uDAqFiB,WAAW,GAAG,IAAI;mDAItB,WAAW,GAAG,IAAI;0BAQ3C,WAAW,EAAE;0BAIb,WAAW,GAAG,IAAI;sBAItB,gBAAgB,GAAG,IAAI;qCAMR,WAAW,GAAG,IAAI;kCAIrB,WAAW,GAAG,IAAI;2BAIzB,WAAW,GAAG,IAAI;iCAWZ,WAAW,GAAG,IAAI;yBAI1B,WAAW;8BAIN,WAAW,GAAG,IAAI;sBAM1B,OAAO;mBAaV,OAAO;qBAIL,OAAO;oBAIR,OAAO;iCAIM,OAAO;gCAOR,OAAO;;qCASJ,WAAW,GAAG,IAAI;;gCAKrB,QAAQ,IAAI,CAAC;CAG1C,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"gmail-element-getter.d.ts","sourceRoot":"","sources":["../../../../../../src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAA+B,EAC7B,mBAAmB,EACpB,MAAM,yCAAyC,CAAC;AAmBjD,QAAA,MAAM,kBAAkB;yBACD,WAAW,GAAG,IAAI;uCAcJ,WAAW,GAAG,IAAI;kDAKP,WAAW,GAAG,IAAI;+CAKrB,WAAW,GAAG,IAAI;wBAIzC,WAAW,GAAG,IAAI;iCAOT,WAAW,GAAG,IAAI;gCAInB,WAAW,GAAG,SAAS,GAAG,IAAI;2CA8BnB,WAAW,GAAG,IAAI;iDAIZ,MAAM,UAAU,CAC3D,mBAAmB,EACnB,KAAK,CACN;uBAgBkB,WAAW,GAAG,IAAI;kCAIP,WAAW,GAAG,IAAI;+BAUrB,WAAW,GAAG,IAAI;0CAIP,WAAW,GAAG,IAAI;+BAI7B,WAAW,GAAG,IAAI;+CAQrC,GAAG,KACR,MAAM,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC;qBAItB,WAAW,GAAG,IAAI;+BAOR,OAAO;;;;;;uDAgFiB,WAAW,GAAG,IAAI;mDAItB,WAAW,GAAG,IAAI;0BAQ3C,WAAW,EAAE;0BAIb,WAAW,GAAG,IAAI;sBAItB,gBAAgB,GAAG,IAAI;qCAMR,WAAW,GAAG,IAAI;kCAIrB,WAAW,GAAG,IAAI;2BAIzB,WAAW,GAAG,IAAI;iCAWZ,WAAW,GAAG,IAAI;yBAI1B,WAAW;8BAIN,WAAW,GAAG,IAAI;sBAM1B,OAAO;mBAaV,OAAO;qBAIL,OAAO;oBAIR,OAAO;iCAIM,OAAO;gCAOR,OAAO;;qCASJ,WAAW,GAAG,IAAI;;gCAKrB,QAAQ,IAAI,CAAC;CAG1C,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -7,6 +7,14 @@ import getMainContentElementChangedStream from './gmail-element-getter/get-main-
7
7
  import isIntegratedViewGmail from './gmail-driver/isIntegratedViewGmail';
8
8
  import Logger from '../../lib/logger';
9
9
  import waitFor from '../../lib/wait-for';
10
+ /**
11
+ * The selector for the new app menu https://support.google.com/mail/answer/11555490 -- FEB 2023
12
+ */
13
+ const APP_MENU = '.aeN.WR.a6o.anZ.nH.oy8Mbf[role=navigation]';
14
+ /**
15
+ * If the APP_MENU selector is not found, NAV_MENU _might_ be present.
16
+ */
17
+ const NAV_MENU = '.aeN.WR.nH.oy8Mbf[role=navigation]';
10
18
  // TODO Figure out if these functions can and should be able to return null
11
19
  const GmailElementGetter = {
12
20
  getActiveMoreMenu() {
@@ -81,6 +89,9 @@ const GmailElementGetter = {
81
89
  return document.querySelector('.aeN .aj5.J-KU-Jg');
82
90
  },
83
91
  getLeftNavContainerElement() {
92
+ if (this.getAppMenu()) {
93
+ return this.getAppMenuContainer()?.querySelector('.aqn.aIH') ?? null;
94
+ }
84
95
  if (isIntegratedViewGmail()) {
85
96
  return document.querySelector('div[role=navigation] + div.aqn');
86
97
  }
@@ -144,14 +155,6 @@ const GmailElementGetter = {
144
155
  getAppMenuAsync: once(async () => {
145
156
  if (!GmailElementGetter.isStandalone()) {
146
157
  await GmailElementGetter.waitForGmailModeToSettle();
147
- /**
148
- * The selector for the new app menu https://support.google.com/mail/answer/11555490 -- FEB 2023
149
- */
150
- const APP_MENU = '.aeN.WR.a6o.anZ.nH.oy8Mbf[role=navigation]';
151
- /**
152
- * If the APP_MENU selector is not found, NAV_MENU _might_ be present.
153
- */
154
- const NAV_MENU = '.aeN.WR.nH.oy8Mbf[role=navigation]';
155
158
  try {
156
159
  const element = await waitFor(() => document.querySelector(`${APP_MENU}, ${NAV_MENU}`));
157
160
  if (!document.querySelector(APP_MENU)) {
@@ -172,10 +175,12 @@ const GmailElementGetter = {
172
175
  getAppMenuContainer() {
173
176
  return document.querySelector('.aqk.aql.bkL');
174
177
  },
175
- // TODO figure out if we use it
176
- // getNavMenu() {
177
- // return document.querySelector('.aeN.WR.nH.oy8Mbf[role=navigation]');
178
- // },
178
+ getAppMenu() {
179
+ return document.querySelector(APP_MENU);
180
+ },
181
+ getAppHeader() {
182
+ return document.querySelector('.oy8Mbf.qp');
183
+ },
179
184
  getSeparateSectionNavItemMenuInjectionContainer() {
180
185
  return document.querySelector('.aeN');
181
186
  },
@@ -17,19 +17,11 @@ export declare class GmailAppMenuItemView extends GmailAppMenuItemView_base {
17
17
  readonly HOVER: "aIk";
18
18
  readonly ACTIVE: "apV";
19
19
  };
20
- get element(): HTMLElement | undefined;
21
- setMenuItemDescriptor(newMenuItemDescriptor: AppMenuItemDescriptor): void;
22
- get menuItemDescriptor(): AppMenuItemDescriptor | undefined;
23
- constructor(driver: GmailDriver);
20
+ get element(): HTMLElement;
21
+ set menuItemDescriptor(newMenuItemDescriptor: AppMenuItemDescriptor);
22
+ get menuItemDescriptor(): AppMenuItemDescriptor;
23
+ constructor(driver: GmailDriver, menuItemDescriptor: AppMenuItemDescriptor);
24
24
  remove(): void;
25
- /**
26
- * @internal
27
- */
28
- blur(): void;
29
- /**
30
- * @internal
31
- */
32
- hover(): void;
33
25
  }
34
26
  export {};
35
27
  //# sourceMappingURL=gmail-app-menu-item-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gmail-app-menu-item-view.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,OAAO,iBAAiB,MAAM,eAAe,CAAC;AAK9C,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,YAAY,MAAgB,CAAC;AAC1C,eAAO,MAAM,cAAc,yBAAmC,CAAC;AAC/D,eAAO,MAAM,aAAa,4BAA+C,CAAC;mDAOL,kBAAkB,aAAa,CAAC;AAArG,qBAAa,oBAAqB,SAAQ,yBAA4D;;IACpG,MAAM,CAAC,UAAU;;;MAGN;IAOX,IAAI,OAAO,4BAEV;IAED,qBAAqB,CAAC,qBAAqB,EAAE,qBAAqB;IAKlE,IAAI,kBAAkB,sCAErB;gBAEW,MAAM,EAAE,WAAW;IAc/B,MAAM;IAON;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;CAqFN"}
1
+ {"version":3,"file":"gmail-app-menu-item-view.d.ts","sourceRoot":"","sources":["../../../../../../../src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,OAAO,iBAAiB,MAAM,eAAe,CAAC;AAO9C,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,YAAY,MAAgB,CAAC;AAC1C,eAAO,MAAM,cAAc,yBAAmC,CAAC;AAC/D,eAAO,MAAM,aAAa,4BAA+C,CAAC;mDAOL,kBAAkB,aAAa,CAAC;AAArG,qBAAa,oBAAqB,SAAQ,yBAA4D;;IACpG,MAAM,CAAC,UAAU;;;MAGN;IAOX,IAAI,OAAO,gBAEV;IAED,IAAI,kBAAkB,CAAC,qBAAqB,uBAAA,EAG3C;IAED,IAAI,kBAAkB,0BAErB;gBAEW,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB;IAwB1E,MAAM;CA6GP"}
@@ -2,6 +2,8 @@ import querySelector from '../../../lib/dom/querySelectorOrFail';
2
2
  import { EventEmitter } from 'events';
3
3
  import cx from 'classnames';
4
4
  import GmailElementGetter from '../gmail-element-getter';
5
+ import { stylesStream } from '../gmail-driver/track-gmail-styles';
6
+ import isEqual from 'fast-deep-equal';
5
7
  export const NATIVE_CLASS = 'Xa';
6
8
  export const INBOXSDK_CLASS = 'inboxsdk__appMenuItem';
7
9
  export const ELEMENT_CLASS = `${NATIVE_CLASS} ${INBOXSDK_CLASS}`;
@@ -21,17 +23,26 @@ export class GmailAppMenuItemView extends EventEmitter {
21
23
  get element() {
22
24
  return this.#element;
23
25
  }
24
- setMenuItemDescriptor(newMenuItemDescriptor) {
26
+ set menuItemDescriptor(newMenuItemDescriptor) {
25
27
  this.#menuItemDescriptor = newMenuItemDescriptor;
26
28
  this.#update();
27
29
  }
28
30
  get menuItemDescriptor() {
29
31
  return this.#menuItemDescriptor;
30
32
  }
31
- constructor(driver) {
33
+ constructor(driver, menuItemDescriptor) {
32
34
  super();
33
35
  this.#element = this.#setupElement();
34
36
  this.#driver = driver;
37
+ this.#menuItemDescriptor = menuItemDescriptor;
38
+ this.#update();
39
+ stylesStream
40
+ .skipDuplicates((a, b) => isEqual(a, b))
41
+ .onValue(({ type }) => {
42
+ if (type === 'theme') {
43
+ this.#update();
44
+ }
45
+ });
35
46
  driver.getStopper().onValue(() => this.remove());
36
47
  this.#element.addEventListener('click', (e) => this.#onClick(e));
37
48
  this.#element.addEventListener('mouseleave', this.#onBlur);
@@ -44,21 +55,6 @@ export class GmailAppMenuItemView extends EventEmitter {
44
55
  this.element?.remove();
45
56
  this.emit('destroy');
46
57
  }
47
- /**
48
- * @internal
49
- */
50
- blur() {
51
- this.element?.classList.remove(GmailAppMenuItemView.elementCss.HOVER);
52
- }
53
- /**
54
- * @internal
55
- */
56
- hover() {
57
- if (this.element?.classList.contains(GmailAppMenuItemView.elementCss.ACTIVE)) {
58
- return;
59
- }
60
- this.element?.classList.add(GmailAppMenuItemView.elementCss.HOVER);
61
- }
62
58
  #setupElement() {
63
59
  const element = document.createElement('div');
64
60
  element.className = ELEMENT_CLASS;
@@ -72,7 +68,8 @@ export class GmailAppMenuItemView extends EventEmitter {
72
68
  const element = this.element;
73
69
  if (!element)
74
70
  return;
75
- element.className = cx(ELEMENT_CLASS, this.#menuItemDescriptor?.className);
71
+ const existingClassNames = Object.values(GmailAppMenuItemView.elementCss).filter((className) => element.classList.contains(className));
72
+ element.className = cx(ELEMENT_CLASS, this.#menuItemDescriptor?.className, ...existingClassNames);
76
73
  this.#updateName(element);
77
74
  this.#updateIcon(element);
78
75
  this.#updateARIA(element);
@@ -81,6 +78,7 @@ export class GmailAppMenuItemView extends EventEmitter {
81
78
  const headingElement = querySelector(element, HEADING_ELEMENT_SELECTOR);
82
79
  headingElement.textContent = this.#menuItemDescriptor?.name ?? '';
83
80
  }
81
+ static #preloadedIcons = new Set();
84
82
  #updateIcon(element) {
85
83
  const iconContainerEl = querySelector(element, ICON_ELEMENT_SELECTOR);
86
84
  const { iconUrl, iconClassName } = this.#menuItemDescriptor ?? {};
@@ -88,8 +86,22 @@ export class GmailAppMenuItemView extends EventEmitter {
88
86
  const rawTheme = GmailElementGetter.isDarkTheme()
89
87
  ? iconUrl.darkTheme
90
88
  : iconUrl.lightTheme;
89
+ if (!rawTheme)
90
+ return;
91
91
  const theme = typeof rawTheme === 'string' ? rawTheme : rawTheme.default;
92
92
  const activeImg = typeof rawTheme === 'string' ? rawTheme : rawTheme.active;
93
+ // alleviate FOUC when switching between active and default icons
94
+ // https://stackoverflow.com/a/68521953/1924257
95
+ for (const url of [theme, activeImg]) {
96
+ if (GmailAppMenuItemView.#preloadedIcons.has(url))
97
+ continue;
98
+ GmailAppMenuItemView.#preloadedIcons.add(url);
99
+ var link = document.createElement('link');
100
+ link.rel = 'preload';
101
+ link.as = 'image';
102
+ link.href = url;
103
+ document.head.appendChild(link);
104
+ }
93
105
  iconContainerEl.style.setProperty('--background-image', `url(${theme})`);
94
106
  iconContainerEl.style.setProperty('--background-image--active', `url(${activeImg})`);
95
107
  }
@@ -8,8 +8,8 @@ type ThemedIcon = string | {
8
8
  export type AppMenuItemDescriptor = {
9
9
  name: string;
10
10
  iconUrl?: {
11
- darkTheme: ThemedIcon;
12
- lightTheme: ThemedIcon;
11
+ darkTheme?: ThemedIcon;
12
+ lightTheme?: ThemedIcon;
13
13
  };
14
14
  className?: string;
15
15
  iconClassName?: string;
@@ -28,14 +28,25 @@ export type AppMenuItemDescriptor = {
28
28
  */
29
29
  isRouteActive: (routeView: RouteView) => boolean;
30
30
  };
31
+ /**
32
+ * In dark themes, Gmail has different colored primary buttons depending on hover or active state
33
+ */
34
+ type PanelPrimaryButtonThemedIcon = string | {
35
+ panelHovered: string;
36
+ panelDefault: string;
37
+ };
31
38
  export type AppMenuItemPanelDescriptor = {
32
39
  className?: string;
40
+ /** In the form of HTML as a string.
41
+ *
42
+ * If this option is provided, the panel defaults to loading=true. */
43
+ loadingIcon?: string;
33
44
  primaryButton?: {
34
45
  name: string;
35
46
  onClick: (e: MouseEvent) => void;
36
47
  iconUrl?: {
37
- darkTheme: string;
38
- lightTheme: string;
48
+ darkTheme?: PanelPrimaryButtonThemedIcon;
49
+ lightTheme?: PanelPrimaryButtonThemedIcon;
39
50
  };
40
51
  className?: string;
41
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"app-menu.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/namespaces/app-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,KAAK,UAAU,GACX,MAAM,GACN;IACE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,UAAU,CAAC;QACtB,UAAU,EAAE,UAAU,CAAC;KACxB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,EAAE,CAAC;IACjB;;;;OAIG;IACH,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;QACjC,OAAO,CAAC,EAAE;YACR,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,OAAO;;gBAGd,MAAM,EAAE,WAAW;IAI/B,WAAW,CAAC,kBAAkB,EAAE,qBAAqB,GAAG,eAAe;IAKjE,OAAO;CAId"}
1
+ {"version":3,"file":"app-menu.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/namespaces/app-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,KAAK,UAAU,GACX,MAAM,GACN;IACE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,UAAU,CAAC;QACvB,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,EAAE,CAAC;IACjB;;;;OAIG;IACH,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,KAAK,4BAA4B,GAC7B,MAAM,GACN;IACE,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;0EAEsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;QACjC,OAAO,CAAC,EAAE;YACR,SAAS,CAAC,EAAE,4BAA4B,CAAC;YACzC,UAAU,CAAC,EAAE,4BAA4B,CAAC;SAC3C,CAAC;QACF,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,OAAO;;gBAGd,MAAM,EAAE,WAAW;IAI/B,WAAW,CAAC,kBAAkB,EAAE,qBAAqB,GAAG,eAAe;IAKjE,OAAO;CAId"}
@@ -1 +1 @@
1
- {"version":3,"file":"app-menu-item-view.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/views/app-menu-item-view.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAUzC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAK3D,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;8CAyC8D,aAAa,aAAa,CAAC;AAH3F;;GAEG;AACH,qBAAa,eAAgB,SAAQ,oBAAuD;;IAiT1F,IAAI,kBAAkB,0BAErB;gBAQW,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB;IAuDpE,mBAAmB,CAAC,eAAe,EAAE,0BAA0B;IAiC/D,MAAM,CAAC,kBAAkB,EAAE,qBAAqB;IAMtD,MAAM;CAYP"}
1
+ {"version":3,"file":"app-menu-item-view.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/views/app-menu-item-view.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAWzC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAK3D,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;8CA0C8D,aAAa,aAAa,CAAC;AAH3F;;GAEG;AACH,qBAAa,eAAgB,SAAQ,oBAAuD;;IA8W1F,IAAI,kBAAkB,0BAErB;gBAQW,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB;IAsDpE,mBAAmB,CAAC,eAAe,EAAE,0BAA0B;IA2C/D,MAAM,CAAC,kBAAkB,EAAE,qBAAqB;IAMtD,MAAM;CAaP"}
@@ -1,5 +1,6 @@
1
1
  import Kefir from 'kefir';
2
2
  import kefirBus from 'kefir-bus';
3
+ import cx from 'classnames';
3
4
  import EventEmitter from '../lib/safe-event-emitter';
4
5
  import { GmailAppMenuItemView, NATIVE_CLASS, INBOXSDK_CLASS, } from '../dom-driver/gmail/views/gmail-app-menu-item-view';
5
6
  import { NATIVE_CLASS as PANEL_NATIVE_CLASS, CollapsiblePanelView, } from './collapsible-panel-view';
@@ -55,10 +56,35 @@ export class AppMenuItemView extends EventEmitter {
55
56
  const button = appMenuElement?.querySelector(`.${NATIVE_CLASS}.${ACTIVE}`);
56
57
  return button;
57
58
  }
59
+ static #isPanelLess() {
60
+ const activePanel = AppMenuItemView.#getActivePanel();
61
+ return !activePanel;
62
+ }
63
+ static #adjustTooltipNub() {
64
+ // adjust all menu items' collapsible panel's tooltip nub position
65
+ const appMenuElement = GmailElementGetter.getAppMenu();
66
+ for (const menuItem of appMenuElement?.querySelectorAll(`.${NATIVE_CLASS}`) ?? []) {
67
+ const panel = AppMenuItemView.#menuItemToPanelMap.get(menuItem);
68
+ if (!panel)
69
+ continue;
70
+ const nubElement = panel?.querySelector('* > .aTV');
71
+ const iconElement = menuItem?.querySelector('.V6');
72
+ const iconElementBox = iconElement?.getBoundingClientRect();
73
+ const offsetTop = (iconElement?.offsetTop ?? 0) + (iconElementBox?.height ?? 0) * 0.5;
74
+ const nubSide = 17;
75
+ const nubDiagonal = nubSide * Math.sqrt(2);
76
+ const offsetNub = nubDiagonal / 4;
77
+ const offset = offsetTop - offsetNub;
78
+ if (nubElement && offset) {
79
+ nubElement.style.top = `${offset}px`;
80
+ }
81
+ }
82
+ }
58
83
  static #setUpRouteViewDriverStream(driver) {
59
84
  if (AppMenuItemView.#routeViewDriverStream)
60
85
  return;
61
86
  AppMenuItemView.#routeViewDriverStream = driver.getRouteViewDriverStream();
87
+ // Activate menu items on route changes. Used for deep-links, browser history navigation etc.
62
88
  AppMenuItemView.#routeViewDriverStream.onValue(async (routeView) => {
63
89
  const routeViewID = routeView.getRouteID();
64
90
  const routeType = routeView.getRouteType();
@@ -72,7 +98,10 @@ export class AppMenuItemView extends EventEmitter {
72
98
  return descriptor?.isRouteActive(routeView);
73
99
  }) ?? [];
74
100
  if (gmailView?.element) {
75
- AppMenuItemView.#menuItemChangeBus.emit(['click', gmailView.element]);
101
+ AppMenuItemView.#menuItemChangeBus.emit([
102
+ 'route-activated',
103
+ gmailView.element,
104
+ ]);
76
105
  return;
77
106
  }
78
107
  /* Handling native app menu items */
@@ -86,12 +115,15 @@ export class AppMenuItemView extends EventEmitter {
86
115
  const menuItemElement = menuItemClass &&
87
116
  document.querySelector(`.${menuItemClass}`);
88
117
  if (menuItemElement) {
89
- AppMenuItemView.#menuItemChangeBus.emit(['click', menuItemElement]);
118
+ AppMenuItemView.#menuItemChangeBus.emit([
119
+ 'route-activated',
120
+ menuItemElement,
121
+ ]);
90
122
  }
91
123
  });
92
124
  }
93
125
  static {
94
- (async () => {
126
+ (async function init() {
95
127
  const gmailAppMenu = await GmailElementGetter.getAppMenuAsync();
96
128
  if (!gmailAppMenu) {
97
129
  return;
@@ -155,6 +187,28 @@ export class AppMenuItemView extends EventEmitter {
155
187
  AppMenuItemView.#menuItemChangeStream.onValue(async (v) => {
156
188
  const [type, menuItem, mouseEvent] = v;
157
189
  const { ACTIVE, HOVER } = GmailAppMenuItemView.elementCss;
190
+ function handleActivate() {
191
+ const appMenuElement = GmailElementGetter.getAppMenuContainer();
192
+ // deactivate active panel
193
+ const activePanel = AppMenuItemView.#getActivePanel();
194
+ if (activePanel) {
195
+ activePanel.style.removeProperty('height');
196
+ activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
197
+ activePanel.classList.remove(CollapsiblePanelView.elementCss.HOVER);
198
+ }
199
+ // deactivate menu items
200
+ for (const menuItem_ of appMenuElement?.querySelectorAll(`.${NATIVE_CLASS}`) ?? []) {
201
+ menuItem_.classList.remove(ACTIVE);
202
+ menuItem_.classList.remove(HOVER);
203
+ }
204
+ // activate menu item
205
+ menuItem.classList.add(ACTIVE);
206
+ // activate panel
207
+ const panel = AppMenuItemView.#menuItemToPanelMap.get(menuItem);
208
+ if (panel) {
209
+ panel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
210
+ }
211
+ }
158
212
  switch (type) {
159
213
  case 'mouseenter': {
160
214
  const panel = AppMenuItemView.#menuItemToPanelMap.get(menuItem);
@@ -226,26 +280,19 @@ export class AppMenuItemView extends EventEmitter {
226
280
  break;
227
281
  }
228
282
  case 'click': {
229
- const appMenuElement = GmailElementGetter.getAppMenuContainer();
230
- // deactivate active panel
231
- const activePanel = AppMenuItemView.#getActivePanel();
232
- if (activePanel) {
233
- activePanel.style.removeProperty('height');
234
- activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
235
- activePanel.classList.remove(CollapsiblePanelView.elementCss.HOVER);
236
- }
237
- // deactivate menu items
238
- for (const menuItem_ of appMenuElement?.querySelectorAll(`.${NATIVE_CLASS}`) ?? []) {
239
- menuItem_.classList.remove(ACTIVE);
240
- menuItem_.classList.remove(HOVER);
241
- }
242
- // activate menu item
243
- menuItem.classList.add(ACTIVE);
244
- // activate panel
245
- const panel = AppMenuItemView.#menuItemToPanelMap.get(menuItem);
246
- if (panel) {
247
- panel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
283
+ handleActivate();
284
+ // handle panel-less mode
285
+ const isPanelLess = AppMenuItemView.#isPanelLess();
286
+ for (const panel of document.querySelectorAll(CollapsiblePanelView.elementSelectors.NATIVE) ?? []) {
287
+ panel.classList.toggle(CollapsiblePanelView.elementCss.PANEL_LESS, isPanelLess);
248
288
  }
289
+ GmailElementGetter.getAppMenu()?.classList.toggle('aTO', isPanelLess);
290
+ GmailElementGetter.getAppHeader()?.classList.toggle('aTO', isPanelLess);
291
+ break;
292
+ }
293
+ case 'route-activated': {
294
+ handleActivate();
295
+ break;
249
296
  }
250
297
  }
251
298
  });
@@ -271,9 +318,9 @@ export class AppMenuItemView extends EventEmitter {
271
318
  const gmailElement = gmailView.element;
272
319
  if (gmailElement) {
273
320
  AppMenuItemView.#menuItemToPanelMap.set(gmailElement, undefined);
321
+ AppMenuItemView.#adjustTooltipNub();
274
322
  }
275
323
  gmailView.on('destroy', () => {
276
- AppMenuItemView.#menuItemChangeBus.end();
277
324
  this.remove();
278
325
  });
279
326
  gmailView.on('click', () => {
@@ -302,7 +349,14 @@ export class AppMenuItemView extends EventEmitter {
302
349
  AppMenuItemView.#appMenuItemViews.add(this);
303
350
  }
304
351
  async addCollapsiblePanel(panelDescriptor) {
305
- const collapsiblePanel = await addCollapsiblePanel(this.#driver, panelDescriptor);
352
+ const descriptor = {
353
+ ...panelDescriptor,
354
+ className: cx(panelDescriptor.className, {
355
+ [CollapsiblePanelView.elementCss.COLLAPSED]: !GmailElementGetter.isAppBurgerMenuOpen(),
356
+ [CollapsiblePanelView.elementCss.PANEL_LESS]: AppMenuItemView.#isPanelLess(),
357
+ }),
358
+ };
359
+ const collapsiblePanel = await addCollapsiblePanel(this.#driver, descriptor, this.menuItemDescriptor.insertIndex);
306
360
  if (collapsiblePanel) {
307
361
  this.#gmailViewPromise.then((gmailView) => {
308
362
  const gmailElement = gmailView.element;
@@ -314,9 +368,8 @@ export class AppMenuItemView extends EventEmitter {
314
368
  e,
315
369
  ]);
316
370
  });
317
- }
318
- if (gmailElement && collapsiblePanel) {
319
371
  AppMenuItemView.#menuItemToPanelMap.set(gmailElement, collapsiblePanel.element);
372
+ AppMenuItemView.#adjustTooltipNub();
320
373
  }
321
374
  });
322
375
  }
@@ -325,7 +378,7 @@ export class AppMenuItemView extends EventEmitter {
325
378
  }
326
379
  async update(menuItemDescriptor) {
327
380
  const gmailView = await this.#gmailViewPromise;
328
- gmailView.setMenuItemDescriptor(menuItemDescriptor);
381
+ gmailView.menuItemDescriptor = menuItemDescriptor;
329
382
  this.#menuItemDescriptor = menuItemDescriptor;
330
383
  }
331
384
  remove() {
@@ -338,6 +391,7 @@ export class AppMenuItemView extends EventEmitter {
338
391
  gmailView.element &&
339
392
  AppMenuItemView.#menuItemToPanelMap.delete(gmailView.element);
340
393
  gmailView.remove();
394
+ AppMenuItemView.#adjustTooltipNub();
341
395
  });
342
396
  AppMenuItemView.#appMenuItemViews.delete(this);
343
397
  }