77import '../../focus/focus-ring.js' ;
88import '../../ripple/ripple.js' ;
99
10- import { html , isServer , LitElement , nothing , TemplateResult } from 'lit' ;
10+ import { html , isServer , LitElement , nothing , PropertyValues , TemplateResult } from 'lit' ;
1111import { property , query , queryAsync , state } from 'lit/decorators.js' ;
1212import { ClassInfo , classMap } from 'lit/directives/class-map.js' ;
1313import { when } from 'lit/directives/when.js' ;
1414
1515import { requestUpdateOnAriaChange } from '../../aria/delegate.js' ;
1616import { dispatchActivationClick , isActivationClick } from '../../controller/events.js' ;
17- import { FormController , getFormValue } from '../../controller/form-controller.js' ;
1817import { ripple } from '../../ripple/directive.js' ;
1918import { MdRipple } from '../../ripple/ripple.js' ;
2019
@@ -68,30 +67,40 @@ export class Switch extends LitElement {
6867 @query ( 'button' ) private readonly button ! : HTMLButtonElement | null ;
6968
7069 /**
71- * The associated form element with which this element's value will submit.
70+ * The value associated with this switch on form submission. `null` is
71+ * submitted when `selected` is `false`.
7272 */
73- get form ( ) {
74- return this . closest ( 'form' ) ;
75- }
73+ @property ( ) value = 'on' ;
7674
7775 /**
7876 * The HTML name to use in form submission.
7977 */
80- @property ( { reflect : true } ) name = '' ;
78+ get name ( ) {
79+ return this . getAttribute ( 'name' ) ?? '' ;
80+ }
81+ set name ( name : string ) {
82+ this . setAttribute ( 'name' , name ) ;
83+ }
8184
8285 /**
83- * The value associated with this switch on form submission. `null` is
84- * submitted when `selected` is `false`.
86+ * The associated form element with which this element's value will submit.
8587 */
86- @property ( ) value = 'on' ;
88+ get form ( ) {
89+ return this . internals . form ;
90+ }
8791
88- [ getFormValue ] ( ) {
89- return this . selected ? this . value : null ;
92+ /**
93+ * The labels this element is associated with.
94+ */
95+ get labels ( ) {
96+ return this . internals . labels ;
9097 }
9198
99+ private readonly internals =
100+ ( this as HTMLElement /* needed for closure */ ) . attachInternals ( ) ;
101+
92102 constructor ( ) {
93103 super ( ) ;
94- this . addController ( new FormController ( this ) ) ;
95104 if ( ! isServer ) {
96105 this . addEventListener ( 'click' , ( event : MouseEvent ) => {
97106 if ( ! isActivationClick ( event ) ) {
@@ -106,6 +115,12 @@ export class Switch extends LitElement {
106115 }
107116 }
108117
118+ protected override update ( changed : PropertyValues < Switch > ) {
119+ const state = String ( this . selected ) ;
120+ this . internals . setFormValue ( this . selected ? this . value : null , state ) ;
121+ super . update ( changed ) ;
122+ }
123+
109124 protected override render ( ) : TemplateResult {
110125 // NOTE: buttons must use only [phrasing
111126 // content](https://html.spec.whatwg.org/multipage/dom.html#phrasing-content)
@@ -218,4 +233,16 @@ export class Switch extends LitElement {
218233 // Additionally, native change event is not an InputEvent.
219234 this . dispatchEvent ( new Event ( 'change' , { bubbles : true } ) ) ;
220235 }
236+
237+ /** @private */
238+ formResetCallback ( ) {
239+ // The selected property does not reflect, so the original attribute set by
240+ // the user is used to determine the default value.
241+ this . selected = this . hasAttribute ( 'selected' ) ;
242+ }
243+
244+ /** @private */
245+ formStateRestoreCallback ( state : string ) {
246+ this . selected = state === 'true' ;
247+ }
221248}
0 commit comments