@material/web 1.0.2-nightly.f7a66a8.0 → 1.1.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.
Files changed (118) hide show
  1. package/checkbox/internal/checkbox.d.ts +1 -0
  2. package/checkbox/internal/checkbox.js +6 -1
  3. package/checkbox/internal/checkbox.js.map +1 -1
  4. package/chips/internal/_shared.scss +16 -3
  5. package/chips/internal/_trailing-icon.scss +2 -1
  6. package/chips/internal/assist-styles.css.js +1 -1
  7. package/chips/internal/assist-styles.css.js.map +1 -1
  8. package/chips/internal/chip-set.js +2 -6
  9. package/chips/internal/chip-set.js.map +1 -1
  10. package/chips/internal/chip.d.ts +8 -0
  11. package/chips/internal/chip.js +17 -2
  12. package/chips/internal/chip.js.map +1 -1
  13. package/chips/internal/filter-chip.d.ts +8 -0
  14. package/chips/internal/filter-chip.js +17 -4
  15. package/chips/internal/filter-chip.js.map +1 -1
  16. package/chips/internal/filter-styles.css.js +1 -1
  17. package/chips/internal/filter-styles.css.js.map +1 -1
  18. package/chips/internal/input-styles.css.js +1 -1
  19. package/chips/internal/input-styles.css.js.map +1 -1
  20. package/chips/internal/shared-styles.css.js +1 -1
  21. package/chips/internal/shared-styles.css.js.map +1 -1
  22. package/chips/internal/suggestion-styles.css.js +1 -1
  23. package/chips/internal/suggestion-styles.css.js.map +1 -1
  24. package/chips/internal/trailing-icon-styles.css.js +1 -1
  25. package/chips/internal/trailing-icon-styles.css.js.map +1 -1
  26. package/chips/internal/trailing-icons.js +8 -4
  27. package/chips/internal/trailing-icons.js.map +1 -1
  28. package/fab/internal/_shared.scss +1 -0
  29. package/fab/internal/shared-styles.css.js +1 -1
  30. package/fab/internal/shared-styles.css.js.map +1 -1
  31. package/field/internal/_content.scss +3 -1
  32. package/field/internal/shared-styles.css.js +1 -1
  33. package/field/internal/shared-styles.css.js.map +1 -1
  34. package/internal/aria/aria.d.ts +0 -29
  35. package/internal/aria/aria.js +0 -141
  36. package/internal/aria/aria.js.map +1 -1
  37. package/internal/controller/form-submitter.js +2 -2
  38. package/internal/controller/form-submitter.js.map +1 -1
  39. package/labs/behaviors/constraint-validation.d.ts +2 -2
  40. package/labs/behaviors/constraint-validation.js +18 -1
  41. package/labs/behaviors/constraint-validation.js.map +1 -1
  42. package/labs/behaviors/element-internals.js +1 -5
  43. package/labs/behaviors/element-internals.js.map +1 -1
  44. package/labs/behaviors/focusable.js +20 -7
  45. package/labs/behaviors/focusable.js.map +1 -1
  46. package/labs/behaviors/on-report-validity.d.ts +70 -0
  47. package/labs/behaviors/on-report-validity.js +185 -0
  48. package/labs/behaviors/on-report-validity.js.map +1 -0
  49. package/labs/behaviors/validators/checkbox-validator.d.ts +6 -3
  50. package/labs/behaviors/validators/checkbox-validator.js.map +1 -1
  51. package/labs/behaviors/validators/radio-validator.d.ts +38 -0
  52. package/labs/behaviors/validators/radio-validator.js +65 -0
  53. package/labs/behaviors/validators/radio-validator.js.map +1 -0
  54. package/labs/behaviors/validators/select-validator.d.ts +35 -0
  55. package/labs/behaviors/validators/select-validator.js +33 -0
  56. package/labs/behaviors/validators/select-validator.js.map +1 -0
  57. package/labs/behaviors/validators/text-field-validator.d.ts +110 -0
  58. package/labs/behaviors/validators/text-field-validator.js +146 -0
  59. package/labs/behaviors/validators/text-field-validator.js.map +1 -0
  60. package/labs/behaviors/validators/validator.d.ts +4 -0
  61. package/labs/behaviors/validators/validator.js.map +1 -1
  62. package/labs/card/internal/_outlined-card.scss +1 -1
  63. package/labs/card/internal/_shared.scss +10 -2
  64. package/labs/card/internal/outlined-styles.css.js +1 -1
  65. package/labs/card/internal/outlined-styles.css.js.map +1 -1
  66. package/labs/card/internal/shared-styles.css.js +1 -1
  67. package/labs/card/internal/shared-styles.css.js.map +1 -1
  68. package/labs/segmentedbutton/internal/_shared.scss +1 -0
  69. package/labs/segmentedbutton/internal/shared-styles.css.js +1 -1
  70. package/labs/segmentedbutton/internal/shared-styles.css.js.map +1 -1
  71. package/list/internal/list.js +2 -6
  72. package/list/internal/list.js.map +1 -1
  73. package/list/internal/listitem/_list-item.scss +2 -0
  74. package/list/internal/listitem/list-item-styles.css.js +1 -1
  75. package/list/internal/listitem/list-item-styles.css.js.map +1 -1
  76. package/menu/internal/controllers/menuItemController.d.ts +13 -1
  77. package/menu/internal/controllers/menuItemController.js +32 -6
  78. package/menu/internal/controllers/menuItemController.js.map +1 -1
  79. package/menu/internal/menu.js +7 -8
  80. package/menu/internal/menu.js.map +1 -1
  81. package/menu/internal/menuitem/menu-item.d.ts +2 -0
  82. package/menu/internal/menuitem/menu-item.js +13 -1
  83. package/menu/internal/menuitem/menu-item.js.map +1 -1
  84. package/package.json +1 -1
  85. package/radio/internal/radio.d.ts +11 -1
  86. package/radio/internal/radio.js +28 -2
  87. package/radio/internal/radio.js.map +1 -1
  88. package/radio/internal/single-selection-controller.d.ts +5 -5
  89. package/radio/internal/single-selection-controller.js +16 -14
  90. package/radio/internal/single-selection-controller.js.map +1 -1
  91. package/select/internal/_shared.scss +5 -0
  92. package/select/internal/select.d.ts +21 -72
  93. package/select/internal/select.js +106 -184
  94. package/select/internal/select.js.map +1 -1
  95. package/select/internal/selectoption/select-option.d.ts +2 -0
  96. package/select/internal/selectoption/select-option.js +13 -1
  97. package/select/internal/selectoption/select-option.js.map +1 -1
  98. package/select/internal/selectoption/selectOptionController.d.ts +7 -3
  99. package/select/internal/selectoption/selectOptionController.js +8 -11
  100. package/select/internal/selectoption/selectOptionController.js.map +1 -1
  101. package/select/internal/shared-styles.css.js +1 -1
  102. package/select/internal/shared-styles.css.js.map +1 -1
  103. package/switch/internal/_icon.scss +14 -10
  104. package/switch/internal/switch-styles.css.js +1 -1
  105. package/switch/internal/switch-styles.css.js.map +1 -1
  106. package/switch/internal/switch.js +12 -8
  107. package/switch/internal/switch.js.map +1 -1
  108. package/tabs/internal/tab.js +2 -6
  109. package/tabs/internal/tab.js.map +1 -1
  110. package/tabs/internal/tabs.js +2 -6
  111. package/tabs/internal/tabs.js.map +1 -1
  112. package/textfield/internal/text-field.d.ts +9 -74
  113. package/textfield/internal/text-field.js +34 -150
  114. package/textfield/internal/text-field.js.map +1 -1
  115. package/tokens/_md-comp-assist-chip.scss +11 -0
  116. package/tokens/_md-comp-filter-chip.scss +14 -0
  117. package/tokens/_md-comp-input-chip.scss +14 -0
  118. package/tokens/_md-comp-suggestion-chip.scss +11 -0
