mirror of
				https://github.com/ionic-team/ionic-framework.git
				synced 2025-11-04 21:30:00 +08:00 
			
		
		
		
	refactor(checkbox): use promise
This commit is contained in:
		@ -1,5 +1,6 @@
 | 
				
			|||||||
import type { ComponentInterface, EventEmitter } from '@stencil/core';
 | 
					import type { ComponentInterface, EventEmitter } from '@stencil/core';
 | 
				
			||||||
import { Component, Element, Event, Host, Method, Prop, State, h, forceUpdate } from '@stencil/core';
 | 
					import { Component, Element, Event, Host, Method, Prop, State, h, forceUpdate, Build } from '@stencil/core';
 | 
				
			||||||
 | 
					import { checkInvalidState } from '@utils/forms';
 | 
				
			||||||
import type { Attributes } from '@utils/helpers';
 | 
					import type { Attributes } from '@utils/helpers';
 | 
				
			||||||
import { inheritAriaAttributes, renderHiddenInput } from '@utils/helpers';
 | 
					import { inheritAriaAttributes, renderHiddenInput } from '@utils/helpers';
 | 
				
			||||||
import { createColorClasses, hostContext } from '@utils/theme';
 | 
					import { createColorClasses, hostContext } from '@utils/theme';
 | 
				
			||||||
@ -35,6 +36,7 @@ export class Checkbox implements ComponentInterface {
 | 
				
			|||||||
  private helperTextId = `${this.inputId}-helper-text`;
 | 
					  private helperTextId = `${this.inputId}-helper-text`;
 | 
				
			||||||
  private errorTextId = `${this.inputId}-error-text`;
 | 
					  private errorTextId = `${this.inputId}-error-text`;
 | 
				
			||||||
  private inheritedAttributes: Attributes = {};
 | 
					  private inheritedAttributes: Attributes = {};
 | 
				
			||||||
 | 
					  private validationObserver?: MutationObserver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Element() el!: HTMLIonCheckboxElement;
 | 
					  @Element() el!: HTMLIonCheckboxElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -125,6 +127,8 @@ export class Checkbox implements ComponentInterface {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  @State() isInvalid = false;
 | 
					  @State() isInvalid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @State() private hintTextID?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Emitted when the checked property has changed as a result of a user action such as a click.
 | 
					   * Emitted when the checked property has changed as a result of a user action such as a click.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
@ -143,7 +147,45 @@ export class Checkbox implements ComponentInterface {
 | 
				
			|||||||
  @Event() ionBlur!: EventEmitter<void>;
 | 
					  @Event() ionBlur!: EventEmitter<void>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  connectedCallback() {
 | 
					  connectedCallback() {
 | 
				
			||||||
    // Always set initial state.
 | 
					    const { el } = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Watch for class changes to update validation state.
 | 
				
			||||||
 | 
					    if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
 | 
				
			||||||
 | 
					      this.validationObserver = new MutationObserver(() => {
 | 
				
			||||||
 | 
					        const newIsInvalid = checkInvalidState(el);
 | 
				
			||||||
 | 
					        if (this.isInvalid !== newIsInvalid) {
 | 
				
			||||||
 | 
					          this.isInvalid = newIsInvalid;
 | 
				
			||||||
 | 
					          /**
 | 
				
			||||||
 | 
					           * Screen readers tend to announce changes
 | 
				
			||||||
 | 
					           * to `aria-describedby` when the attribute
 | 
				
			||||||
 | 
					           * is changed during a blur event for a
 | 
				
			||||||
 | 
					           * native form control.
 | 
				
			||||||
 | 
					           * However, the announcement can be spotty
 | 
				
			||||||
 | 
					           * when using a non-native form control
 | 
				
			||||||
 | 
					           * and `forceUpdate()`.
 | 
				
			||||||
 | 
					           * This is due to `forceUpdate()` internally
 | 
				
			||||||
 | 
					           * rescheduling the DOM update to a lower
 | 
				
			||||||
 | 
					           * priority queue regardless if it's called
 | 
				
			||||||
 | 
					           * inside a Promise or not, thus causing
 | 
				
			||||||
 | 
					           * the screen reader to potentially miss the
 | 
				
			||||||
 | 
					           * change.
 | 
				
			||||||
 | 
					           * By using a State variable inside a Promise,
 | 
				
			||||||
 | 
					           * it guarantees a re-render immediately at
 | 
				
			||||||
 | 
					           * a higher priority.
 | 
				
			||||||
 | 
					           */
 | 
				
			||||||
 | 
					          Promise.resolve().then(() => {
 | 
				
			||||||
 | 
					            this.hintTextID = this.getHintTextID();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.validationObserver.observe(el, {
 | 
				
			||||||
 | 
					        attributes: true,
 | 
				
			||||||
 | 
					        attributeFilter: ['class'],
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Always set initial state
 | 
				
			||||||
    this.isInvalid = this.checkInvalidState();
 | 
					    this.isInvalid = this.checkInvalidState();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -153,6 +195,14 @@ export class Checkbox implements ComponentInterface {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  disconnectedCallback() {
 | 
				
			||||||
 | 
					    // Clean up validation observer to prevent memory leaks.
 | 
				
			||||||
 | 
					    if (this.validationObserver) {
 | 
				
			||||||
 | 
					      this.validationObserver.disconnect();
 | 
				
			||||||
 | 
					      this.validationObserver = undefined;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** @internal */
 | 
					  /** @internal */
 | 
				
			||||||
  @Method()
 | 
					  @Method()
 | 
				
			||||||
  async setFocus() {
 | 
					  async setFocus() {
 | 
				
			||||||
@ -301,7 +351,7 @@ export class Checkbox implements ComponentInterface {
 | 
				
			|||||||
      <Host
 | 
					      <Host
 | 
				
			||||||
        role="checkbox"
 | 
					        role="checkbox"
 | 
				
			||||||
        aria-checked={indeterminate ? 'mixed' : `${checked}`}
 | 
					        aria-checked={indeterminate ? 'mixed' : `${checked}`}
 | 
				
			||||||
        aria-describedby={this.getHintTextID()}
 | 
					        aria-describedby={this.hintTextID}
 | 
				
			||||||
        aria-invalid={this.isInvalid ? 'true' : undefined}
 | 
					        aria-invalid={this.isInvalid ? 'true' : undefined}
 | 
				
			||||||
        aria-labelledby={hasLabelContent ? this.inputLabelId : null}
 | 
					        aria-labelledby={hasLabelContent ? this.inputLabelId : null}
 | 
				
			||||||
        aria-label={inheritedAttributes['aria-label'] || null}
 | 
					        aria-label={inheritedAttributes['aria-label'] || null}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
type FormElement = HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSelectElement;
 | 
					type FormElement = HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSelectElement | HTMLIonCheckboxElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Checks if the form element is in an invalid state based on
 | 
					 * Checks if the form element is in an invalid state based on
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user