11import type { ComponentInterface , EventEmitter } from '@stencil/core' ;
22import { Component , Element , Event , Host , Method , Prop , State , Watch , h , forceUpdate } from '@stencil/core' ;
3- import { win } from '@utils/browser' ;
4- import type { LegacyFormController } from '@utils/forms' ;
5- import { createLegacyFormController } from '@utils/forms' ;
6- import { findItemLabel , focusElement , getAriaLabel , renderHiddenInput , inheritAttributes , raf } from '@utils/helpers' ;
3+ import type { LegacyFormController , NotchController } from '@utils/forms' ;
4+ import { createLegacyFormController , createNotchController } from '@utils/forms' ;
5+ import { findItemLabel , focusElement , getAriaLabel , renderHiddenInput , inheritAttributes } from '@utils/helpers' ;
76import type { Attributes } from '@utils/helpers' ;
87import { printIonWarning } from '@utils/logging' ;
98import { actionSheetController , alertController , popoverController } from '@utils/overlays' ;
@@ -58,7 +57,8 @@ export class Select implements ComponentInterface {
5857 private inheritedAttributes : Attributes = { } ;
5958 private nativeWrapperEl : HTMLElement | undefined ;
6059 private notchSpacerEl : HTMLElement | undefined ;
61- private notchVisibilityIO : IntersectionObserver | undefined ;
60+
61+ private notchController ?: NotchController ;
6262
6363 // This flag ensures we log the deprecation warning at most once.
6464 private hasLoggedDeprecationWarning = false ;
@@ -245,6 +245,11 @@ export class Select implements ComponentInterface {
245245 const { el } = this ;
246246
247247 this . legacyFormController = createLegacyFormController ( el ) ;
248+ this . notchController = createNotchController (
249+ el ,
250+ ( ) => this . notchSpacerEl ,
251+ ( ) => this . labelSlot
252+ ) ;
248253
249254 this . updateOverlayOptions ( ) ;
250255 this . emitStyle ( ) ;
@@ -267,6 +272,11 @@ export class Select implements ComponentInterface {
267272 this . mutationO . disconnect ( ) ;
268273 this . mutationO = undefined ;
269274 }
275+
276+ if ( this . notchController ) {
277+ this . notchController . destroy ( ) ;
278+ this . notchController = undefined ;
279+ }
270280 }
271281
272282 /**
@@ -746,17 +756,7 @@ export class Select implements ComponentInterface {
746756 }
747757
748758 componentDidRender ( ) {
749- if ( this . needsExplicitNotchWidth ( ) ) {
750- /**
751- * Run this the frame after
752- * the browser has re-painted the select.
753- * Otherwise, the label element may have a width
754- * of 0 and the IntersectionObserver will be used.
755- */
756- raf ( ( ) => {
757- this . setNotchWidth ( ) ;
758- } ) ;
759- }
759+ this . notchController ?. calculateNotchWidth ( ) ;
760760 }
761761
762762 /**
@@ -777,120 +777,6 @@ export class Select implements ComponentInterface {
777777 return this . label !== undefined || this . labelSlot !== null ;
778778 }
779779
780- private needsExplicitNotchWidth ( ) {
781- if (
782- /**
783- * If the notch is not being used
784- * then we do not need to set the notch width.
785- */
786- this . notchSpacerEl === undefined ||
787- /**
788- * If either the label property is being
789- * used or the label slot is not defined,
790- * then we do not need to estimate the notch width.
791- */
792- this . label !== undefined ||
793- this . labelSlot === null
794- ) {
795- return false ;
796- }
797-
798- return true ;
799- }
800-
801- /**
802- * When using a label prop we can render
803- * the label value inside of the notch and
804- * let the browser calculate the size of the notch.
805- * However, we cannot render the label slot in multiple
806- * places so we need to manually calculate the notch dimension
807- * based on the size of the slotted content.
808- *
809- * This function should only be used to set the notch width
810- * on slotted label content. The notch width for label prop
811- * content is automatically calculated based on the
812- * intrinsic size of the label text.
813- */
814- private setNotchWidth ( ) {
815- const { el, notchSpacerEl } = this ;
816-
817- if ( notchSpacerEl === undefined ) {
818- return ;
819- }
820-
821- if ( ! this . needsExplicitNotchWidth ( ) ) {
822- notchSpacerEl . style . removeProperty ( 'width' ) ;
823- return ;
824- }
825-
826- const width = this . labelSlot ! . scrollWidth ;
827- if (
828- /**
829- * If the computed width of the label is 0
830- * and notchSpacerEl's offsetParent is null
831- * then that means the element is hidden.
832- * As a result, we need to wait for the element
833- * to become visible before setting the notch width.
834- *
835- * We do not check el.offsetParent because
836- * that can be null if ion-select has
837- * position: fixed applied to it.
838- * notchSpacerEl does not have position: fixed.
839- */
840- width === 0 &&
841- notchSpacerEl . offsetParent === null &&
842- win !== undefined &&
843- 'IntersectionObserver' in win
844- ) {
845- /**
846- * If there is an IO already attached
847- * then that will update the notch
848- * once the element becomes visible.
849- * As a result, there is no need to create
850- * another one.
851- */
852- if ( this . notchVisibilityIO !== undefined ) {
853- return ;
854- }
855-
856- const io = ( this . notchVisibilityIO = new IntersectionObserver (
857- ( ev ) => {
858- /**
859- * If the element is visible then we
860- * can try setting the notch width again.
861- */
862- if ( ev [ 0 ] . intersectionRatio === 1 ) {
863- this . setNotchWidth ( ) ;
864- io . disconnect ( ) ;
865- this . notchVisibilityIO = undefined ;
866- }
867- } ,
868- /**
869- * Set the root to be the select
870- * This causes the IO callback
871- * to be fired in WebKit as soon as the element
872- * is visible. If we used the default root value
873- * then WebKit would only fire the IO callback
874- * after any animations (such as a modal transition)
875- * finished, and there would potentially be a flicker.
876- */
877- { threshold : 0.01 , root : el }
878- ) ) ;
879-
880- io . observe ( notchSpacerEl ) ;
881- return ;
882- }
883-
884- /**
885- * If the element is visible then we can set the notch width.
886- * The notch is only visible when the label is scaled,
887- * which is why we multiply the width by 0.75 as this is
888- * the same amount the label element is scaled by in the
889- * select CSS (See $select-floating-label-scale in select.vars.scss).
890- */
891- notchSpacerEl . style . setProperty ( 'width' , `${ width * 0.75 } px` ) ;
892- }
893-
894780 /**
895781 * Renders the border container
896782 * when fill="outline".
0 commit comments