@spectrum-web-components/menu 1.2.0-beta.8 → 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,19 +149,24 @@ 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,
108
167
  childList: true,
109
- subtree: true
168
+ subtree: true,
169
+ attributeFilter: ["src"]
110
170
  },
111
171
  callback: (mutations) => {
112
172
  const isSubmenu = mutations.every(
@@ -120,13 +180,7 @@ export class MenuItem extends LikeAnchor(
120
180
  });
121
181
  }
122
182
  static get styles() {
123
- return [
124
- menuItemStyles,
125
- checkmarkStyles,
126
- checkmarkSmallOverrides,
127
- chevronStyles,
128
- chevronIconOverrides
129
- ];
183
+ return [menuItemStyles, checkmarkStyles, chevronStyles];
130
184
  }
131
185
  get value() {
132
186
  return this._value || this.itemText;
@@ -144,6 +198,7 @@ export class MenuItem extends LikeAnchor(
144
198
  }
145
199
  /**
146
200
  * @private
201
+ * text content of the menu item minus whitespace
147
202
  */
148
203
  get itemText() {
149
204
  return this.itemChildren.content.reduce(
@@ -151,6 +206,9 @@ export class MenuItem extends LikeAnchor(
151
206
  ""
152
207
  );
153
208
  }
209
+ /**
210
+ * the focusable element of the menu item
211
+ */
154
212
  get focusElement() {
155
213
  return this;
156
214
  }
@@ -177,15 +235,6 @@ export class MenuItem extends LikeAnchor(
177
235
  this._itemChildren = { icon, content };
178
236
  return this._itemChildren;
179
237
  }
180
- click() {
181
- if (this.disabled) {
182
- return;
183
- }
184
- if (this.shouldProxyClick()) {
185
- return;
186
- }
187
- super.click();
188
- }
189
238
  handleClickCapture(event) {
190
239
  if (this.disabled) {
191
240
  event.preventDefault();
@@ -193,6 +242,9 @@ export class MenuItem extends LikeAnchor(
193
242
  event.stopPropagation();
194
243
  return false;
195
244
  }
245
+ if (this.shouldProxyClick()) {
246
+ return;
247
+ }
196
248
  }
197
249
  shouldProxyClick() {
198
250
  let handled = false;
@@ -280,6 +332,9 @@ export class MenuItem extends LikeAnchor(
280
332
  ${this.renderSubmenu()}
281
333
  `;
282
334
  }
335
+ /**
336
+ * determines if item has a submenu and updates the `aria-haspopup` attribute
337
+ */
283
338
  manageSubmenu(event) {
284
339
  this.submenuElement = event.target.assignedElements({
285
340
  flatten: true
@@ -303,6 +358,7 @@ export class MenuItem extends LikeAnchor(
303
358
  firstUpdated(changes) {
304
359
  super.firstUpdated(changes);
305
360
  this.setAttribute("tabindex", "-1");
361
+ this.addEventListener("keydown", this.handleKeydown);
306
362
  this.addEventListener("pointerdown", this.handlePointerdown);
307
363
  this.addEventListener("pointerenter", this.closeOverlaysForRoot);
308
364
  if (!this.hasAttribute("id")) {
@@ -314,6 +370,18 @@ export class MenuItem extends LikeAnchor(
314
370
  if (this.open) return;
315
371
  (_a = this.menuData.parentMenu) == null ? void 0 : _a.closeDescendentOverlays();
316
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
+ }
317
385
  handleSubmenuClick(event) {
318
386
  if (event.composedPath().includes(this.overlayElement)) {
319
387
  return;
@@ -323,6 +391,7 @@ export class MenuItem extends LikeAnchor(
323
391
  handleSubmenuFocus() {
324
392
  requestAnimationFrame(() => {
325
393
  this.overlayElement.open = this.open;
394
+ this.focused = false;
326
395
  });
327
396
  }
328
397
  handlePointerenter() {
@@ -362,13 +431,18 @@ export class MenuItem extends LikeAnchor(
362
431
  });
363
432
  }
364
433
  handleSubmenuOpen(event) {
434
+ var _a;
435
+ const shouldFocus = this.matches(":focus, :focus-within") || this.focused;
365
436
  this.focused = false;
366
437
  const parentOverlay = event.composedPath().find((el) => {
367
438
  return el !== this.overlayElement && el.localName === "sp-overlay";
368
439
  });
440
+ if (shouldFocus)
441
+ (_a = this.submenuElement) == null ? void 0 : _a.focus();
369
442
  this.overlayElement.parentOverlayToForceClose = parentOverlay;
370
443
  }
371
444
  cleanup() {
445
+ this.setAttribute("aria-expanded", "false");
372
446
  this.open = false;
373
447
  this.active = false;
374
448
  }
@@ -398,6 +472,12 @@ export class MenuItem extends LikeAnchor(
398
472
  this.setAttribute("role", role);
399
473
  this.updateAriaSelected();
400
474
  }
475
+ willUpdate(changes) {
476
+ super.updated(changes);
477
+ if (changes.has("open") && !this.open && this.hasSubmenu && this.hasVisibleFocusInTree()) {
478
+ this.focus();
479
+ }
480
+ }
401
481
  updated(changes) {
402
482
  var _a, _b;
403
483
  super.updated(changes);
@@ -467,6 +547,14 @@ export class MenuItem extends LikeAnchor(
467
547
  await new Promise((ready) => requestAnimationFrame(ready));
468
548
  this.dispatchUpdate();
469
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
+ }
470
558
  dispatchUpdate() {
471
559
  if (!this.isConnected) {
472
560
  return;