@material/web 0.1.0-alpha.2 → 1.0.0-pre.1

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 (237) hide show
  1. package/autocomplete/lib/_filled-autocomplete.scss +3 -4
  2. package/autocomplete/lib/_outlined-autocomplete.scss +3 -3
  3. package/autocomplete/lib/_shared.scss +2 -7
  4. package/autocomplete/lib/filled-styles.css.js +1 -1
  5. package/autocomplete/lib/filled-styles.css.js.map +1 -1
  6. package/autocomplete/lib/outlined-styles.css.js +1 -1
  7. package/autocomplete/lib/outlined-styles.css.js.map +1 -1
  8. package/button/lib/_elevated-button.scss +6 -0
  9. package/button/lib/_elevation.scss +30 -28
  10. package/button/lib/_filled-button.scss +6 -0
  11. package/button/lib/_icon.scss +5 -12
  12. package/button/lib/_outlined-button.scss +10 -1
  13. package/button/lib/_shared.scss +16 -6
  14. package/button/lib/_text-button.scss +6 -0
  15. package/button/lib/_tonal-button.scss +6 -0
  16. package/button/lib/button.d.ts +1 -11
  17. package/button/lib/button.js +5 -30
  18. package/button/lib/button.js.map +1 -1
  19. package/button/lib/elevated-styles.css.js +1 -1
  20. package/button/lib/elevated-styles.css.js.map +1 -1
  21. package/button/lib/filled-styles.css.js +1 -1
  22. package/button/lib/filled-styles.css.js.map +1 -1
  23. package/button/lib/outlined-styles.css.js +1 -1
  24. package/button/lib/outlined-styles.css.js.map +1 -1
  25. package/button/lib/shared-elevation-styles.css.js +1 -1
  26. package/button/lib/shared-elevation-styles.css.js.map +1 -1
  27. package/button/lib/shared-styles.css.js +1 -1
  28. package/button/lib/shared-styles.css.js.map +1 -1
  29. package/button/lib/text-styles.css.js +1 -1
  30. package/button/lib/text-styles.css.js.map +1 -1
  31. package/button/lib/tonal-styles.css.js +1 -1
  32. package/button/lib/tonal-styles.css.js.map +1 -1
  33. package/checkbox/lib/_checkbox.scss +4 -0
  34. package/checkbox/lib/checkbox-styles.css.js +1 -1
  35. package/checkbox/lib/checkbox-styles.css.js.map +1 -1
  36. package/chips/chip/lib/_chip-theme.scss +19 -23
  37. package/chips/chip/lib/_chip.scss +0 -2
  38. package/chips/chip/lib/_input-chip-theme.scss +16 -26
  39. package/chips/chip/lib/chip.d.ts +1 -0
  40. package/chips/chip/lib/chip.js +2 -1
  41. package/chips/chip/lib/chip.js.map +1 -1
  42. package/fab/fab-extended.js +1 -2
  43. package/fab/fab-extended.js.map +1 -1
  44. package/fab/fab.js +1 -2
  45. package/fab/fab.js.map +1 -1
  46. package/fab/lib/_shared.scss +11 -9
  47. package/fab/lib/fab-shared-styles.css.js +1 -1
  48. package/fab/lib/fab-shared-styles.css.js.map +1 -1
  49. package/field/lib/filled-styles.css.js +1 -1
  50. package/field/lib/filled-styles.css.js.map +1 -1
  51. package/icon/lib/_icon.scss +8 -5
  52. package/icon/lib/icon-styles.css.js +1 -1
  53. package/icon/lib/icon-styles.css.js.map +1 -1
  54. package/iconbutton/lib/_filled-icon-button.scss +14 -0
  55. package/iconbutton/lib/_filled-tonal-icon-button.scss +14 -0
  56. package/iconbutton/lib/_outlined-icon-button.scss +16 -17
  57. package/iconbutton/lib/_shared.scss +29 -16
  58. package/iconbutton/lib/_standard-icon-button.scss +16 -0
  59. package/iconbutton/lib/filled-styles.css.js +1 -1
  60. package/iconbutton/lib/filled-styles.css.js.map +1 -1
  61. package/iconbutton/lib/filled-tonal-styles.css.js +1 -1
  62. package/iconbutton/lib/filled-tonal-styles.css.js.map +1 -1
  63. package/iconbutton/lib/icon-button-toggle.js +1 -1
  64. package/iconbutton/lib/icon-button-toggle.js.map +1 -1
  65. package/iconbutton/lib/icon-button.js +1 -1
  66. package/iconbutton/lib/icon-button.js.map +1 -1
  67. package/iconbutton/lib/outlined-styles.css.js +1 -1
  68. package/iconbutton/lib/outlined-styles.css.js.map +1 -1
  69. package/iconbutton/lib/shared-styles.css.js +1 -1
  70. package/iconbutton/lib/shared-styles.css.js.map +1 -1
  71. package/iconbutton/lib/standard-styles.css.js +1 -1
  72. package/iconbutton/lib/standard-styles.css.js.map +1 -1
  73. package/list/lib/_list.scss +20 -14
  74. package/list/lib/divider/list-divider.js +2 -0
  75. package/list/lib/divider/list-divider.js.map +1 -1
  76. package/list/lib/list-styles.css.js +1 -1
  77. package/list/lib/list-styles.css.js.map +1 -1
  78. package/list/lib/list.d.ts +1 -0
  79. package/list/lib/list.js +4 -1
  80. package/list/lib/list.js.map +1 -1
  81. package/list/lib/listitem/list-item.js +2 -0
  82. package/list/lib/listitem/list-item.js.map +1 -1
  83. package/menu/lib/_menu.scss +7 -10
  84. package/menu/lib/menu-styles.css.js +1 -1
  85. package/menu/lib/menu-styles.css.js.map +1 -1
  86. package/menusurface/lib/_md-comp-menu-surface.scss +6 -14
  87. package/menusurface/lib/_menu-surface.scss +8 -4
  88. package/menusurface/lib/menu-surface-styles.css.js +1 -1
  89. package/menusurface/lib/menu-surface-styles.css.js.map +1 -1
  90. package/menusurface/lib/menu-surface.d.ts +1 -0
  91. package/menusurface/lib/menu-surface.js +2 -0
  92. package/menusurface/lib/menu-surface.js.map +1 -1
  93. package/navigationdrawer/lib/_navigation-drawer-modal.scss +7 -22
  94. package/navigationdrawer/lib/_navigation-drawer.scss +15 -18
  95. package/navigationdrawer/lib/_shared.scss +2 -7
  96. package/navigationdrawer/lib/navigation-drawer-modal-styles.css.js +1 -1
  97. package/navigationdrawer/lib/navigation-drawer-modal-styles.css.js.map +1 -1
  98. package/navigationdrawer/lib/navigation-drawer-styles.css.js +1 -1
  99. package/navigationdrawer/lib/navigation-drawer-styles.css.js.map +1 -1
  100. package/navigationdrawer/lib/navigation-drawer.d.ts +1 -0
  101. package/navigationdrawer/lib/navigation-drawer.js +3 -2
  102. package/navigationdrawer/lib/navigation-drawer.js.map +1 -1
  103. package/package.json +8 -1
  104. package/radio/_radio.scss +6 -1
  105. package/radio/lib/_radio.scss +127 -91
  106. package/{elevationold/lib/elevation-overlay-styles.css.d.ts → radio/lib/forced-colors-styles.css.d.ts} +0 -0
  107. package/radio/lib/forced-colors-styles.css.js +9 -0
  108. package/radio/lib/forced-colors-styles.css.js.map +1 -0
  109. package/radio/lib/forced-colors-styles.scss +27 -0
  110. package/radio/lib/radio-styles.css.js +1 -1
  111. package/radio/lib/radio-styles.css.js.map +1 -1
  112. package/radio/lib/radio-styles.scss +1 -7
  113. package/radio/lib/radio.d.ts +6 -44
  114. package/radio/lib/radio.js +42 -144
  115. package/radio/lib/radio.js.map +1 -1
  116. package/radio/lib/single-selection-controller.d.ts +51 -138
  117. package/radio/lib/single-selection-controller.js +153 -249
  118. package/radio/lib/single-selection-controller.js.map +1 -1
  119. package/radio/radio.js +2 -1
  120. package/radio/radio.js.map +1 -1
  121. package/textfield/lib/_shared.scss +1 -0
  122. package/textfield/lib/filled-styles.css.js +1 -1
  123. package/textfield/lib/filled-styles.css.js.map +1 -1
  124. package/textfield/lib/shared-styles.css.js +1 -1
  125. package/textfield/lib/shared-styles.css.js.map +1 -1
  126. package/textfield/lib/text-field.js +3 -0
  127. package/textfield/lib/text-field.js.map +1 -1
  128. package/tokens/_index.scss +1 -1
  129. package/tokens/{v0_144 → v0_150}/_index.scss +0 -0
  130. package/tokens/{v0_144 → v0_150}/_md-comp-assist-chip.scss +1 -1
  131. package/tokens/{v0_144 → v0_150}/_md-comp-badge.scss +1 -1
  132. package/tokens/{v0_144 → v0_150}/_md-comp-banner.scss +1 -1
  133. package/tokens/{v0_144 → v0_150}/_md-comp-bottom-app-bar.scss +1 -1
  134. package/tokens/{v0_144 → v0_150}/_md-comp-carousel-item.scss +1 -1
  135. package/tokens/{v0_144 → v0_150}/_md-comp-checkbox.scss +1 -1
  136. package/tokens/{v0_144 → v0_150}/_md-comp-circular-progress-indicator.scss +1 -1
  137. package/tokens/{v0_144 → v0_150}/_md-comp-data-table.scss +1 -1
  138. package/tokens/{v0_144 → v0_150}/_md-comp-date-input-modal.scss +1 -1
  139. package/tokens/{v0_144 → v0_150}/_md-comp-date-picker-docked.scss +1 -1
  140. package/tokens/{v0_144 → v0_150}/_md-comp-date-picker-modal.scss +1 -1
  141. package/tokens/{v0_144 → v0_150}/_md-comp-dialog.scss +1 -1
  142. package/tokens/{v0_144 → v0_150}/_md-comp-divider.scss +1 -1
  143. package/tokens/{v0_144 → v0_150}/_md-comp-elevated-button.scss +1 -1
  144. package/tokens/{v0_144 → v0_150}/_md-comp-elevated-card.scss +1 -1
  145. package/tokens/{v0_144 → v0_150}/_md-comp-extended-fab-branded.scss +1 -1
  146. package/tokens/{v0_144 → v0_150}/_md-comp-extended-fab-primary.scss +1 -1
  147. package/tokens/{v0_144 → v0_150}/_md-comp-extended-fab-secondary.scss +1 -1
  148. package/tokens/{v0_144 → v0_150}/_md-comp-extended-fab-surface.scss +1 -1
  149. package/tokens/{v0_144 → v0_150}/_md-comp-extended-fab-tertiary.scss +1 -1
  150. package/tokens/{v0_144 → v0_150}/_md-comp-fab-branded-large.scss +1 -1
  151. package/tokens/{v0_144 → v0_150}/_md-comp-fab-branded.scss +1 -1
  152. package/tokens/{v0_144 → v0_150}/_md-comp-fab-primary-large.scss +1 -1
  153. package/tokens/{v0_144 → v0_150}/_md-comp-fab-primary-small.scss +1 -1
  154. package/tokens/{v0_144 → v0_150}/_md-comp-fab-primary.scss +1 -1
  155. package/tokens/{v0_144 → v0_150}/_md-comp-fab-secondary-large.scss +1 -1
  156. package/tokens/{v0_144 → v0_150}/_md-comp-fab-secondary-small.scss +1 -1
  157. package/tokens/{v0_144 → v0_150}/_md-comp-fab-secondary.scss +1 -1
  158. package/tokens/{v0_144 → v0_150}/_md-comp-fab-surface-large.scss +1 -1
  159. package/tokens/{v0_144 → v0_150}/_md-comp-fab-surface-small.scss +1 -1
  160. package/tokens/{v0_144 → v0_150}/_md-comp-fab-surface.scss +1 -1
  161. package/tokens/{v0_144 → v0_150}/_md-comp-fab-tertiary-large.scss +1 -1
  162. package/tokens/{v0_144 → v0_150}/_md-comp-fab-tertiary-small.scss +1 -1
  163. package/tokens/{v0_144 → v0_150}/_md-comp-fab-tertiary.scss +1 -1
  164. package/tokens/{v0_144 → v0_150}/_md-comp-filled-autocomplete.scss +1 -1
  165. package/tokens/{v0_144 → v0_150}/_md-comp-filled-button.scss +1 -1
  166. package/tokens/{v0_144 → v0_150}/_md-comp-filled-card.scss +1 -1
  167. package/tokens/{v0_144 → v0_150}/_md-comp-filled-icon-button.scss +1 -1
  168. package/tokens/{v0_144 → v0_150}/_md-comp-filled-menu-button.scss +1 -1
  169. package/tokens/{v0_144 → v0_150}/_md-comp-filled-select.scss +1 -1
  170. package/tokens/{v0_144 → v0_150}/_md-comp-filled-text-field.scss +2 -2
  171. package/tokens/{v0_144 → v0_150}/_md-comp-filled-tonal-button.scss +1 -1
  172. package/tokens/{v0_144 → v0_150}/_md-comp-filled-tonal-icon-button.scss +1 -1
  173. package/tokens/{v0_144 → v0_150}/_md-comp-filter-chip.scss +2 -1
  174. package/tokens/{v0_144 → v0_150}/_md-comp-full-screen-dialog.scss +1 -1
  175. package/tokens/{v0_144 → v0_150}/_md-comp-icon-button.scss +1 -1
  176. package/tokens/{v0_144 → v0_150}/_md-comp-input-chip.scss +1 -1
  177. package/tokens/{v0_144 → v0_150}/_md-comp-linear-progress-indicator.scss +1 -1
  178. package/tokens/{v0_144 → v0_150}/_md-comp-list.scss +1 -1
  179. package/tokens/{v0_144 → v0_150}/_md-comp-menu.scss +1 -1
  180. package/tokens/{v0_144 → v0_150}/_md-comp-navigation-bar.scss +1 -1
  181. package/tokens/{v0_144 → v0_150}/_md-comp-navigation-drawer.scss +1 -1
  182. package/tokens/{v0_144 → v0_150}/_md-comp-navigation-rail.scss +1 -1
  183. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-autocomplete.scss +1 -1
  184. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-button.scss +1 -1
  185. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-card.scss +5 -5
  186. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-icon-button.scss +1 -1
  187. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-menu-button.scss +1 -1
  188. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-segmented-button.scss +1 -1
  189. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-select.scss +1 -1
  190. package/tokens/{v0_144 → v0_150}/_md-comp-outlined-text-field.scss +1 -1
  191. package/tokens/{v0_144 → v0_150}/_md-comp-plain-tooltip.scss +2 -2
  192. package/tokens/{v0_144 → v0_150}/_md-comp-primary-navigation-tab.scss +1 -1
  193. package/tokens/{v0_144 → v0_150}/_md-comp-radio-button.scss +1 -1
  194. package/tokens/{v0_144 → v0_150}/_md-comp-rich-tooltip.scss +1 -1
  195. package/tokens/{v0_144 → v0_150}/_md-comp-scrim.scss +1 -1
  196. package/tokens/{v0_144 → v0_150}/_md-comp-search-bar.scss +1 -1
  197. package/tokens/{v0_144 → v0_150}/_md-comp-search-view.scss +1 -1
  198. package/tokens/{v0_144 → v0_150}/_md-comp-secondary-navigation-tab.scss +1 -1
  199. package/tokens/{v0_144 → v0_150}/_md-comp-sheet-bottom.scss +1 -1
  200. package/tokens/{v0_144 → v0_150}/_md-comp-sheet-floating.scss +1 -1
  201. package/tokens/{v0_144 → v0_150}/_md-comp-sheet-side.scss +1 -1
  202. package/tokens/{v0_144 → v0_150}/_md-comp-slider.scss +1 -1
  203. package/tokens/{v0_144 → v0_150}/_md-comp-snackbar.scss +25 -1
  204. package/tokens/{v0_144 → v0_150}/_md-comp-standard-menu-button.scss +1 -1
  205. package/tokens/{v0_144 → v0_150}/_md-comp-suggestion-chip.scss +6 -6
  206. package/tokens/{v0_144 → v0_150}/_md-comp-switch.scss +1 -1
  207. package/tokens/{v0_144 → v0_150}/_md-comp-text-button.scss +1 -1
  208. package/tokens/{v0_144 → v0_150}/_md-comp-time-input.scss +1 -1
  209. package/tokens/{v0_144 → v0_150}/_md-comp-time-picker.scss +2 -2
  210. package/tokens/{v0_144 → v0_150}/_md-comp-top-app-bar-large.scss +1 -1
  211. package/tokens/{v0_144 → v0_150}/_md-comp-top-app-bar-medium.scss +1 -1
  212. package/tokens/{v0_144 → v0_150}/_md-comp-top-app-bar-small-centered.scss +1 -1
  213. package/tokens/{v0_144 → v0_150}/_md-comp-top-app-bar-small.scss +1 -1
  214. package/tokens/{v0_144 → v0_150}/_md-ref-palette.scss +1 -1
  215. package/tokens/{v0_144 → v0_150}/_md-ref-typeface.scss +1 -1
  216. package/tokens/{v0_144 → v0_150}/_md-sys-color.scss +1 -1
  217. package/tokens/{v0_144 → v0_150}/_md-sys-elevation.scss +1 -1
  218. package/tokens/{v0_144 → v0_150}/_md-sys-motion.scss +1 -1
  219. package/tokens/{v0_144 → v0_150}/_md-sys-shape.scss +1 -1
  220. package/tokens/{v0_144 → v0_150}/_md-sys-state.scss +1 -1
  221. package/tokens/{v0_144 → v0_150}/_md-sys-typescale.scss +1 -1
  222. package/tokens/v0_150/index.test.css.d.ts +1 -0
  223. package/tokens/v0_150/index.test.css.js +9 -0
  224. package/tokens/v0_150/index.test.css.js.map +1 -0
  225. package/tokens/v0_150/index.test.scss +584 -0
  226. package/tokens/v0_150/lib.test.css.d.ts +1 -0
  227. package/tokens/v0_150/lib.test.css.js +9 -0
  228. package/tokens/v0_150/lib.test.css.js.map +1 -0
  229. package/tokens/v0_150/lib.test.scss +663 -0
  230. package/elevationold/lib/_elevation-overlay-theme.scss +0 -31
  231. package/elevationold/lib/_elevation-overlay.scss +0 -18
  232. package/elevationold/lib/_elevation-theme.scss +0 -74
  233. package/elevationold/lib/_surface.scss +0 -15
  234. package/elevationold/lib/elevation-overlay-styles.css.js +0 -9
  235. package/elevationold/lib/elevation-overlay-styles.css.js.map +0 -1
  236. package/elevationold/lib/elevation-overlay-styles.scss +0 -9
  237. package/radio/lib/_radio-theme.scss +0 -377
