@spectrum-web-components/menu 1.2.0-beta.9 → 1.2.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.
@@ -28,15 +28,19 @@ export class MenuGroup extends Menu {
28
28
  static get styles() {
29
29
  return [...super.styles, menuGroupStyles];
30
30
  }
31
+ /**
32
+ * a menu group must have the role `group`
33
+ * and should never function as a menu
34
+ */
31
35
  get ownRole() {
32
- switch (this.selects) {
33
- case "multiple":
34
- case "single":
35
- case "inherit":
36
- return "group";
37
- default:
38
- return "menu";
39
- }
36
+ return "group";
37
+ }
38
+ /**
39
+ * only a menu controls roving tabindex;
40
+ * groups should defer navigation to parent menu
41
+ */
42
+ get controlsRovingTabindex() {
43
+ return false;
40
44
  }
41
45
  updateLabel() {
42
46
  const headerElement = this.headerElements.length ? this.headerElements[0] : void 0;
@@ -62,7 +66,7 @@ export class MenuGroup extends Menu {
62
66
  <span class="header" ?hidden=${!this.headerElement}>
63
67
  <slot name="header" @slotchange=${this.updateLabel}></slot>
64
68
  </span>
65
- <sp-menu ignore>${this.renderMenuItemSlot()}</sp-menu>
69
+ ${this.renderMenuItemSlot()}
66
70
  `;
67
71
  }
68
72
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["MenuGroup.ts"],
4
- "sourcesContent": ["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport {\n CSSResultArray,\n html,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n queryAssignedNodes,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { randomID } from '@spectrum-web-components/shared/src/random-id.js';\n\nimport { Menu } from './Menu.dev.js'\n// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225\nimport '@spectrum-web-components/menu/sp-menu.js';\nimport menuGroupStyles from './menu-group.css.js';\n\n/**\n * @element sp-menu-group\n *\n * @slot header - headline of the menu group\n * @slot - menu items to be listed in the group\n */\nexport class MenuGroup extends Menu {\n public static override get styles(): CSSResultArray {\n return [...super.styles, menuGroupStyles];\n }\n\n private headerId = '';\n\n @queryAssignedNodes({\n slot: 'header',\n flatten: true,\n })\n private headerElements!: NodeListOf<HTMLElement>;\n\n @state()\n private headerElement?: HTMLElement;\n\n protected override get ownRole(): string {\n switch (this.selects) {\n case 'multiple':\n case 'single':\n case 'inherit':\n return 'group';\n default:\n return 'menu';\n }\n }\n\n protected updateLabel(): void {\n const headerElement = this.headerElements.length\n ? this.headerElements[0]\n : undefined;\n if (headerElement !== this.headerElement) {\n if (this.headerElement && this.headerElement.id === this.headerId) {\n this.headerElement.removeAttribute('id');\n }\n if (headerElement) {\n this.headerId =\n this.headerId || `sp-menu-group-label-${randomID()}`;\n const headerId = headerElement.id || this.headerId;\n if (!headerElement.id) {\n headerElement.id = headerId;\n }\n this.setAttribute('aria-labelledby', headerId);\n } else {\n this.removeAttribute('aria-labelledby');\n }\n }\n this.headerElement = headerElement;\n }\n\n public override render(): TemplateResult {\n return html`\n <span class=\"header\" ?hidden=${!this.headerElement}>\n <slot name=\"header\" @slotchange=${this.updateLabel}></slot>\n </span>\n <sp-menu ignore>${this.renderMenuItemSlot()}</sp-menu>\n `;\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;AAYA;AAAA,EAEI;AAAA,OAEG;AACP;AAAA,EACI;AAAA,EACA;AAAA,OACG;AACP,SAAS,gBAAgB;AAEzB,SAAS,YAAY;AAErB,OAAO;AACP,OAAO,qBAAqB;AAQrB,aAAM,kBAAkB,KAAK;AAAA,EAA7B;AAAA;AAKH,SAAQ,WAAW;AAAA;AAAA,EAJnB,WAA2B,SAAyB;AAChD,WAAO,CAAC,GAAG,MAAM,QAAQ,eAAe;AAAA,EAC5C;AAAA,EAaA,IAAuB,UAAkB;AACrC,YAAQ,KAAK,SAAS;AAAA,MAClB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACD,eAAO;AAAA,MACX;AACI,eAAO;AAAA,IACf;AAAA,EACJ;AAAA,EAEU,cAAoB;AAC1B,UAAM,gBAAgB,KAAK,eAAe,SACpC,KAAK,eAAe,CAAC,IACrB;AACN,QAAI,kBAAkB,KAAK,eAAe;AACtC,UAAI,KAAK,iBAAiB,KAAK,cAAc,OAAO,KAAK,UAAU;AAC/D,aAAK,cAAc,gBAAgB,IAAI;AAAA,MAC3C;AACA,UAAI,eAAe;AACf,aAAK,WACD,KAAK,YAAY,uBAAuB,SAAS,CAAC;AACtD,cAAM,WAAW,cAAc,MAAM,KAAK;AAC1C,YAAI,CAAC,cAAc,IAAI;AACnB,wBAAc,KAAK;AAAA,QACvB;AACA,aAAK,aAAa,mBAAmB,QAAQ;AAAA,MACjD,OAAO;AACH,aAAK,gBAAgB,iBAAiB;AAAA,MAC1C;AAAA,IACJ;AACA,SAAK,gBAAgB;AAAA,EACzB;AAAA,EAEgB,SAAyB;AACrC,WAAO;AAAA,2CAC4B,CAAC,KAAK,aAAa;AAAA,kDACZ,KAAK,WAAW;AAAA;AAAA,8BAEpC,KAAK,mBAAmB,CAAC;AAAA;AAAA,EAEnD;AACJ;AA/CY;AAAA,EAJP,mBAAmB;AAAA,IAChB,MAAM;AAAA,IACN,SAAS;AAAA,EACb,CAAC;AAAA,GAVQ,UAWD;AAGA;AAAA,EADP,MAAM;AAAA,GAbE,UAcD;",
4
+ "sourcesContent": ["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport {\n CSSResultArray,\n html,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n queryAssignedNodes,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { randomID } from '@spectrum-web-components/shared/src/random-id.js';\n\nimport { Menu } from './Menu.dev.js'\n// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225\nimport '@spectrum-web-components/menu/sp-menu.js';\nimport menuGroupStyles from './menu-group.css.js';\n\n/**\n * @element sp-menu-group\n *\n * @slot header - headline of the menu group\n * @slot - menu items to be listed in the group\n */\nexport class MenuGroup extends Menu {\n public static override get styles(): CSSResultArray {\n return [...super.styles, menuGroupStyles];\n }\n\n private headerId = '';\n\n @queryAssignedNodes({\n slot: 'header',\n flatten: true,\n })\n private headerElements!: NodeListOf<HTMLElement>;\n\n @state()\n private headerElement?: HTMLElement;\n\n /**\n * a menu group must have the role `group`\n * and should never function as a menu\n */\n protected override get ownRole(): string {\n return 'group';\n }\n\n /**\n * only a menu controls roving tabindex;\n * groups should defer navigation to parent menu\n */\n protected override get controlsRovingTabindex(): boolean {\n return false;\n }\n\n protected updateLabel(): void {\n const headerElement = this.headerElements.length\n ? this.headerElements[0]\n : undefined;\n if (headerElement !== this.headerElement) {\n if (this.headerElement && this.headerElement.id === this.headerId) {\n this.headerElement.removeAttribute('id');\n }\n if (headerElement) {\n this.headerId =\n this.headerId || `sp-menu-group-label-${randomID()}`;\n const headerId = headerElement.id || this.headerId;\n if (!headerElement.id) {\n headerElement.id = headerId;\n }\n this.setAttribute('aria-labelledby', headerId);\n } else {\n this.removeAttribute('aria-labelledby');\n }\n }\n this.headerElement = headerElement;\n }\n\n public override render(): TemplateResult {\n return html`\n <span class=\"header\" ?hidden=${!this.headerElement}>\n <slot name=\"header\" @slotchange=${this.updateLabel}></slot>\n </span>\n ${this.renderMenuItemSlot()}\n `;\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;AAYA;AAAA,EAEI;AAAA,OAEG;AACP;AAAA,EACI;AAAA,EACA;AAAA,OACG;AACP,SAAS,gBAAgB;AAEzB,SAAS,YAAY;AAErB,OAAO;AACP,OAAO,qBAAqB;AAQrB,aAAM,kBAAkB,KAAK;AAAA,EAA7B;AAAA;AAKH,SAAQ,WAAW;AAAA;AAAA,EAJnB,WAA2B,SAAyB;AAChD,WAAO,CAAC,GAAG,MAAM,QAAQ,eAAe;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,IAAuB,UAAkB;AACrC,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAuB,yBAAkC;AACrD,WAAO;AAAA,EACX;AAAA,EAEU,cAAoB;AAC1B,UAAM,gBAAgB,KAAK,eAAe,SACpC,KAAK,eAAe,CAAC,IACrB;AACN,QAAI,kBAAkB,KAAK,eAAe;AACtC,UAAI,KAAK,iBAAiB,KAAK,cAAc,OAAO,KAAK,UAAU;AAC/D,aAAK,cAAc,gBAAgB,IAAI;AAAA,MAC3C;AACA,UAAI,eAAe;AACf,aAAK,WACD,KAAK,YAAY,uBAAuB,SAAS,CAAC;AACtD,cAAM,WAAW,cAAc,MAAM,KAAK;AAC1C,YAAI,CAAC,cAAc,IAAI;AACnB,wBAAc,KAAK;AAAA,QACvB;AACA,aAAK,aAAa,mBAAmB,QAAQ;AAAA,MACjD,OAAO;AACH,aAAK,gBAAgB,iBAAiB;AAAA,MAC1C;AAAA,IACJ;AACA,SAAK,gBAAgB;AAAA,EACzB;AAAA,EAEgB,SAAyB;AACrC,WAAO;AAAA,2CAC4B,CAAC,KAAK,aAAa;AAAA,kDACZ,KAAK,WAAW;AAAA;AAAA,cAEpD,KAAK,mBAAmB,CAAC;AAAA;AAAA,EAEnC;AACJ;AApDY;AAAA,EAJP,mBAAmB;AAAA,IAChB,MAAM;AAAA,IACN,SAAS;AAAA,EACb,CAAC;AAAA,GAVQ,UAWD;AAGA;AAAA,EADP,MAAM;AAAA,GAbE,UAcD;",
6
6
  "names": []
7
7
  }
package/src/MenuGroup.js CHANGED
@@ -1,7 +1,7 @@
1
- "use strict";var n=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var l=(i,s,e,t)=>{for(var r=t>1?void 0:t?h(s,e):s,d=i.length-1,a;d>=0;d--)(a=i[d])&&(r=(t?a(s,e,r):a(r))||r);return t&&r&&n(s,e,r),r};import{html as m}from"@spectrum-web-components/base";import{queryAssignedNodes as o,state as u}from"@spectrum-web-components/base/src/decorators.js";import{randomID as p}from"@spectrum-web-components/shared/src/random-id.js";import{Menu as c}from"./Menu.js";import"@spectrum-web-components/menu/sp-menu.js";import f from"./menu-group.css.js";export class MenuGroup extends c{constructor(){super(...arguments);this.headerId=""}static get styles(){return[...super.styles,f]}get ownRole(){switch(this.selects){case"multiple":case"single":case"inherit":return"group";default:return"menu"}}updateLabel(){const e=this.headerElements.length?this.headerElements[0]:void 0;if(e!==this.headerElement)if(this.headerElement&&this.headerElement.id===this.headerId&&this.headerElement.removeAttribute("id"),e){this.headerId=this.headerId||`sp-menu-group-label-${p()}`;const t=e.id||this.headerId;e.id||(e.id=t),this.setAttribute("aria-labelledby",t)}else this.removeAttribute("aria-labelledby");this.headerElement=e}render(){return m`
1
+ "use strict";var n=Object.defineProperty;var o=Object.getOwnPropertyDescriptor;var l=(i,d,e,t)=>{for(var r=t>1?void 0:t?o(d,e):d,s=i.length-1,a;s>=0;s--)(a=i[s])&&(r=(t?a(d,e,r):a(r))||r);return t&&r&&n(d,e,r),r};import{html as h}from"@spectrum-web-components/base";import{queryAssignedNodes as m,state as p}from"@spectrum-web-components/base/src/decorators.js";import{randomID as u}from"@spectrum-web-components/shared/src/random-id.js";import{Menu as b}from"./Menu.js";import"@spectrum-web-components/menu/sp-menu.js";import f from"./menu-group.css.js";export class MenuGroup extends b{constructor(){super(...arguments);this.headerId=""}static get styles(){return[...super.styles,f]}get ownRole(){return"group"}get controlsRovingTabindex(){return!1}updateLabel(){const e=this.headerElements.length?this.headerElements[0]:void 0;if(e!==this.headerElement)if(this.headerElement&&this.headerElement.id===this.headerId&&this.headerElement.removeAttribute("id"),e){this.headerId=this.headerId||`sp-menu-group-label-${u()}`;const t=e.id||this.headerId;e.id||(e.id=t),this.setAttribute("aria-labelledby",t)}else this.removeAttribute("aria-labelledby");this.headerElement=e}render(){return h`
2
2
  <span class="header" ?hidden=${!this.headerElement}>
3
3
  <slot name="header" @slotchange=${this.updateLabel}></slot>
4
4
  </span>
5
- <sp-menu ignore>${this.renderMenuItemSlot()}</sp-menu>
6
- `}}l([o({slot:"header",flatten:!0})],MenuGroup.prototype,"headerElements",2),l([u()],MenuGroup.prototype,"headerElement",2);
5
+ ${this.renderMenuItemSlot()}
6
+ `}}l([m({slot:"header",flatten:!0})],MenuGroup.prototype,"headerElements",2),l([p()],MenuGroup.prototype,"headerElement",2);
7
7
  //# sourceMappingURL=MenuGroup.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["MenuGroup.ts"],
4
- "sourcesContent": ["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport {\n CSSResultArray,\n html,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n queryAssignedNodes,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { randomID } from '@spectrum-web-components/shared/src/random-id.js';\n\nimport { Menu } from './Menu.js';\n// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225\nimport '@spectrum-web-components/menu/sp-menu.js';\nimport menuGroupStyles from './menu-group.css.js';\n\n/**\n * @element sp-menu-group\n *\n * @slot header - headline of the menu group\n * @slot - menu items to be listed in the group\n */\nexport class MenuGroup extends Menu {\n public static override get styles(): CSSResultArray {\n return [...super.styles, menuGroupStyles];\n }\n\n private headerId = '';\n\n @queryAssignedNodes({\n slot: 'header',\n flatten: true,\n })\n private headerElements!: NodeListOf<HTMLElement>;\n\n @state()\n private headerElement?: HTMLElement;\n\n protected override get ownRole(): string {\n switch (this.selects) {\n case 'multiple':\n case 'single':\n case 'inherit':\n return 'group';\n default:\n return 'menu';\n }\n }\n\n protected updateLabel(): void {\n const headerElement = this.headerElements.length\n ? this.headerElements[0]\n : undefined;\n if (headerElement !== this.headerElement) {\n if (this.headerElement && this.headerElement.id === this.headerId) {\n this.headerElement.removeAttribute('id');\n }\n if (headerElement) {\n this.headerId =\n this.headerId || `sp-menu-group-label-${randomID()}`;\n const headerId = headerElement.id || this.headerId;\n if (!headerElement.id) {\n headerElement.id = headerId;\n }\n this.setAttribute('aria-labelledby', headerId);\n } else {\n this.removeAttribute('aria-labelledby');\n }\n }\n this.headerElement = headerElement;\n }\n\n public override render(): TemplateResult {\n return html`\n <span class=\"header\" ?hidden=${!this.headerElement}>\n <slot name=\"header\" @slotchange=${this.updateLabel}></slot>\n </span>\n <sp-menu ignore>${this.renderMenuItemSlot()}</sp-menu>\n `;\n }\n}\n"],
5
- "mappings": "qNAYA,OAEI,QAAAA,MAEG,gCACP,OACI,sBAAAC,EACA,SAAAC,MACG,kDACP,OAAS,YAAAC,MAAgB,mDAEzB,OAAS,QAAAC,MAAY,YAErB,MAAO,2CACP,OAAOC,MAAqB,sBAQrB,aAAM,kBAAkBD,CAAK,CAA7B,kCAKH,KAAQ,SAAW,GAJnB,WAA2B,QAAyB,CAChD,MAAO,CAAC,GAAG,MAAM,OAAQC,CAAe,CAC5C,CAaA,IAAuB,SAAkB,CACrC,OAAQ,KAAK,QAAS,CAClB,IAAK,WACL,IAAK,SACL,IAAK,UACD,MAAO,QACX,QACI,MAAO,MACf,CACJ,CAEU,aAAoB,CAC1B,MAAMC,EAAgB,KAAK,eAAe,OACpC,KAAK,eAAe,CAAC,EACrB,OACN,GAAIA,IAAkB,KAAK,cAIvB,GAHI,KAAK,eAAiB,KAAK,cAAc,KAAO,KAAK,UACrD,KAAK,cAAc,gBAAgB,IAAI,EAEvCA,EAAe,CACf,KAAK,SACD,KAAK,UAAY,uBAAuBH,EAAS,CAAC,GACtD,MAAMI,EAAWD,EAAc,IAAM,KAAK,SACrCA,EAAc,KACfA,EAAc,GAAKC,GAEvB,KAAK,aAAa,kBAAmBA,CAAQ,CACjD,MACI,KAAK,gBAAgB,iBAAiB,EAG9C,KAAK,cAAgBD,CACzB,CAEgB,QAAyB,CACrC,OAAON;AAAA,2CAC4B,CAAC,KAAK,aAAa;AAAA,kDACZ,KAAK,WAAW;AAAA;AAAA,8BAEpC,KAAK,mBAAmB,CAAC;AAAA,SAEnD,CACJ,CA/CYQ,EAAA,CAJPP,EAAmB,CAChB,KAAM,SACN,QAAS,EACb,CAAC,GAVQ,UAWD,8BAGAO,EAAA,CADPN,EAAM,GAbE,UAcD",
4
+ "sourcesContent": ["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport {\n CSSResultArray,\n html,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n queryAssignedNodes,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { randomID } from '@spectrum-web-components/shared/src/random-id.js';\n\nimport { Menu } from './Menu.js';\n// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225\nimport '@spectrum-web-components/menu/sp-menu.js';\nimport menuGroupStyles from './menu-group.css.js';\n\n/**\n * @element sp-menu-group\n *\n * @slot header - headline of the menu group\n * @slot - menu items to be listed in the group\n */\nexport class MenuGroup extends Menu {\n public static override get styles(): CSSResultArray {\n return [...super.styles, menuGroupStyles];\n }\n\n private headerId = '';\n\n @queryAssignedNodes({\n slot: 'header',\n flatten: true,\n })\n private headerElements!: NodeListOf<HTMLElement>;\n\n @state()\n private headerElement?: HTMLElement;\n\n /**\n * a menu group must have the role `group`\n * and should never function as a menu\n */\n protected override get ownRole(): string {\n return 'group';\n }\n\n /**\n * only a menu controls roving tabindex;\n * groups should defer navigation to parent menu\n */\n protected override get controlsRovingTabindex(): boolean {\n return false;\n }\n\n protected updateLabel(): void {\n const headerElement = this.headerElements.length\n ? this.headerElements[0]\n : undefined;\n if (headerElement !== this.headerElement) {\n if (this.headerElement && this.headerElement.id === this.headerId) {\n this.headerElement.removeAttribute('id');\n }\n if (headerElement) {\n this.headerId =\n this.headerId || `sp-menu-group-label-${randomID()}`;\n const headerId = headerElement.id || this.headerId;\n if (!headerElement.id) {\n headerElement.id = headerId;\n }\n this.setAttribute('aria-labelledby', headerId);\n } else {\n this.removeAttribute('aria-labelledby');\n }\n }\n this.headerElement = headerElement;\n }\n\n public override render(): TemplateResult {\n return html`\n <span class=\"header\" ?hidden=${!this.headerElement}>\n <slot name=\"header\" @slotchange=${this.updateLabel}></slot>\n </span>\n ${this.renderMenuItemSlot()}\n `;\n }\n}\n"],
5
+ "mappings": "qNAYA,OAEI,QAAAA,MAEG,gCACP,OACI,sBAAAC,EACA,SAAAC,MACG,kDACP,OAAS,YAAAC,MAAgB,mDAEzB,OAAS,QAAAC,MAAY,YAErB,MAAO,2CACP,OAAOC,MAAqB,sBAQrB,aAAM,kBAAkBD,CAAK,CAA7B,kCAKH,KAAQ,SAAW,GAJnB,WAA2B,QAAyB,CAChD,MAAO,CAAC,GAAG,MAAM,OAAQC,CAAe,CAC5C,CAiBA,IAAuB,SAAkB,CACrC,MAAO,OACX,CAMA,IAAuB,wBAAkC,CACrD,MAAO,EACX,CAEU,aAAoB,CAC1B,MAAMC,EAAgB,KAAK,eAAe,OACpC,KAAK,eAAe,CAAC,EACrB,OACN,GAAIA,IAAkB,KAAK,cAIvB,GAHI,KAAK,eAAiB,KAAK,cAAc,KAAO,KAAK,UACrD,KAAK,cAAc,gBAAgB,IAAI,EAEvCA,EAAe,CACf,KAAK,SACD,KAAK,UAAY,uBAAuBH,EAAS,CAAC,GACtD,MAAMI,EAAWD,EAAc,IAAM,KAAK,SACrCA,EAAc,KACfA,EAAc,GAAKC,GAEvB,KAAK,aAAa,kBAAmBA,CAAQ,CACjD,MACI,KAAK,gBAAgB,iBAAiB,EAG9C,KAAK,cAAgBD,CACzB,CAEgB,QAAyB,CACrC,OAAON;AAAA,2CAC4B,CAAC,KAAK,aAAa;AAAA,kDACZ,KAAK,WAAW;AAAA;AAAA,cAEpD,KAAK,mBAAmB,CAAC;AAAA,SAEnC,CACJ,CApDYQ,EAAA,CAJPP,EAAmB,CAChB,KAAM,SACN,QAAS,EACb,CAAC,GAVQ,UAWD,8BAGAO,EAAA,CADPN,EAAM,GAbE,UAcD",
6
6
  "names": ["html", "queryAssignedNodes", "state", "randomID", "Menu", "menuGroupStyles", "headerElement", "headerId", "__decorateClass"]
7
7
  }
package/src/MenuItem.d.ts CHANGED
@@ -8,6 +8,9 @@ type MenuCascadeItem = {
8
8
  hadFocusRoot: boolean;
9
9
  ancestorWithSelects?: HTMLElement;
10
10
  };
11
+ /**
12
+ * Fires when a menu item is added or updated so that a parent menu can track it.
13
+ */
11
14
  export declare class MenuItemAddedOrUpdatedEvent extends Event {
12
15
  constructor(item: MenuItem);
13
16
  clear(item: MenuItem): void;
@@ -16,6 +19,26 @@ export declare class MenuItemAddedOrUpdatedEvent extends Event {
16
19
  private _item;
17
20
  currentAncestorWithSelects?: Menu;
18
21
  }
22
+ /**
23
+ * Fires to forward keyboard event information to parent menu.
24
+ */
25
+ export declare class MenuItemKeydownEvent extends KeyboardEvent {
26
+ root?: MenuItem;
27
+ private _event?;
28
+ constructor({ root, event }: {
29
+ root?: MenuItem;
30
+ event?: KeyboardEvent;
31
+ });
32
+ get altKey(): boolean;
33
+ get code(): string;
34
+ get ctrlKey(): boolean;
35
+ get isComposing(): boolean;
36
+ get key(): string;
37
+ get location(): number;
38
+ get metaKey(): boolean;
39
+ get repeat(): boolean;
40
+ get shiftKey(): boolean;
41
+ }
19
42
  export type MenuItemChildren = {
20
43
  icon: Element[];
21
44
  content: Node[];
@@ -43,31 +66,55 @@ declare const MenuItem_base: typeof Focusable & {
43
66
  export declare class MenuItem extends MenuItem_base {
44
67
  static get styles(): CSSResultArray;
45
68
  abortControllerSubmenu: AbortController;
69
+ /**
70
+ * whether the menu item is active or has an active descendant
71
+ */
46
72
  active: boolean;
47
73
  private dependencyManager;
74
+ /**
75
+ * whether the menu item has keyboard focus
76
+ */
48
77
  focused: boolean;
78
+ /**
79
+ * whether the menu item is selected
80
+ */
49
81
  selected: boolean;
82
+ /**
83
+ * value of the menu item which is used for selection
84
+ */
50
85
  get value(): string;
51
86
  set value(value: string);
52
87
  private _value;
53
88
  /**
54
89
  * @private
90
+ * text content of the menu item minus whitespace
55
91
  */
56
92
  get itemText(): string;
93
+ /**
94
+ * whether the menu item has a submenu
95
+ */
57
96
  hasSubmenu: boolean;
58
97
  contentSlot: HTMLSlotElement;
59
98
  iconSlot: HTMLSlotElement;
99
+ /**
100
+ * whether menu item text content should not wrap
101
+ */
60
102
  noWrap: boolean;
61
103
  private anchorElement;
62
104
  overlayElement: Overlay;
63
105
  private submenuElement?;
106
+ /**
107
+ * the focusable element of the menu item
108
+ */
64
109
  get focusElement(): HTMLElement;
65
110
  protected get hasIcon(): boolean;
66
111
  get itemChildren(): MenuItemChildren;
67
112
  private _itemChildren?;
68
113
  constructor();
114
+ /**
115
+ * whether submenu is open
116
+ */
69
117
  open: boolean;
70
- click(): void;
71
118
  private handleClickCapture;
72
119
  private handleSlottableRequest;
73
120
  private proxyFocus;
@@ -75,12 +122,21 @@ export declare class MenuItem extends MenuItem_base {
75
122
  protected breakItemChildrenCache(): void;
76
123
  protected renderSubmenu(): TemplateResult;
77
124
  protected render(): TemplateResult;
125
+ /**
126
+ * determines if item has a submenu and updates the `aria-haspopup` attribute
127
+ */
78
128
  protected manageSubmenu(event: Event & {
79
129
  target: HTMLSlotElement;
80
130
  }): void;
81
131
  private handlePointerdown;
82
132
  protected firstUpdated(changes: PropertyValues): void;
133
+ /**
134
+ * forward key info from keydown event to parent menu
135
+ */
136
+ handleKeydown: (event: KeyboardEvent) => void;
83
137
  protected closeOverlaysForRoot(): void;
138
+ protected handleFocus(event: FocusEvent): void;
139
+ protected handleBlur(event: FocusEvent): void;
84
140
  protected handleSubmenuClick(event: Event): void;
85
141
  protected handleSubmenuFocus(): void;
86
142
  protected handleBeforetoggle: (event: Event) => void;
@@ -103,12 +159,15 @@ export declare class MenuItem extends MenuItem_base {
103
159
  openOverlay(): Promise<void>;
104
160
  updateAriaSelected(): void;
105
161
  setRole(role: string): void;
162
+ protected willUpdate(changes: PropertyValues<this>): void;
106
163
  protected updated(changes: PropertyValues<this>): void;
107
164
  connectedCallback(): void;
108
165
  _parentElement: HTMLElement;
109
166
  disconnectedCallback(): void;
110
167
  private willDispatchUpdate;
111
168
  triggerUpdate(): Promise<void>;
169
+ focus(): void;
170
+ blur(): void;
112
171
  dispatchUpdate(): void;
113
172
  menuData: {
114
173
  focusRoot?: Menu;
@@ -27,11 +27,9 @@ import { LikeAnchor } from "@spectrum-web-components/shared/src/like-anchor.js";
27
27
  import { Focusable } from "@spectrum-web-components/shared/src/focusable.js";
28
28
  import "@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js";
29
29
  import chevronStyles from "@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js";
30
- import chevronIconOverrides from "@spectrum-web-components/icon/src/icon-chevron-overrides.css.js";
31
30
  import { DependencyManagerController } from "@spectrum-web-components/reactive-controllers/src/DependencyManger.js";
32
31
  import menuItemStyles from "./menu-item.css.js";
33
32
  import checkmarkStyles from "@spectrum-web-components/icon/src/spectrum-icon-checkmark.css.js";
34
- import checkmarkSmallOverrides from "@spectrum-web-components/icon/src/icon-checkmark-overrides.css.js";
35
33
  import { MutationController } from "@lit-labs/observers/mutation-controller.js";
36
34
  import { SlottableRequestEvent } from "@spectrum-web-components/overlay/src/slottable-request-event.js";
37
35
  const POINTERLEAVE_TIMEOUT = 100;
@@ -59,6 +57,49 @@ export class MenuItemAddedOrUpdatedEvent extends Event {
59
57
  return this._item;
60
58
  }
61
59
  }
60
+ export class MenuItemKeydownEvent extends KeyboardEvent {
61
+ constructor({ root, event }) {
62
+ super("sp-menu-item-keydown", { bubbles: true, composed: true });
63
+ this.root = root;
64
+ this._event = event;
65
+ }
66
+ get altKey() {
67
+ var _a;
68
+ return ((_a = this._event) == null ? void 0 : _a.altKey) || false;
69
+ }
70
+ get code() {
71
+ var _a;
72
+ return ((_a = this._event) == null ? void 0 : _a.code) || "";
73
+ }
74
+ get ctrlKey() {
75
+ var _a;
76
+ return ((_a = this._event) == null ? void 0 : _a.ctrlKey) || false;
77
+ }
78
+ get isComposing() {
79
+ var _a;
80
+ return ((_a = this._event) == null ? void 0 : _a.isComposing) || false;
81
+ }
82
+ get key() {
83
+ var _a;
84
+ return ((_a = this._event) == null ? void 0 : _a.key) || "";
85
+ }
86
+ get location() {
87
+ var _a;
88
+ return ((_a = this._event) == null ? void 0 : _a.location) || 0;
89
+ }
90
+ get metaKey() {
91
+ var _a;
92
+ return ((_a = this._event) == null ? void 0 : _a.metaKey) || false;
93
+ }
94
+ get repeat() {
95
+ var _a;
96
+ return ((_a = this._event) == null ? void 0 : _a.repeat) || false;
97
+ }
98
+ get shiftKey() {
99
+ var _a;
100
+ return ((_a = this._event) == null ? void 0 : _a.shiftKey) || false;
101
+ }
102
+ }
62
103
  export class MenuItem extends LikeAnchor(
63
104
  ObserveSlotText(ObserveSlotPresence(Focusable, '[slot="icon"]'))
64
105
  ) {
@@ -81,6 +122,20 @@ export class MenuItem extends LikeAnchor(
81
122
  this.proxyFocus = () => {
82
123
  this.focus();
83
124
  };
125
+ /**
126
+ * forward key info from keydown event to parent menu
127
+ */
128
+ this.handleKeydown = (event) => {
129
+ const { target, key } = event;
130
+ const openSubmenuKey = this.hasSubmenu && !this.open && [" ", "Enter"].includes(key);
131
+ if (target === this) {
132
+ if (["ArrowLeft", "ArrowRight", "Escape"].includes(key) || openSubmenuKey)
133
+ event.preventDefault();
134
+ this.dispatchEvent(
135
+ new MenuItemKeydownEvent({ root: this, event })
136
+ );
137
+ }
138
+ };
84
139
  this.handleBeforetoggle = (event) => {
85
140
  if (event.newState === "closed") {
86
141
  this.open = true;
@@ -94,14 +149,18 @@ export class MenuItem extends LikeAnchor(
94
149
  this.recentlyLeftChild = false;
95
150
  this.willDispatchUpdate = false;
96
151
  this.menuData = {
152
+ // menu that controls ArrowUp/ArrowDown navigation
97
153
  focusRoot: void 0,
98
154
  parentMenu: void 0,
155
+ // menu or menu group that controls selection
99
156
  selectionRoot: void 0,
100
157
  cleanupSteps: []
101
158
  };
102
159
  this.addEventListener("click", this.handleClickCapture, {
103
160
  capture: true
104
161
  });
162
+ this.addEventListener("focus", this.handleFocus);
163
+ this.addEventListener("blur", this.handleBlur);
105
164
  new MutationController(this, {
106
165
  config: {
107
166
  characterData: true,
@@ -121,13 +180,7 @@ export class MenuItem extends LikeAnchor(
121
180
  });
122
181
  }
123
182
  static get styles() {
124
- return [
125
- menuItemStyles,
126
- checkmarkStyles,
127
- checkmarkSmallOverrides,
128
- chevronStyles,
129
- chevronIconOverrides
130
- ];
183
+ return [menuItemStyles, checkmarkStyles, chevronStyles];
131
184
  }
132
185
  get value() {
133
186
  return this._value || this.itemText;
@@ -145,6 +198,7 @@ export class MenuItem extends LikeAnchor(
145
198
  }
146
199
  /**
147
200
  * @private
201
+ * text content of the menu item minus whitespace
148
202
  */
149
203
  get itemText() {
150
204
  return this.itemChildren.content.reduce(
@@ -152,6 +206,9 @@ export class MenuItem extends LikeAnchor(
152
206
  ""
153
207
  );
154
208
  }
209
+ /**
210
+ * the focusable element of the menu item
211
+ */
155
212
  get focusElement() {
156
213
  return this;
157
214
  }
@@ -178,15 +235,6 @@ export class MenuItem extends LikeAnchor(
178
235
  this._itemChildren = { icon, content };
179
236
  return this._itemChildren;
180
237
  }
181
- click() {
182
- if (this.disabled) {
183
- return;
184
- }
185
- if (this.shouldProxyClick()) {
186
- return;
187
- }
188
- super.click();
189
- }
190
238
  handleClickCapture(event) {
191
239
  if (this.disabled) {
192
240
  event.preventDefault();
@@ -194,6 +242,9 @@ export class MenuItem extends LikeAnchor(
194
242
  event.stopPropagation();
195
243
  return false;
196
244
  }
245
+ if (this.shouldProxyClick()) {
246
+ return;
247
+ }
197
248
  }
198
249
  shouldProxyClick() {
199
250
  let handled = false;
@@ -281,6 +332,9 @@ export class MenuItem extends LikeAnchor(
281
332
  ${this.renderSubmenu()}
282
333
  `;
283
334
  }
335
+ /**
336
+ * determines if item has a submenu and updates the `aria-haspopup` attribute
337
+ */
284
338
  manageSubmenu(event) {
285
339
  this.submenuElement = event.target.assignedElements({
286
340
  flatten: true
@@ -304,6 +358,7 @@ export class MenuItem extends LikeAnchor(
304
358
  firstUpdated(changes) {
305
359
  super.firstUpdated(changes);
306
360
  this.setAttribute("tabindex", "-1");
361
+ this.addEventListener("keydown", this.handleKeydown);
307
362
  this.addEventListener("pointerdown", this.handlePointerdown);
308
363
  this.addEventListener("pointerenter", this.closeOverlaysForRoot);
309
364
  if (!this.hasAttribute("id")) {
@@ -315,6 +370,18 @@ export class MenuItem extends LikeAnchor(
315
370
  if (this.open) return;
316
371
  (_a = this.menuData.parentMenu) == null ? void 0 : _a.closeDescendentOverlays();
317
372
  }
373
+ handleFocus(event) {
374
+ const { target } = event;
375
+ if (target === this) {
376
+ this.focused = true;
377
+ }
378
+ }
379
+ handleBlur(event) {
380
+ const { target } = event;
381
+ if (target === this) {
382
+ this.focused = false;
383
+ }
384
+ }
318
385
  handleSubmenuClick(event) {
319
386
  if (event.composedPath().includes(this.overlayElement)) {
320
387
  return;
@@ -324,6 +391,7 @@ export class MenuItem extends LikeAnchor(
324
391
  handleSubmenuFocus() {
325
392
  requestAnimationFrame(() => {
326
393
  this.overlayElement.open = this.open;
394
+ this.focused = false;
327
395
  });
328
396
  }
329
397
  handlePointerenter() {
@@ -363,13 +431,18 @@ export class MenuItem extends LikeAnchor(
363
431
  });
364
432
  }
365
433
  handleSubmenuOpen(event) {
434
+ var _a;
435
+ const shouldFocus = this.matches(":focus, :focus-within") || this.focused;
366
436
  this.focused = false;
367
437
  const parentOverlay = event.composedPath().find((el) => {
368
438
  return el !== this.overlayElement && el.localName === "sp-overlay";
369
439
  });
440
+ if (shouldFocus)
441
+ (_a = this.submenuElement) == null ? void 0 : _a.focus();
370
442
  this.overlayElement.parentOverlayToForceClose = parentOverlay;
371
443
  }
372
444
  cleanup() {
445
+ this.setAttribute("aria-expanded", "false");
373
446
  this.open = false;
374
447
  this.active = false;
375
448
  }
@@ -399,6 +472,12 @@ export class MenuItem extends LikeAnchor(
399
472
  this.setAttribute("role", role);
400
473
  this.updateAriaSelected();
401
474
  }
475
+ willUpdate(changes) {
476
+ super.updated(changes);
477
+ if (changes.has("open") && !this.open && this.hasSubmenu && this.hasVisibleFocusInTree()) {
478
+ this.focus();
479
+ }
480
+ }
402
481
  updated(changes) {
403
482
  var _a, _b;
404
483
  super.updated(changes);
@@ -468,6 +547,14 @@ export class MenuItem extends LikeAnchor(
468
547
  await new Promise((ready) => requestAnimationFrame(ready));
469
548
  this.dispatchUpdate();
470
549
  }
550
+ focus() {
551
+ super.focus();
552
+ this.dispatchEvent(new FocusEvent("focus"));
553
+ }
554
+ blur() {
555
+ this.dispatchEvent(new FocusEvent("blur"));
556
+ super.blur();
557
+ }
471
558
  dispatchUpdate() {
472
559
  if (!this.isConnected) {
473
560
  return;