@@ -1 +1 @@
1
- {"version":3,"file":"single-selection-controller.js","sourceRoot":"","sources":["single-selection-controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAO,yBAAyB;IAIpC,YAA6B,IAA4B;QAA5B,SAAI,GAAJ,IAAI,CAAwB;QAHjD,YAAO,GAAG,KAAK,CAAC;QAChB,SAAI,GAAsB,IAAI,CAAC;QAyCtB,kBAAa,GAAG,GAAG,EAAE;YACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC,CAAC;QAEe,mBAAc,GAAG,GAAG,EAAE;YACrC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC,CAAC;QAoDF;;;;WAIG;QACc,kBAAa,GAAG,CAAC,KAAoB,EAAE,EAAE;YACxD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,KAAK,WAAW,CAAC;YACzC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC;YACrC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,KAAK,WAAW,CAAC;YACzC,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,YAAY,CAAC;YAC3C,wBAAwB;YACxB,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;gBAC3C,OAAO;aACR;YAED,2DAA2D;YAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;gBACpB,OAAO;aACR;YAED,8DAA8D;YAC9D,qDAAqD;YACrD,KAAK,CAAC,cAAc,EAAE,CAAC;YAEvB,wCAAwC;YACxC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC;YAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC;YAE9D,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;YACzD,8DAA8D;YAC9D,8DAA8D;YAC9D,OAAO,SAAS,KAAK,SAAS,EAAE;gBAC9B,IAAI,SAAS,IAAI,QAAQ,CAAC,MAAM,EAAE;oBAChC,gDAAgD;oBAChD,SAAS,GAAG,CAAC,CAAC;iBACf;qBAAM,IAAI,SAAS,GAAG,CAAC,EAAE;oBACxB,6CAA6C;oBAC7C,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;iBACjC;gBAED,gDAAgD;gBAChD,yCAAyC;gBACzC,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;gBACxC,IAAI,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE;oBACxC,IAAI,QAAQ,EAAE;wBACZ,SAAS,EAAE,CAAC;qBACb;yBAAM;wBACL,SAAS,EAAE,CAAC;qBACb;oBAED,SAAS;iBACV;gBAED,uDAAuD;gBACvD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;oBAC9B,IAAI,OAAO,KAAK,WAAW,EAAE;wBAC3B,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;wBACxB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;wBACtB,OAAO,CAAC,IAAI,EAAE,CAAC;qBAChB;iBACF;gBAED,0EAA0E;gBAC1E,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;gBAC3B,WAAW,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACzB,WAAW,CAAC,KAAK,EAAE,CAAC;gBACpB,sEAAsE;gBACtE,qDAAqD;gBACrD,WAAW,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC,CAAC,CAAC;gBAEhE,MAAM;aACP;QACH,CAAC,CAAC;IA7K0D,CAAC;IAE7D,aAAa;QACX,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAgB,CAAC;QAClD,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5D,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACrB,uEAAuE;YACvE,wCAAwC;YACxC,IAAI,CAAC,eAAe,EAAE,CAAC;SACxB;QAED,mCAAmC;QACnC,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/D,gDAAgD;QAChD,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,mBAAmB;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACtB,OAAO;SACR;QAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAYO,eAAe;QACrB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,gBAAgB,EAAE,EAAE;YAC7C,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,EAAE;gBACzB,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;aACzB;SACF;IACH,CAAC;IAED;;OAEG;IACK,gBAAgB;QACtB,2DAA2D;QAC3D,oDAAoD;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACzC,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnE,mEAAmE;QACnE,IAAI,cAAc,IAAI,IAAI,CAAC,OAAO,EAAE;YAClC,MAAM,SAAS,GAAG,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC;YAC9C,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC;YAEvB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;gBAC9B,IAAI,OAAO,KAAK,SAAS,EAAE;oBACzB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;iBACvB;aACF;YACD,OAAO;SACR;QAED,wDAAwD;QACxD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC9B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;SACtB;IACH,CAAC;IAED;;;OAGG;IACK,gBAAgB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACvB,OAAO,EAAE,CAAC;SACX;QAED,OAAO,KAAK,CAAC,IAAI,CACf,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAyB,UAAU,IAAI,IAAI,CAAC,CACvE,CAAC;IACJ,CAAC;CA6EF","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {ReactiveController} from 'lit';\n\n/**\n * An element that supports single-selection with `SingleSelectionController`.\n */\nexport interface SingleSelectionElement extends HTMLElement {\n /**\n * Whether or not the element is selected.\n */\n checked: boolean;\n}\n\n/**\n * A `ReactiveController` that provides root node-scoped single selection for\n * elements, similar to native `<input type=\"radio\">` selection.\n *\n * To use, elements should add the controller and call\n * `selectionController.handleCheckedChange()` in a getter/setter. This must\n * be synchronous to match native behavior.\n *\n * @example\n * const CHECKED = Symbol('checked');\n *\n * class MyToggle extends LitElement {\n * get checked() { return this[CHECKED]; }\n * set checked(checked: boolean) {\n * const oldValue = this.checked;\n * if (oldValue === checked) {\n * return;\n * }\n *\n * this[CHECKED] = checked;\n * this.selectionController.handleCheckedChange();\n * this.requestUpdate('checked', oldValue);\n * }\n *\n * [CHECKED] = false;\n *\n * private selectionController = new SingleSelectionController(this);\n *\n * constructor() {\n * super();\n * this.addController(this.selectionController);\n * }\n * }\n */\nexport class SingleSelectionController implements ReactiveController {\n private focused = false;\n private root: ParentNode | null = null;\n\n constructor(private readonly host: SingleSelectionElement) {}\n\n hostConnected() {\n this.root = this.host.getRootNode() as ParentNode;\n this.host.addEventListener('keydown', this.handleKeyDown);\n this.host.addEventListener('focusin', this.handleFocusIn);\n this.host.addEventListener('focusout', this.handleFocusOut);\n if (this.host.checked) {\n // Uncheck other siblings when attached if already checked. This mimics\n // native <input type=\"radio\"> behavior.\n this.uncheckSiblings();\n }\n\n // Update for the newly added host.\n this.updateTabIndices();\n }\n\n hostDisconnected() {\n this.host.removeEventListener('keydown', this.handleKeyDown);\n this.host.removeEventListener('focusin', this.handleFocusIn);\n this.host.removeEventListener('focusout', this.handleFocusOut);\n // Update for siblings that are still connected.\n this.updateTabIndices();\n this.root = null;\n }\n\n /**\n * Should be called whenever the host's `checked` property changes\n * synchronously.\n */\n handleCheckedChange() {\n if (!this.host.checked) {\n return;\n }\n\n this.uncheckSiblings();\n this.updateTabIndices();\n }\n\n private readonly handleFocusIn = () => {\n this.focused = true;\n this.updateTabIndices();\n };\n\n private readonly handleFocusOut = () => {\n this.focused = false;\n this.updateTabIndices();\n };\n\n private uncheckSiblings() {\n for (const sibling of this.getNamedSiblings()) {\n if (sibling !== this.host) {\n sibling.checked = false;\n }\n }\n }\n\n /**\n * Updates the `tabindex` of the host and its siblings.\n */\n private updateTabIndices() {\n // There are three tabindex states for a group of elements:\n // 1. If any are checked, that element is focusable.\n const siblings = this.getNamedSiblings();\n const checkedSibling = siblings.find((sibling) => sibling.checked);\n // 2. If an element is focused, the others are no longer focusable.\n if (checkedSibling || this.focused) {\n const focusable = checkedSibling || this.host;\n focusable.tabIndex = 0;\n\n for (const sibling of siblings) {\n if (sibling !== focusable) {\n sibling.tabIndex = -1;\n }\n }\n return;\n }\n\n // 3. If none are checked or focused, all are focusable.\n for (const sibling of siblings) {\n sibling.tabIndex = 0;\n }\n }\n\n /**\n * Retrieves all siblings in the host element's root with the same `name`\n * attribute.\n */\n private getNamedSiblings() {\n const name = this.host.getAttribute('name');\n if (!name || !this.root) {\n return [];\n }\n\n return Array.from(\n this.root.querySelectorAll<SingleSelectionElement>(`[name=\"${name}\"]`),\n );\n }\n\n /**\n * Handles arrow key events from the host. Using the arrow keys will\n * select and check the next or previous sibling with the host's\n * `name` attribute.\n */\n private readonly handleKeyDown = (event: KeyboardEvent) => {\n const isDown = event.key === 'ArrowDown';\n const isUp = event.key === 'ArrowUp';\n const isLeft = event.key === 'ArrowLeft';\n const isRight = event.key === 'ArrowRight';\n // Ignore non-arrow keys\n if (!isLeft && !isRight && !isDown && !isUp) {\n return;\n }\n\n // Don't try to select another sibling if there aren't any.\n const siblings = this.getNamedSiblings();\n if (!siblings.length) {\n return;\n }\n\n // Prevent default interactions on the element for arrow keys,\n // since this controller will introduce new behavior.\n event.preventDefault();\n\n // Check if moving forwards or backwards\n const isRtl = getComputedStyle(this.host).direction === 'rtl';\n const forwards = isRtl ? isLeft || isDown : isRight || isDown;\n\n const hostIndex = siblings.indexOf(this.host);\n let nextIndex = forwards ? hostIndex + 1 : hostIndex - 1;\n // Search for the next sibling that is not disabled to select.\n // If we return to the host index, there is nothing to select.\n while (nextIndex !== hostIndex) {\n if (nextIndex >= siblings.length) {\n // Return to start if moving past the last item.\n nextIndex = 0;\n } else if (nextIndex < 0) {\n // Go to end if moving before the first item.\n nextIndex = siblings.length - 1;\n }\n\n // Check if the next sibling is disabled. If so,\n // move the index and continue searching.\n const nextSibling = siblings[nextIndex];\n if (nextSibling.hasAttribute('disabled')) {\n if (forwards) {\n nextIndex++;\n } else {\n nextIndex--;\n }\n\n continue;\n }\n\n // Uncheck and remove focusability from other siblings.\n for (const sibling of siblings) {\n if (sibling !== nextSibling) {\n sibling.checked = false;\n sibling.tabIndex = -1;\n sibling.blur();\n }\n }\n\n // The next sibling should be checked, focused and dispatch a change event\n nextSibling.checked = true;\n nextSibling.tabIndex = 0;\n nextSibling.focus();\n // Fire a change event since the change is triggered by a user action.\n // This matches native <input type=\"radio\"> behavior.\n nextSibling.dispatchEvent(new Event('change', {bubbles: true}));\n\n break;\n }\n };\n}\n"]}
1
+ {"version":3,"file":"single-selection-controller.js","sourceRoot":"","sources":["single-selection-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {ReactiveController} from 'lit';\n\n/**\n * An element that supports single-selection with `SingleSelectionController`.\n */\nexport interface SingleSelectionElement extends HTMLElement {\n /**\n * Whether or not the element is selected.\n */\n checked: boolean;\n}\n\n/**\n * A `ReactiveController` that provides root node-scoped single selection for\n * elements, similar to native `<input type=\"radio\">` selection.\n *\n * To use, elements should add the controller and call\n * `selectionController.handleCheckedChange()` in a getter/setter. This must\n * be synchronous to match native behavior.\n *\n * @example\n * const CHECKED = Symbol('checked');\n *\n * class MyToggle extends LitElement {\n * get checked() { return this[CHECKED]; }\n * set checked(checked: boolean) {\n * const oldValue = this.checked;\n * if (oldValue === checked) {\n * return;\n * }\n *\n * this[CHECKED] = checked;\n * this.selectionController.handleCheckedChange();\n * this.requestUpdate('checked', oldValue);\n * }\n *\n * [CHECKED] = false;\n *\n * private selectionController = new SingleSelectionController(this);\n *\n * constructor() {\n * super();\n * this.addController(this.selectionController);\n * }\n * }\n */\nexport class SingleSelectionController implements ReactiveController {\n /**\n * All single selection elements in the host element's root with the same\n * `name` attribute, including the host element.\n */\n get controls(): [SingleSelectionElement, ...SingleSelectionElement[]] {\n const name = this.host.getAttribute('name');\n if (!name || !this.root || !this.host.isConnected) {\n return [this.host];\n }\n\n // Cast as unknown since there is not enough information for typescript to\n // know that there is always at least one element (the host).\n return Array.from(\n this.root.querySelectorAll<SingleSelectionElement>(`[name=\"${name}\"]`),\n ) as unknown as [SingleSelectionElement, ...SingleSelectionElement[]];\n }\n\n private focused = false;\n private root: ParentNode | null = null;\n\n constructor(private readonly host: SingleSelectionElement) {}\n\n hostConnected() {\n this.root = this.host.getRootNode() as ParentNode;\n this.host.addEventListener('keydown', this.handleKeyDown);\n this.host.addEventListener('focusin', this.handleFocusIn);\n this.host.addEventListener('focusout', this.handleFocusOut);\n if (this.host.checked) {\n // Uncheck other siblings when attached if already checked. This mimics\n // native <input type=\"radio\"> behavior.\n this.uncheckSiblings();\n }\n\n // Update for the newly added host.\n this.updateTabIndices();\n }\n\n hostDisconnected() {\n this.host.removeEventListener('keydown', this.handleKeyDown);\n this.host.removeEventListener('focusin', this.handleFocusIn);\n this.host.removeEventListener('focusout', this.handleFocusOut);\n // Update for siblings that are still connected.\n this.updateTabIndices();\n this.root = null;\n }\n\n /**\n * Should be called whenever the host's `checked` property changes\n * synchronously.\n */\n handleCheckedChange() {\n if (!this.host.checked) {\n return;\n }\n\n this.uncheckSiblings();\n this.updateTabIndices();\n }\n\n private readonly handleFocusIn = () => {\n this.focused = true;\n this.updateTabIndices();\n };\n\n private readonly handleFocusOut = () => {\n this.focused = false;\n this.updateTabIndices();\n };\n\n private uncheckSiblings() {\n for (const sibling of this.controls) {\n if (sibling !== this.host) {\n sibling.checked = false;\n }\n }\n }\n\n /**\n * Updates the `tabindex` of the host and its siblings.\n */\n private updateTabIndices() {\n // There are three tabindex states for a group of elements:\n // 1. If any are checked, that element is focusable.\n const siblings = this.controls;\n const checkedSibling = siblings.find((sibling) => sibling.checked);\n // 2. If an element is focused, the others are no longer focusable.\n if (checkedSibling || this.focused) {\n const focusable = checkedSibling || this.host;\n focusable.tabIndex = 0;\n\n for (const sibling of siblings) {\n if (sibling !== focusable) {\n sibling.tabIndex = -1;\n }\n }\n return;\n }\n\n // 3. If none are checked or focused, all are focusable.\n for (const sibling of siblings) {\n sibling.tabIndex = 0;\n }\n }\n\n /**\n * Handles arrow key events from the host. Using the arrow keys will\n * select and check the next or previous sibling with the host's\n * `name` attribute.\n */\n private readonly handleKeyDown = (event: KeyboardEvent) => {\n const isDown = event.key === 'ArrowDown';\n const isUp = event.key === 'ArrowUp';\n const isLeft = event.key === 'ArrowLeft';\n const isRight = event.key === 'ArrowRight';\n // Ignore non-arrow keys\n if (!isLeft && !isRight && !isDown && !isUp) {\n return;\n }\n\n // Don't try to select another sibling if there aren't any.\n const siblings = this.controls;\n if (!siblings.length) {\n return;\n }\n\n // Prevent default interactions on the element for arrow keys,\n // since this controller will introduce new behavior.\n event.preventDefault();\n\n // Check if moving forwards or backwards\n const isRtl = getComputedStyle(this.host).direction === 'rtl';\n const forwards = isRtl ? isLeft || isDown : isRight || isDown;\n\n const hostIndex = siblings.indexOf(this.host);\n let nextIndex = forwards ? hostIndex + 1 : hostIndex - 1;\n // Search for the next sibling that is not disabled to select.\n // If we return to the host index, there is nothing to select.\n while (nextIndex !== hostIndex) {\n if (nextIndex >= siblings.length) {\n // Return to start if moving past the last item.\n nextIndex = 0;\n } else if (nextIndex < 0) {\n // Go to end if moving before the first item.\n nextIndex = siblings.length - 1;\n }\n\n // Check if the next sibling is disabled. If so,\n // move the index and continue searching.\n const nextSibling = siblings[nextIndex];\n if (nextSibling.hasAttribute('disabled')) {\n if (forwards) {\n nextIndex++;\n } else {\n nextIndex--;\n }\n\n continue;\n }\n\n // Uncheck and remove focusability from other siblings.\n for (const sibling of siblings) {\n if (sibling !== nextSibling) {\n sibling.checked = false;\n sibling.tabIndex = -1;\n sibling.blur();\n }\n }\n\n // The next sibling should be checked, focused and dispatch a change event\n nextSibling.checked = true;\n nextSibling.tabIndex = 0;\n nextSibling.focus();\n // Fire a change event since the change is triggered by a user action.\n // This matches native <input type=\"radio\"> behavior.\n nextSibling.dispatchEvent(new Event('change', {bubbles: true}));\n\n break;\n }\n };\n}\n"]}
@@ -69,6 +69,11 @@
69
69
  display: flex;