@@ -3,29 +3,27 @@
3
3
  * Copyright 2018 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ var _a;
6
7
  import { __decorate, __metadata } from "tslib";
7
- // Style preference for leading underscores.
8
- // tslint:disable:strip-private-property-underscore
9
8
  import '../../focus/focus-ring.js';
10
9
  import '../../ripple/ripple.js';
11
10
  import { html, LitElement, nothing } from 'lit';
12
11
  import { property, query, queryAsync, state } from 'lit/decorators.js';
13
- import { classMap } from 'lit/directives/class-map.js';
14
12
  import { when } from 'lit/directives/when.js';
15
- import { dispatchActivationClick, isActivationClick } from '../../controller/events.js';
13
+ import { dispatchActivationClick, isActivationClick, redispatchEvent } from '../../controller/events.js';
16
14
  import { FormController, getFormValue } from '../../controller/form-controller.js';
17
15
  import { ariaProperty } from '../../decorators/aria-property.js';
18
16
  import { pointerPress, shouldShowStrongFocus } from '../../focus/strong-focus.js';
19
17
  import { ripple } from '../../ripple/directive.js';
20
18
  import { SingleSelectionController } from './single-selection-controller.js';
19
+ const CHECKED = Symbol('checked');
21
20
  /**
22
21
  * @fires checked
23
- * @soyCompatible
24
22
  */