70
70
  }
71
71
 
72
+ md-menu {
73
+ min-width: var(--__menu-min-width, inherit);
74
+ max-width: var(--__menu-max-width, inherit);
75
+ }
76
+
72
77
  md-menu ::slotted(:not[disabled]) {
73
78
  cursor: pointer;
74
79
  }
@@ -6,10 +6,14 @@
6
6
  import '../../menu/menu.js';
7
7
  import { LitElement, PropertyValues } from 'lit';
8
8
  import { StaticValue } from 'lit/static-html.js';
9
+ import { Field } from '../../field/internal/field.js';
10
+ import { createValidator, getValidityAnchor } from '../../labs/behaviors/constraint-validation.js';
9
11
  import { getFormValue } from '../../labs/behaviors/form-associated.js';
12
+ import { onReportValidity } from '../../labs/behaviors/on-report-validity.js';
13
+ import { SelectValidator } from '../../labs/behaviors/validators/select-validator.js';
10
14
  import { SelectOption } from './selectoption/selectOptionController.js';
11
15
  declare const VALUE: unique symbol;
12
- declare const selectBaseClass: import("../../labs/behaviors/mixin.js").MixinReturn<(abstract new (...args: any[]) => import("../../labs/behaviors/element-internals.js").WithElementInternals) & typeof LitElement & import("../../labs/behaviors/form-associated.js").FormAssociatedConstructor, import("../../labs/behaviors/form-associated.js").FormAssociated>;
16
+ declare const selectBaseClass: import("../../labs/behaviors/mixin.js").MixinReturn<import("../../labs/behaviors/mixin.js").MixinReturn<import("../../labs/behaviors/mixin.js").MixinReturn<(abstract new (...args: any[]) => import("../../labs/behaviors/element-internals.js").WithElementInternals) & typeof LitElement & import("../../labs/behaviors/form-associated.js").FormAssociatedConstructor, import("../../labs/behaviors/form-associated.js").FormAssociated>, import("../../labs/behaviors/constraint-validation.js").ConstraintValidation>, import("../../labs/behaviors/on-report-validity.js").OnReportValidity>;
13
17
  /**
14
18
  * @fires change {Event} The native `change` event on
15
19
  * [`<input>`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event)
@@ -25,6 +29,12 @@ declare const selectBaseClass: import("../../labs/behaviors/mixin.js").MixinRetu
25
29
  * and closed.
26
30
  */