25
23
  export class Radio extends LitElement {
26
24
  constructor() {
27
25
  super();
28
- this._checked = false; // tslint:disable-line:enforce-name-casing
26
+ this[_a] = false;
29
27
  this.disabled = false;
30
28
  /**
31
29
  * The element value to use in form submission when checked.
@@ -35,18 +33,7 @@ export class Radio extends LitElement {
35
33
  * The HTML name to use in form submission.
36
34
  */
37
35
  this.name = '';
38
- /**
39
- * Touch target extends beyond visual boundary of a component by default.
40
- * Set to `true` to remove touch target added to the component.
41
- * @see https://material.io/design/usability/accessibility.html
42
- */
43
- this.reducedTouchTarget = false;
44
- /**
45
- * input's tabindex is updated based on checked status.
46
- * Tab navigation will be removed from unchecked radios.
47
- */
48
- this.formElementTabIndex = 0;
49
- this.focused = false;
36
+ this.selectionController = new SingleSelectionController(this);
50
37
  this.showFocusRing = false;
51
38
  this.showRipple = false;
52
39
  this.getRipple = () => {
@@ -57,6 +44,7 @@ export class Radio extends LitElement {
57
44
  return html `<md-ripple unbounded ?disabled=${this.disabled}></md-ripple>`;
58
45
  };
59
46
  this.addController(new FormController(this));
47
+ this.addController(this.selectionController);
60
48
  this.addEventListener('click', (event) => {
61
49
  if (!isActivationClick(event)) {
62
50
  return;
@@ -66,38 +54,16 @@ export class Radio extends LitElement {
66
54
  });
67
55
  }
68
56
  get checked() {
69
- return this._checked;
57
+ return this[CHECKED];
70
58
  }
71
- /**
72
- * We define our own getter/setter for `checked` because we need to track
73
- * changes to it synchronously.
74
- *
75
- * The order in which the `checked` property is set across radio buttons
76
- * within the same group is very important. However, we can't rely on
77
- * UpdatingElement's `updated` callback to observe these changes (which is
78
- * also what the `@observer` decorator uses), because it batches changes to
79
- * all properties.
80
- *
81
- * Consider:
82
- *
83
- * radio1.disabled = true;
84
- * radio2.checked = true;
85
- * radio1.checked = true;
86
- *
87
- * In this case we'd first see all changes for radio1, and then for radio2,
88
- * and we couldn't tell that radio1 was the most recently checked.
89
- */
90
- set checked(isChecked) {
91
- const oldValue = this._checked;
92
- if (isChecked === oldValue) {
59
+ set checked(checked) {
60
+ const wasChecked = this.checked;
61
+ if (wasChecked === checked) {
93
62
  return;
94
63
  }
95
- this._checked = isChecked;
96
- this.selectionController?.update(this);
97
- this.requestUpdate('checked', oldValue);
98
- // useful when unchecks self and wrapping element needs to synchronize
99
- // TODO(b/168543810): Remove triggering event on programmatic API call.
100
- this.dispatchEvent(new Event('checked', { bubbles: true, composed: true }));
64
+ this[CHECKED] = checked;
65
+ this.requestUpdate('checked', wasChecked);
66
+ this.selectionController.handleCheckedChange();
101
67
  }
102
68
  /**
103
69
  * The associated form element with which this element's value will submit.
@@ -105,110 +71,54 @@ export class Radio extends LitElement {
105
71
  get form() {
106
72
  return this.closest('form');
107
73
  }
108
- [getFormValue]() {
74
+ [(_a = CHECKED, getFormValue)]() {
109
75
  return this.checked ? this.value : null;
110
76
  }
111
77
  focus() {
112
78
  this.input?.focus();
113
79
  }
114
- connectedCallback() {
115
- super.connectedCallback();
116
- // Note that we must defer creating the selection controller until the
117
- // element has connected, because selection controllers are keyed by the
118
- // radio's shadow root. For example, if we're stamping in a lit map
119
- // or repeat, then we'll be constructed before we're added to a root node.
120
- //
121
- // Also note if we aren't using native shadow DOM, we still need a
122
- // SelectionController, because we should update checked status of other
123
- // radios in the group when selection changes. It also simplifies
124
- // implementation and testing to use one in all cases.
125
- //
126
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
127
- this.selectionController = SingleSelectionController.getController(this);
128
- this.selectionController.register(this);
129
- // Radios maybe checked before connected, update selection as soon it is
130
- // connected to DOM. Last checked radio button in the DOM will be selected.
131
- //
132
- // NOTE: If we update selection only after firstUpdate() we might mistakenly
133
- // update checked status before other radios are rendered.
134
- this.selectionController.update(this);
135
- }
136
- disconnectedCallback() {
137
- // The controller is initialized in connectedCallback, so if we are in
138
- // disconnectedCallback then it must be initialized.
139
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
140
- this.selectionController.unregister(this);
141
- this.selectionController = undefined;
142
- }
143
- updated(changedProperties) {
144
- if (changedProperties.has('checked') && this.input) {
145
- this.input.checked = this.checked;
146
- if (!this.checked) {
147
- // Remove focus ring when unchecked on other radio programmatically.
148
- // Blur on input since this determines the focus style.
149
- this.input.blur();
150
- }
151
- }
152
- }
153
- /**
154
- * @soyTemplate
155
- * @soyAttributes radioAttributes: input
156
- * @soyClasses radioClasses: .md3-radio
157
- */
158
80
  render() {
159
- /** @classMap */
160
- const classes = {
161
- 'md3-radio--touch': !this.reducedTouchTarget,
162
- 'md3-ripple-upgraded--background-focused': this.focused,
163
- 'md3-radio--disabled': this.disabled,
164
- };
165
81
  return html `
166
- <div class="md3-radio ${classMap(classes)}">
167
- ${this.renderFocusRing()}
168
- <input
169
- tabindex="${this.formElementTabIndex}"
170
- class="md3-radio__native-control"
171
- type="radio"
172
- name="${this.name}"
173
- aria-label="${this.ariaLabel || nothing}"
174
- .checked="${this.checked}"
175
- .value="${this.value}"
176
- ?disabled="${this.disabled}"
177
- @change="${this.handleChange}"
178
- @focus="${this.handleFocus}"
179
- @blur="${this.handleBlur}"
180
- @pointerdown=${this.handlePointerDown}
181
- ${ripple(this.getRipple)}
182
- >
183
- <div class="md3-radio__background">
184
- <div class="md3-radio__outer-circle"></div>
185
- <div class="md3-radio__inner-circle"></div>
186
- </div>
187
- <div class="md3-radio__ripple">
188
- ${when(this.showRipple, this.renderRipple)}
189
- </div>
190
- </div>`;
82
+ ${when(this.showRipple, this.renderRipple)}
83
+ ${this.renderFocusRing()}
84
+ <svg class="icon" viewBox="0 0 20 20">
85
+ <mask id="cutout">
86
+ <rect width="100%" height="100%" fill="white" />
87
+ <circle cx="10" cy="10" r="8" fill="black" />
88
+ </mask>
89
+ <circle class="outer circle" cx="10" cy="10" r="10" mask="url(#cutout)" />
90
+ <circle class="inner circle" cx="10" cy="10" r="5" />
91
+ </svg>
92
+ <input
93
+ type="radio"
94
+ name=${this.name}
95
+ aria-label=${this.ariaLabel || nothing}
96
+ .checked=${this.checked}
97
+ .value=${this.value}
98
+ ?disabled=${this.disabled}
99
+ @change=${this.handleChange}
100
+ @focus=${this.handleFocus}
101
+ @blur=${this.handleBlur}
102
+ @pointerdown=${this.handlePointerDown}
103
+ ${ripple(this.getRipple)}
104
+ >
105
+ `;
191
106
  }
192
107
  handleBlur() {
193
- this.focused = false;
194
108
  this.showFocusRing = false;
195
109
  }
196
110
  handleFocus() {
197
- this.focused = true;
198
111
  this.showFocusRing = shouldShowStrongFocus();
199
112
  }
200
- handleChange() {
113
+ handleChange(event) {
201
114
  if (this.disabled) {
202
115
  return;
203
116
  }
204
117
  // Per spec, the change event on a radio input always represents checked.
205
118
  this.checked = true;
206
- this.dispatchEvent(new Event('change', {
207
- bubbles: true,
208
- composed: true,
209
- }));
119
+ redispatchEvent(this, event);
210
120
  }
211
- handlePointerDown(event) {
121
+ handlePointerDown() {
212
122
  pointerPress();
213
123
  this.showFocusRing = shouldShowStrongFocus();
214
124
  }
@@ -224,7 +134,7 @@ __decorate([
224
134
  __metadata("design:paramtypes", [Boolean])
225
135
  ], Radio.prototype, "checked", null);
226
136
  __decorate([
227
- property({ type: Boolean }),
137
+ property({ type: Boolean, reflect: true }),
228
138
  __metadata("design:type", Object)
229
139
  ], Radio.prototype, "disabled", void 0);
230
140
  __decorate([
@@ -235,24 +145,12 @@ __decorate([
235
145
  property({ type: String, reflect: true }),
236
146
  __metadata("design:type", Object)
237
147
  ], Radio.prototype, "name", void 0);
238
- __decorate([
239
- property({ type: Boolean }),
240
- __metadata("design:type", Object)
241
- ], Radio.prototype, "reducedTouchTarget", void 0);
242
- __decorate([
243
- property({ type: Number }),
244
- __metadata("design:type", Object)
245
- ], Radio.prototype, "formElementTabIndex", void 0);
246
148
  __decorate([
247
149
  ariaProperty // tslint:disable-line:no-new-decorators
248
150
  ,
249
151
  property({ attribute: 'data-aria-label', noAccessor: true }),
250
152
  __metadata("design:type", String)
251
153
  ], Radio.prototype, "ariaLabel", void 0);
252
- __decorate([
253
- state(),
254
- __metadata("design:type", Object)
255
- ], Radio.prototype, "focused", void 0);
256
154
  __decorate([
257
155
  query('input'),
258
156
  __metadata("design:type", HTMLInputElement)
@@ -1 +1 @@
1
- {"version":3,"file":"radio.js","sourceRoot":"","sources":["radio.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Style preference for leading underscores.\n// tslint:disable:strip-private-property-underscore\n\nimport '../../focus/focus-ring.js';\nimport '../../ripple/ripple.js';\n\nimport {html, LitElement, nothing, PropertyValues, TemplateResult} from 'lit';\nimport {property, query, queryAsync, state} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {when} from 'lit/directives/when.js';\n\nimport {dispatchActivationClick, isActivationClick} from '../../controller/events.js';\nimport {FormController, getFormValue} from '../../controller/form-controller.js';\nimport {ariaProperty} from '../../decorators/aria-property.js';\nimport {pointerPress, shouldShowStrongFocus} from '../../focus/strong-focus.js';\nimport {ripple} from '../../ripple/directive.js';\nimport {MdRipple} from '../../ripple/ripple.js';\n\nimport {SingleSelectionController} from './single-selection-controller.js';\n\n/**\n * @fires checked\n * @soyCompatible\n */\nexport class Radio extends LitElement {\n static override shadowRootOptions:\n ShadowRootInit = {...LitElement.shadowRootOptions, delegatesFocus: true};\n\n static formAssociated = true;\n\n @property({type: Boolean, reflect: true})\n get checked(): boolean {\n return this._checked;\n }\n\n /**\n * We define our own getter/setter for `checked` because we need to track\n * changes to it synchronously.\n *\n * The order in which the `checked` property is set across radio buttons\n * within the same group is very important. However, we can't rely on\n * UpdatingElement's `updated` callback to observe these changes (which is\n * also what the `@observer` decorator uses), because it batches changes to\n * all properties.\n *\n * Consider:\n *\n * radio1.disabled = true;\n * radio2.checked = true;\n * radio1.checked = true;\n *\n * In this case we'd first see all changes for radio1, and then for radio2,\n * and we couldn't tell that radio1 was the most recently checked.\n */\n set checked(isChecked: boolean) {\n const oldValue = this._checked;\n if (isChecked === oldValue) {\n return;\n }\n this._checked = isChecked;\n this.selectionController?.update(this);\n\n this.requestUpdate('checked', oldValue);\n\n // useful when unchecks self and wrapping element needs to synchronize\n // TODO(b/168543810): Remove triggering event on programmatic API call.\n this.dispatchEvent(new Event('checked', {bubbles: true, composed: true}));\n }\n\n private _checked = false; // tslint:disable-line:enforce-name-casing\n\n @property({type: Boolean}) disabled = false;\n\n /**\n * The element value to use in form submission when checked.\n */\n @property({type: String}) value = 'on';\n\n /**\n * The HTML name to use in form submission.\n */\n @property({type: String, reflect: true}) name = '';\n\n /**\n * Touch target extends beyond visual boundary of a component by default.\n * Set to `true` to remove touch target added to the component.\n * @see https://material.io/design/usability/accessibility.html\n */\n @property({type: Boolean}) reducedTouchTarget = false;\n\n /**\n * input's tabindex is updated based on checked status.\n * Tab navigation will be removed from unchecked radios.\n */\n @property({type: Number}) formElementTabIndex = 0;\n\n @ariaProperty // tslint:disable-line:no-new-decorators\n @property({attribute: 'data-aria-label', noAccessor: true})\n override ariaLabel!: string;\n\n /**\n * The associated form element with which this element's value will submit.\n */\n get form() {\n return this.closest('form');\n }\n\n @state() private focused = false;\n @query('input') private readonly input!: HTMLInputElement|null;\n @queryAsync('md-ripple') private readonly ripple!: Promise<MdRipple|null>;\n private selectionController?: SingleSelectionController;\n @state() private showFocusRing = false;\n @state() private showRipple = false;\n\n constructor() {\n super();\n this.addController(new FormController(this));\n this.addEventListener('click', (event: Event) => {\n if (!isActivationClick(event)) {\n return;\n }\n this.focus();\n dispatchActivationClick(this.input!);\n });\n }\n\n [getFormValue]() {\n return this.checked ? this.value : null;\n }\n\n override focus() {\n this.input?.focus();\n }\n\n override connectedCallback() {\n super.connectedCallback();\n // Note that we must defer creating the selection controller until the\n // element has connected, because selection controllers are keyed by the\n // radio's shadow root. For example, if we're stamping in a lit map\n // or repeat, then we'll be constructed before we're added to a root node.\n //\n // Also note if we aren't using native shadow DOM, we still need a\n // SelectionController, because we should update checked status of other\n // radios in the group when selection changes. It also simplifies\n // implementation and testing to use one in all cases.\n //\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n this.selectionController = SingleSelectionController.getController(this);\n this.selectionController.register(this);\n\n // Radios maybe checked before connected, update selection as soon it is\n // connected to DOM. Last checked radio button in the DOM will be selected.\n //\n // NOTE: If we update selection only after firstUpdate() we might mistakenly\n // update checked status before other radios are rendered.\n this.selectionController.update(this);\n }\n\n override disconnectedCallback() {\n // The controller is initialized in connectedCallback, so if we are in\n // disconnectedCallback then it must be initialized.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.selectionController!.unregister(this);\n this.selectionController = undefined;\n }\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('checked') && this.input) {\n this.input.checked = this.checked;\n if (!this.checked) {\n // Remove focus ring when unchecked on other radio programmatically.\n // Blur on input since this determines the focus style.\n this.input.blur();\n }\n }\n }\n\n /**\n * @soyTemplate\n * @soyAttributes radioAttributes: input\n * @soyClasses radioClasses: .md3-radio\n */\n protected override render(): TemplateResult {\n /** @classMap */\n const classes = {\n 'md3-radio--touch': !this.reducedTouchTarget,\n 'md3-ripple-upgraded--background-focused': this.focused,\n 'md3-radio--disabled': this.disabled,\n };\n\n return html`\n <div class=\"md3-radio ${classMap(classes)}\">\n ${this.renderFocusRing()}\n <input\n tabindex=\"${this.formElementTabIndex}\"\n class=\"md3-radio__native-control\"\n type=\"radio\"\n name=\"${this.name}\"\n aria-label=\"${this.ariaLabel || nothing}\"\n .checked=\"${this.checked}\"\n .value=\"${this.value}\"\n ?disabled=\"${this.disabled}\"\n @change=\"${this.handleChange}\"\n @focus=\"${this.handleFocus}\"\n @blur=\"${this.handleBlur}\"\n @pointerdown=${this.handlePointerDown}\n ${ripple(this.getRipple)}\n >\n <div class=\"md3-radio__background\">\n <div class=\"md3-radio__outer-circle\"></div>\n <div class=\"md3-radio__inner-circle\"></div>\n </div>\n <div class=\"md3-radio__ripple\">\n ${when(this.showRipple, this.renderRipple)}\n </div>\n </div>`;\n }\n\n private handleBlur() {\n this.focused = false;\n this.showFocusRing = false;\n }\n\n private handleFocus() {\n this.focused = true;\n this.showFocusRing = shouldShowStrongFocus();\n }\n\n private handleChange() {\n if (this.disabled) {\n return;\n }\n\n // Per spec, the change event on a radio input always represents checked.\n this.checked = true;\n this.dispatchEvent(new Event('change', {\n bubbles: true,\n composed: true,\n }));\n }\n\n private handlePointerDown(event: PointerEvent) {\n pointerPress();\n this.showFocusRing = shouldShowStrongFocus();\n }\n\n private readonly getRipple = () => {\n this.showRipple = true;\n return this.ripple;\n };\n\n private readonly renderRipple = () => {\n return html`<md-ripple unbounded ?disabled=${this.disabled}></md-ripple>`;\n };\n\n private renderFocusRing(): TemplateResult {\n return html`<md-focus-ring .visible=${this.showFocusRing}></md-focus-ring>`;\n }\n}\n"]}
1
+ {"version":3,"file":"radio.js","sourceRoot":"","sources":["radio.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport '../../focus/focus-ring.js';\nimport '../../ripple/ripple.js';\n\nimport {html, LitElement, nothing, TemplateResult} from 'lit';\nimport {property, query, queryAsync, state} from 'lit/decorators.js';\nimport {when} from 'lit/directives/when.js';\n\nimport {dispatchActivationClick, isActivationClick, redispatchEvent} from '../../controller/events.js';\nimport {FormController, getFormValue} from '../../controller/form-controller.js';\nimport {ariaProperty} from '../../decorators/aria-property.js';\nimport {pointerPress, shouldShowStrongFocus} from '../../focus/strong-focus.js';\nimport {ripple} from '../../ripple/directive.js';\nimport {MdRipple} from '../../ripple/ripple.js';\n\nimport {SingleSelectionController} from './single-selection-controller.js';\n\nconst CHECKED = Symbol('checked');\n\n/**\n * @fires checked\n */\nexport class Radio extends LitElement {\n static override shadowRootOptions:\n ShadowRootInit = {...LitElement.shadowRootOptions, delegatesFocus: true};\n\n static formAssociated = true;\n\n @property({type: Boolean, reflect: true})\n get checked() {\n return this[CHECKED];\n }\n set checked(checked: boolean) {\n const wasChecked = this.checked;\n if (wasChecked === checked) {\n return;\n }\n\n this[CHECKED] = checked;\n this.requestUpdate('checked', wasChecked);\n this.selectionController.handleCheckedChange();\n }\n\n [CHECKED] = false;\n\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * The element value to use in form submission when checked.\n */\n @property({type: String}) value = 'on';\n\n /**\n * The HTML name to use in form submission.\n */\n @property({type: String, reflect: true}) name = '';\n\n @ariaProperty // tslint:disable-line:no-new-decorators\n @property({attribute: 'data-aria-label', noAccessor: true})\n override ariaLabel!: string;\n\n /**\n * The associated form element with which this element's value will submit.\n */\n get form() {\n return this.closest('form');\n }\n\n @query('input') private readonly input!: HTMLInputElement|null;\n @queryAsync('md-ripple') private readonly ripple!: Promise<MdRipple|null>;\n private readonly selectionController = new SingleSelectionController(this);\n @state() private showFocusRing = false;\n @state() private showRipple = false;\n\n constructor() {\n super();\n this.addController(new FormController(this));\n this.addController(this.selectionController);\n this.addEventListener('click', (event: Event) => {\n if (!isActivationClick(event)) {\n return;\n }\n this.focus();\n dispatchActivationClick(this.input!);\n });\n }\n\n [getFormValue]() {\n return this.checked ? this.value : null;\n }\n\n override focus() {\n this.input?.focus();\n }\n\n protected override render(): TemplateResult {\n return html`\n ${when(this.showRipple, this.renderRipple)}\n ${this.renderFocusRing()}\n <svg class=\"icon\" viewBox=\"0 0 20 20\">\n <mask id=\"cutout\">\n <rect width=\"100%\" height=\"100%\" fill=\"white\" />\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"black\" />\n </mask>\n <circle class=\"outer circle\" cx=\"10\" cy=\"10\" r=\"10\" mask=\"url(#cutout)\" />\n <circle class=\"inner circle\" cx=\"10\" cy=\"10\" r=\"5\" />\n </svg>\n <input\n type=\"radio\"\n name=${this.name}\n aria-label=${this.ariaLabel || nothing}\n .checked=${this.checked}\n .value=${this.value}\n ?disabled=${this.disabled}\n @change=${this.handleChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n @pointerdown=${this.handlePointerDown}\n ${ripple(this.getRipple)}\n >\n `;\n }\n\n private handleBlur() {\n this.showFocusRing = false;\n }\n\n private handleFocus() {\n this.showFocusRing = shouldShowStrongFocus();\n }\n\n private handleChange(event: Event) {\n if (this.disabled) {\n return;\n }\n\n // Per spec, the change event on a radio input always represents checked.\n this.checked = true;\n redispatchEvent(this, event);\n }\n\n private handlePointerDown() {\n pointerPress();\n this.showFocusRing = shouldShowStrongFocus();\n }\n\n private readonly getRipple = () => {\n this.showRipple = true;\n return this.ripple;\n };\n\n private readonly renderRipple = () => {\n return html`<md-ripple unbounded ?disabled=${this.disabled}></md-ripple>`;\n };\n\n private renderFocusRing(): TemplateResult {\n return html`<md-focus-ring .visible=${this.showFocusRing}></md-focus-ring>`;\n }\n}\n"]}
@@ -1,167 +1,80 @@
1
1
  /**
2
2
  * @license
3
- * Copyright 2020 Google LLC
3
+ * Copyright 2022 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import { ReactiveController } from 'lit';
6
7
  /**
7
- * Set of checkable elements with added metadata
8
+ * An element that supports single-selection with `SingleSelectionController`.
8
9
  */
9
- export declare class SingleSelectionSet {
10
- selected: CheckableElement | null;
11
- ordered: CheckableElement[] | null;
12
- readonly set: Set<CheckableElement>;
13
- }
14
- /**
15
- * Element that is checkable consumed by
16
- * `SingleSelectionController` and `SingleSelectionSet`
17
- */
18
- export declare type CheckableElement = HTMLElement & {
19
- name: string;
10
+ export interface SingleSelectionElement extends HTMLElement {
11
+ /**
12
+ * Whether or not the element is selected.
13
+ */
20
14
  checked: boolean;
21
- formElementTabIndex?: number;
22
- };
15
+ }
23
16
  /**
24
- * Controller that provides behavior similar to a native `<input type="radio">`
25
- * group.
26
- *
27
- * Behaviors:
17
+ * A `ReactiveController` that provides root node-scoped single selection for
18
+ * elements, similar to native `<input type="radio">` selection.
28
19
  *
29
- * - Selection via key navigation (currently LTR is supported)
30
- * - Deselection of other grouped, checkable controls upon selection
31
- * - Grouping of checkable elements by name
32
- * - Defaults grouping scope to host shadow root
33
- * - Document-wide scoping enabled
34
- * - Land focus only on checked element. Focuses leading element when none
35
- * checked.
20
+ * To use, elements should add the controller and call
21
+ * `selectionController.handleCheckedChange()` in a getter/setter. This must
22
+ * be synchronous to match native behavior.
36
23
  *
37
- * Intended Usage:
24
+ * @example
25
+ * const CHECKED = Symbol('checked');
38
26
  *
39
- * ```ts
40
- * class MyElement extends HTMLElement {
41
- * private selectionController: SingleSelectionController | null = null;
42
- * name = "";
43
- * global = false;
44
- *
45
- * private _checked = false;
27
+ * class MyToggle extends LitElement {
28
+ * get checked() { return this[CHECKED]; }
46
29
  * set checked(checked: boolean) {
47
- * const oldVal = this._checked;
48
- * if (checked === oldVal) return;
49
- *
50
- * this._checked = checked;
51
- *
52
- * if (this.selectionController) {
53
- * this.selectionController.update(this)
30
+ * const oldValue = this.checked;
31
+ * if (oldValue === checked) {
32
+ * return;
54
33
  * }
55
- * }
56
34
  *
57
- * get checked() {
58
- * return this._checked;
35
+ * this[CHECKED] = checked;
36
+ * this.selectionController.handleCheckedChange();
37
+ * this.requestUpdate('checked', oldValue);
59
38
  * }
60
39
  *
61
- * connectedCallback() {
62
- * this.selectionController = SelectionController.getController(this);
63
- * this.selectionController.register(this);
64
- * this.selectionController.update(this);
65
- * }
40
+ * [CHECKED] = false;
41
+ *
42
+ * private selectionController = new SingleSelectionController(this);
66
43
  *
67
- * disconnectedCallback() {
68
- * this.selectionController!.unregister(this);
69
- * this.selectionController = null;
44
+ * constructor() {
45
+ * super();
46
+ * this.addController(this.selectionController);
70
47
  * }
71
48
  * }
72
- * ```
73
49
  */
74
- export declare class SingleSelectionController {
75
- private readonly sets;
76
- private focusedSet;
77
- private mouseIsDown;
78
- /**
79
- * Get a controller for the given element. If no controller exists, one will
80
- * be created. Defaults to getting the controller scoped to the element's root
81
- * node shadow root unless `element.global` is true. Then, it will get a
82
- * `window.document`-scoped controller.
83
- *
84
- * @param element Element from which to get / create a SelectionController. If
85
- * `element.global` is true, it gets a selection controller scoped to
86
- * `window.document`.
87
- */
88
- static getController(element: HTMLElement | HTMLElement & {
89
- global: boolean;
90
- }): SingleSelectionController;
91
- constructor(element: Node);
92
- protected keyDownHandler(e: KeyboardEvent): void;
93
- protected mousedownHandler(): void;
94
- protected mouseupHandler(): void;
95
- /**
96
- * Whether or not the controller controls the given element.
97
- *
98
- * @param element element to check
99
- */
100
- has(element: CheckableElement): boolean;
101
- /**
102
- * Selects and returns the controlled element previous to the given element in
103
- * document position order. See
104
- * [Node.compareDocumentPosition](https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition).
105
- *
106
- * @param element element relative from which preceding element is fetched
107
- */
108
- selectPrevious(element: CheckableElement): CheckableElement;
109
- /**
110
- * Selects and returns the controlled element next to the given element in
111
- * document position order. See
112
- * [Node.compareDocumentPosition](https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition).
113
- *
114
- * @param element element relative from which following element is fetched
115
- */
116
- selectNext(element: CheckableElement): CheckableElement;
117
- select(element: CheckableElement): void;
118
- /**
119
- * Focuses the selected element in the given element's selection set. User's
120
- * mouse selection will override this focus.
121
- *
122
- * @param element Element from which selection set is derived and subsequently
123
- * focused.
124
- * @deprecated update() method now handles focus management by setting
125
- * appropriate tabindex to form element.
126
- */
127
- focus(element: CheckableElement): void;
128
- /**
129
- * @return Returns true if atleast one radio is selected in the radio group.
130
- */
131
- isAnySelected(element: CheckableElement): boolean;
132
- /**
133
- * Returns the elements in the given element's selection set in document
134
- * position order.
135
- * [Node.compareDocumentPosition](https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition).
136
- *
137
- * @param element Element from which selection set is derived and subsequently
138
- * ordered.
139
- */
140
- getOrdered(element: CheckableElement): CheckableElement[];
50
+ export declare class SingleSelectionController implements ReactiveController {
51
+ private readonly host;
52
+ private focused;
53
+ private root;
54
+ constructor(host: SingleSelectionElement);
55
+ hostConnected(): void;
56
+ hostDisconnected(): void;
141
57
  /**
142
- * Gets the selection set of the given name and creates one if it does not yet
143
- * exist.
144
- *
145
- * @param name Name of set
58
+ * Should be called whenever the host's `checked` property changes
59
+ * synchronously.
146
60
  */
147
- getSet(name: string): SingleSelectionSet;
61
+ handleCheckedChange(): void;
62
+ private readonly handleFocusIn;
63
+ private readonly handleFocusOut;
64
+ private uncheckSiblings;
148
65
  /**
149
- * Register the element in the selection controller.
150
- *
151
- * @param element Element to register. Registers in set of `element.name`.
66
+ * Updates the `tabindex` of the host and its siblings.
152
67
  */
153
- register(element: CheckableElement): void;
68
+ private updateTabIndices;
154
69
  /**
155
- * Unregister the element from selection controller.
156
- *
157
- * @param element Element to register. Registers in set of `element.name`.
70
+ * Retrieves all siblings in the host element's root with the same `name`
71
+ * attribute.
158
72
  */
159
- unregister(element: CheckableElement): void;
73
+ private getNamedSiblings;
160
74
  /**
161
- * Unselects other elements in element's set if element is checked. Noop
162
- * otherwise.
163
- *
164
- * @param element Element from which to calculate selection controller update.
75
+ * Handles arrow key events from the host. Using the arrow keys will
76
+ * select and check the next or previous sibling with the host's
77
+ * `name` attribute.
165
78
  */
166
- update(element: CheckableElement): void;
79
+ private readonly handleKeyDown;
167
80
  }