27
31
  export declare abstract class Select extends selectBaseClass {
32
+ /** @nocollapse */
33
+ static shadowRootOptions: {
34
+ delegatesFocus: boolean;
35
+ mode: ShadowRootMode;
36
+ slotAssignment?: SlotAssignmentMode;
37
+ };
28
38
  /**
29
39
  * Opens the menu synchronously with no animation.
30
40
  */
@@ -66,6 +76,10 @@ export declare abstract class Select extends selectBaseClass {
66
76
  * element with stacking context and hidden overflows such as `md-dialog`.
67
77
  */
68
78
  menuPositioning: 'absolute' | 'fixed' | 'popover';
79
+ /**
80
+ * Clamps the menu-width to the width of the select.
81
+ */
82
+ clampMenuWidth: boolean;
69
83
  /**
70
84
  * The max time between the keystrokes of the typeahead select / menu behavior
71
85
  * before it clears the typeahead buffer.
@@ -104,27 +118,6 @@ export declare abstract class Select extends selectBaseClass {
104
118
  * NOTE: md-select only suppoprts single selection.
105
119
  */
106
120
  get selectedOptions(): SelectOption[];
107
- /**
108
- * Returns a ValidityState object that represents the validity states of the
109
- * checkbox.
110
- *
111
- * Note that selects will only set `valueMissing` if unselected and
112
- * `required`.
113
- */
114
- get validity(): ValidityState;
115
- /**
116
- * Returns the native validation error message.
117
- *
118
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#constraint_validation_process
119
- */
120
- get validationMessage(): string;
121
- /**
122
- * Returns whether an element will successfully validate based on forms
123
- * validation rules and constraints.
124
- *
125
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#constraint_validation_process
126
- */
127
- get willValidate(): boolean;
128
121
  protected abstract readonly fieldTag: StaticValue;
129
122
  /**
130
123
  * Used for initializing select when the user sets the `value` directly.
@@ -156,9 +149,9 @@ export declare abstract class Select extends selectBaseClass {
156
149
  private readonly menu;
157
150
  private readonly labelEl;
158
151
  private readonly leadingIcons;
159
- private isCheckingValidity;
160
- private isReportingValidity;
161
- private customValidationMessage;
152
+ private prevOpen;
153
+ private selectWidth;
154
+ constructor();
162
155
  /**
163
156
  * Selects an option given the value of the option, and updates MdSelect's
164
157
  * value.
@@ -173,50 +166,9 @@ export declare abstract class Select extends selectBaseClass {
173
166
  * Reset the select to its default value.
174
167
  */
175
168
  reset(): void;
176
- /**
177
- * Checks the select's native validation and returns whether or not the
178
- * element is valid.
179
- *
180
- * If invalid, this method will dispatch the `invalid` event.
181
- *
182
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/checkValidity
183
- *
184
- * @return true if the select is valid, or false if not.
185
- */
186
- checkValidity(): boolean;
187
- /**
188
- * Checks the select's native validation and returns whether or not the
189
- * element is valid.
190
- *
191
- * If invalid, this method will dispatch the `invalid` event.
192
- *
193
- * This method will display or clear an error text message equal to the
194
- * select's `validationMessage`, unless the invalid event is canceled.
195
- *
196
- * Use `setCustomValidity()` to customize the `validationMessage`.
197
- *
198
- * This method can also be used to re-announce error messages to screen
199
- * readers.
200
- *
201
- * @return true if the select is valid, or false if not.
202
- */
203
- reportValidity(): boolean;
204
- private showErrorMessage;
205
- /**
206
- * Sets the select's native validation error message. This is used to
207
- * customize `validationMessage`.
208
- *
209
- * When the error is not an empty string, the select is considered invalid
210
- * and `validity.customError` will be true.
211
- *
212
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/setCustomValidity
213
- *
214
- * @param error The error message to display.
215
- */
216
- setCustomValidity(error: string): void;
169
+ [onReportValidity](invalidEvent: Event | null): void;
217
170
  protected update(changed: PropertyValues<Select>): void;
218
171
  protected render(): import("lit-html").TemplateResult<1>;
219
- protected updated(changed: PropertyValues<Select>): void;
220
172
  protected firstUpdated(changed: PropertyValues<Select>): Promise<void>;
221
173
  private getRenderClasses;
222
174
  private renderField;
@@ -290,15 +242,12 @@ export declare abstract class Select extends selectBaseClass {
290
242
  */
291
243
  private dispatchInteractionEvents;
292
244
  private getErrorText;
293
- private syncValidity;
294
- private getRequiredValidationMessage;
295
- private readonly onInvalid;
296
- connectedCallback(): void;
297
- disconnectedCallback(): void;
298
245
  disabled: boolean;
299
246
  name: string;
300
247
  [getFormValue](): string;
301
248
  formResetCallback(): void;
302
249
  formStateRestoreCallback(state: string): void;
250
+ [createValidator](): SelectValidator;
251
+ [getValidityAnchor](): Field;
303
252
  }
304
253
  export {};
@@ -9,11 +9,15 @@ import '../../menu/menu.js';
9
9
  import { html, isServer, LitElement, nothing } from 'lit';
10
10
  import { property, query, queryAssignedElements, state } from 'lit/decorators.js';
11
11
  import { classMap } from 'lit/directives/class-map.js';
12
+ import { styleMap } from 'lit/directives/style-map.js';
12
13
  import { html as staticHtml } from 'lit/static-html.js';
13
14
  import { requestUpdateOnAriaChange } from '../../internal/aria/delegate.js';
14
15
  import { redispatchEvent } from '../../internal/controller/events.js';
15
- import { internals, mixinElementInternals, } from '../../labs/behaviors/element-internals.js';
16
+ import { createValidator, getValidityAnchor, mixinConstraintValidation, } from '../../labs/behaviors/constraint-validation.js';
17
+ import { mixinElementInternals } from '../../labs/behaviors/element-internals.js';
16
18
  import { getFormValue, mixinFormAssociated, } from '../../labs/behaviors/form-associated.js';
19
+ import { mixinOnReportValidity, onReportValidity, } from '../../labs/behaviors/on-report-validity.js';
20
+ import { SelectValidator } from '../../labs/behaviors/validators/select-validator.js';
17
21
  import { getActiveItem } from '../../list/internal/list-navigation-helpers.js';
18
22
  import { isElementInSubtree, isSelectableKey, } from '../../menu/internal/controllers/shared.js';
19
23
  import { TYPEAHEAD_RECORD } from '../../menu/internal/controllers/typeaheadController.js';
@@ -21,7 +25,7 @@ import { DEFAULT_TYPEAHEAD_BUFFER_TIME } from '../../menu/internal/menu.js';
21
25
  import { getSelectedItems } from './shared.js';
22
26
  const VALUE = Symbol('value');
23
27
  // Separate variable needed for closure.
24
- const selectBaseClass = mixinFormAssociated(mixinElementInternals(LitElement));
28
+ const selectBaseClass = mixinOnReportValidity(mixinConstraintValidation(mixinFormAssociated(mixinElementInternals(LitElement))));
25
29
  /**
26
30
  * @fires change {Event} The native `change` event on
27
31
  * [`<input>`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event)
@@ -37,8 +41,54 @@ const selectBaseClass = mixinFormAssociated(mixinElementInternals(LitElement));
37
41
  * and closed.
38
42
  */
39
43
  export class Select extends selectBaseClass {
44
+ /**
45
+ * The value of the currently selected option.
46
+ *
47
+ * Note: For SSR, set `[selected]` on the requested option and `displayText`
48
+ * rather than setting `value` setting `value` will incur a DOM query.
49
+ */
50
+ get value() {
51
+ return this[VALUE];
52
+ }
53
+ set value(value) {
54
+ if (isServer)
55
+ return;
56
+ this.lastUserSetValue = value;
57
+ this.select(value);
58
+ }
59
+ get options() {
60
+ // NOTE: this does a DOM query.
61
+ return (this.menu?.items ?? []);
62
+ }
63
+ /**
64
+ * The index of the currently selected option.
65
+ *
66
+ * Note: For SSR, set `[selected]` on the requested option and `displayText`
67
+ * rather than setting `selectedIndex` setting `selectedIndex` will incur a
68
+ * DOM query.
69
+ */
70
+ get selectedIndex() {
71
+ // tslint:disable-next-line:enforce-name-casing
72
+ const [_option, index] = (this.getSelectedOptions() ?? [])[0] ?? [];
73
+ return index ?? -1;
74
+ }
75
+ set selectedIndex(index) {
76
+ this.lastUserSetSelectedIndex = index;
77
+ this.selectIndex(index);
78
+ }
79
+ /**
80
+ * Returns an array of selected options.
81
+ *
82
+ * NOTE: md-select only suppoprts single selection.
83
+ */
84
+ get selectedOptions() {
85
+ return (this.getSelectedOptions() ?? []).map(([option]) => option);
86
+ }
87
+ get hasError() {
88
+ return this.error || this.nativeError;
89
+ }
40
90
  constructor() {
41
- super(...arguments);
91
+ super();
42
92
  /**
43
93
  * Opens the menu synchronously with no animation.
44
94
  */
@@ -80,6 +130,10 @@ export class Select extends selectBaseClass {
80
130
  * element with stacking context and hidden overflows such as `md-dialog`.
81
131
  */
82
132
  this.menuPositioning = 'popover';
133
+ /**
134
+ * Clamps the menu-width to the width of the select.
135
+ */
136
+ this.clampMenuWidth = false;
83
137
  /**
84
138
  * The max time between the keystrokes of the typeahead select / menu behavior
85
139
  * before it clears the typeahead buffer.
@@ -120,91 +174,15 @@ export class Select extends selectBaseClass {
120
174
  this.nativeErrorText = '';
121
175
  this.focused = false;
122
176
  this.open = false;
123
- this.isCheckingValidity = false;
124
- this.isReportingValidity = false;
125
- this.customValidationMessage = '';
126
- this.onInvalid = (invalidEvent) => {
127
- if (this.isCheckingValidity || this.isReportingValidity) {
128
- return;
129
- }
130
- this.showErrorMessage(false, invalidEvent);
131
- };
132
- }
133
- /**
134
- * The value of the currently selected option.
135
- *
136
- * Note: For SSR, set `[selected]` on the requested option and `displayText`
137
- * rather than setting `value` setting `value` will incur a DOM query.
138
- */
139
- get value() {
140
- return this[VALUE];
141
- }
142
- set value(value) {
143
- if (isServer)
177
+ // Have to keep track of previous open because it's state and private and thus
178
+ // cannot be tracked in PropertyValues<this> map.
179
+ this.prevOpen = this.open;
180
+ this.selectWidth = 0;
181
+ if (isServer) {
144
182
  return;
145
- this.lastUserSetValue = value;
146
- this.select(value);
147
- }
148
- get options() {
149
- // NOTE: this does a DOM query.
150
- return (this.menu?.items ?? []);
151
- }
152
- /**
153
- * The index of the currently selected option.
154
- *
155
- * Note: For SSR, set `[selected]` on the requested option and `displayText`
156
- * rather than setting `selectedIndex` setting `selectedIndex` will incur a
157
- * DOM query.
158
- */
159
- get selectedIndex() {
160
- // tslint:disable-next-line:enforce-name-casing
161
- const [_option, index] = (this.getSelectedOptions() ?? [])[0] ?? [];
162
- return index ?? -1;
163
- }
164
- set selectedIndex(index) {
165
- this.lastUserSetSelectedIndex = index;
166
- this.selectIndex(index);
167
- }
168
- /**
169
- * Returns an array of selected options.
170
- *
171
- * NOTE: md-select only suppoprts single selection.
172
- */
173
- get selectedOptions() {
174
- return (this.getSelectedOptions() ?? []).map(([option]) => option);
175
- }
176
- /**
177
- * Returns a ValidityState object that represents the validity states of the
178
- * checkbox.
179
- *
180
- * Note that selects will only set `valueMissing` if unselected and
181
- * `required`.
182
- */
183
- get validity() {
184
- this.syncValidity();
185
- return this[internals].validity;
186
- }
187
- /**
188
- * Returns the native validation error message.
189
- *
190
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#constraint_validation_process
191
- */
192
- get validationMessage() {
193
- this.syncValidity();
194
- return this[internals].validationMessage;
195
- }
196
- /**
197
- * Returns whether an element will successfully validate based on forms
198
- * validation rules and constraints.
199
- *
200
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#constraint_validation_process
201
- */
202
- get willValidate() {
203
- this.syncValidity();
204
- return this[internals].willValidate;
205
- }
206
- get hasError() {
207
- return this.error || this.nativeError;
183
+ }
184
+ this.addEventListener('focus', this.handleFocus.bind(this));
185
+ this.addEventListener('blur', this.handleBlur.bind(this));
208
186
  }
209
187
  /**
210
188
  * Selects an option given the value of the option, and updates MdSelect's
@@ -237,76 +215,22 @@ export class Select extends selectBaseClass {
237
215
  this.nativeError = false;
238
216
  this.nativeErrorText = '';
239
217
  }
240
- /**
241
- * Checks the select's native validation and returns whether or not the
242
- * element is valid.
243
- *
244
- * If invalid, this method will dispatch the `invalid` event.
245
- *
246
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/checkValidity
247
- *
248
- * @return true if the select is valid, or false if not.
249
- */
250
- checkValidity() {
251
- this.isCheckingValidity = true;
252
- this.syncValidity();
253
- const isValid = this[internals].checkValidity();
254
- this.isCheckingValidity = false;
255
- return isValid;
256
- }
257
- /**
258
- * Checks the select's native validation and returns whether or not the
259
- * element is valid.
260
- *
261
- * If invalid, this method will dispatch the `invalid` event.
262
- *
263
- * This method will display or clear an error text message equal to the
264
- * select's `validationMessage`, unless the invalid event is canceled.
265
- *
266
- * Use `setCustomValidity()` to customize the `validationMessage`.
267
- *
268
- * This method can also be used to re-announce error messages to screen
269
- * readers.
270
- *
271
- * @return true if the select is valid, or false if not.
272
- */
273
- reportValidity() {
274
- this.isReportingValidity = true;
275
- let invalidEvent;
276
- this.addEventListener('invalid', (event) => {
277
- invalidEvent = event;
278
- }, { once: true });
279
- const valid = this.checkValidity();
280
- this.showErrorMessage(valid, invalidEvent);
281
- this.isReportingValidity = false;
282
- return valid;
283
- }
284
- showErrorMessage(valid, invalidEvent) {
218
+ [(_a = VALUE, onReportValidity)](invalidEvent) {
285
219
  if (invalidEvent?.defaultPrevented) {
286
- return valid;
220
+ return;
221
+ }
222
+ if (invalidEvent) {
223
+ // Prevent default pop-up behavior. This also prevents focusing, so we
224
+ // manually focus.
225
+ invalidEvent.preventDefault();
226
+ this.focus();
287
227
  }
288
228
  const prevMessage = this.getErrorText();
289
- this.nativeError = !valid;
229
+ this.nativeError = !!invalidEvent;
290
230
  this.nativeErrorText = this.validationMessage;
291
231
  if (prevMessage === this.getErrorText()) {
292
232
  this.field?.reannounceError();
293
233
  }
294
- return valid;
295
- }
296
- /**
297
- * Sets the select's native validation error message. This is used to
298
- * customize `validationMessage`.
299
- *
300
- * When the error is not an empty string, the select is considered invalid
301
- * and `validity.customError` will be true.
302
- *
303
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/setCustomValidity
304
- *
305
- * @param error The error message to display.
306
- */
307
- setCustomValidity(error) {
308
- this.customValidationMessage = error;
309
- this.syncValidity();
310
234
  }
311
235
  update(changed) {
312
236
  // In SSR the options will be ready to query, so try to figure out what
@@ -314,6 +238,16 @@ export class Select extends selectBaseClass {
314
238
  if (!this.hasUpdated) {
315
239
  this.initUserSelection();
316
240
  }
241
+ // We have just opened the menu.
242
+ // We are only able to check for the select's rect in `update()` instead of
243
+ // having to wait for `updated()` because the menu can never be open on
244
+ // first render since it is not settable and Lit SSR does not support click
245
+ // events which would open the menu.
246
+ if (this.prevOpen !== this.open && this.open) {
247
+ const selectRect = this.getBoundingClientRect();
248
+ this.selectWidth = selectRect.width;
249
+ }
250
+ this.prevOpen = this.open;
317
251
  super.update(changed);
318
252
  }
319
253
  render() {
@@ -325,11 +259,6 @@ export class Select extends selectBaseClass {
325
259
  </span>
326
260
  `;
327
261
  }
328
- updated(changed) {
329
- if (changed.has('required')) {
330
- this.syncValidity();
331
- }
332
- }
333
262
  async firstUpdated(changed) {
334
263
  await this.menu?.updateComplete;
335
264
  // If this has been handled on update already due to SSR, try again.
@@ -379,9 +308,7 @@ export class Select extends selectBaseClass {
379
308
  supporting-text=${this.supportingText}
380
309
  error-text=${this.getErrorText()}
381
310
  @keydown=${this.handleKeydown}
382
- @click=${this.handleClick}
383
- @focus=${this.handleFocus}
384
- @blur=${this.handleBlur}>
311
+ @click=${this.handleClick}>
385
312
  ${this.renderFieldContent()}
386
313
  <div id="description" slot="aria-describedby"></div>
387
314
  </${this.fieldTag}>`;
@@ -437,6 +364,12 @@ export class Select extends selectBaseClass {
437
364
  part="menu"
438
365
  exportparts="focus-ring: menu-focus-ring"
439
366
  anchor="field"
367
+ style=${styleMap({
368
+ '--__menu-min-width': `${this.selectWidth}px`,
369
+ '--__menu-max-width': this.clampMenuWidth
370
+ ? `${this.selectWidth}px`
371
+ : undefined,
372
+ })}
440
373
  .open=${this.open}
441
374
  .quick=${this.quick}
442
375
  .positioning=${this.menuPositioning}
@@ -554,7 +487,6 @@ export class Select extends selectBaseClass {
554
487
  this[VALUE] = '';
555
488
  this.displayText = '';
556
489
  }
557
- this.syncValidity();
558
490
  return hasSelectedOptionChanged;
559
491
  }
560
492
  /**
@@ -683,31 +615,7 @@ export class Select extends selectBaseClass {
683
615
  getErrorText() {
684
616
  return this.error ? this.errorText : this.nativeErrorText;
685
617
  }
686
- syncValidity() {
687
- const valueMissing = this.required && !this.value;
688
- const customError = !!this.customValidationMessage;
689
- const validationMessage = this.customValidationMessage ||
690
- (valueMissing && this.getRequiredValidationMessage()) ||
691
- '';
692
- this[internals].setValidity({ valueMissing, customError }, validationMessage, this.field ?? undefined);
693
- }
694
- // Returns the platform `<select>` validation message for i18n.
695
- getRequiredValidationMessage() {
696
- const select = document.createElement('select');
697
- select.required = true;
698
- return select.validationMessage;
699
- }
700
- connectedCallback() {
701
- super.connectedCallback();
702
- // Handles the case where the user submits the form and native validation
703
- // error pops up. We want the error styles to show.
704
- this.addEventListener('invalid', this.onInvalid);
705
- }
706
- disconnectedCallback() {
707
- super.disconnectedCallback();
708
- this.removeEventListener('invalid', this.onInvalid);
709
- }
710
- [(_a = VALUE, getFormValue)]() {
618
+ [getFormValue]() {
711
619
  return this.value;
712
620
  }
713
621
  formResetCallback() {
@@ -716,10 +624,21 @@ export class Select extends selectBaseClass {
716
624
  formStateRestoreCallback(state) {
717
625
  this.value = state;
718
626
  }
627
+ [createValidator]() {
628
+ return new SelectValidator(() => this);
629
+ }
630
+ [getValidityAnchor]() {
631
+ return this.field;
632
+ }
719
633
  }
720
634
  (() => {
721
635
  requestUpdateOnAriaChange(Select);
722
636
  })();
637
+ /** @nocollapse */
638
+ Select.shadowRootOptions = {
639
+ ...LitElement.shadowRootOptions,
640
+ delegatesFocus: true,
641
+ };
723
642
  __decorate([
724
643
  property({ type: Boolean })
725
644
  ], Select.prototype, "quick", void 0);
@@ -741,6 +660,9 @@ __decorate([
741
660
  __decorate([
742
661
  property({ attribute: 'menu-positioning' })
743
662
  ], Select.prototype, "menuPositioning", void 0);
663
+ __decorate([
664
+ property({ type: Boolean, attribute: 'clamp-menu-width' })
665
+ ], Select.prototype, "clampMenuWidth", void 0);
744
666
  __decorate([
745
667
  property({ type: Number, attribute: 'typeahead-delay' })
746
668
  ], Select.prototype, "typeaheadDelay", void 0);