1
1
import type { ComponentInterface , EventEmitter } from '@stencil/core' ;
2
2
import { 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' ;
7
6
import type { Attributes } from '@utils/helpers' ;
8
7
import { printIonWarning } from '@utils/logging' ;
9
8
import { actionSheetController , alertController , popoverController } from '@utils/overlays' ;
@@ -58,7 +57,8 @@ export class Select implements ComponentInterface {
58
57
private inheritedAttributes : Attributes = { } ;
59
58
private nativeWrapperEl : HTMLElement | undefined ;
60
59
private notchSpacerEl : HTMLElement | undefined ;
61
- private notchVisibilityIO : IntersectionObserver | undefined ;
60
+
61
+ private notchController ?: NotchController ;
62
62
63
63
// This flag ensures we log the deprecation warning at most once.
64
64
private hasLoggedDeprecationWarning = false ;
@@ -245,6 +245,11 @@ export class Select implements ComponentInterface {
245
245
const { el } = this ;
246
246
247
247
this . legacyFormController = createLegacyFormController ( el ) ;
248
+ this . notchController = createNotchController (
249
+ el ,
250
+ ( ) => this . notchSpacerEl ,
251
+ ( ) => this . labelSlot
252
+ ) ;
248
253
249
254
this . updateOverlayOptions ( ) ;
250
255
this . emitStyle ( ) ;
@@ -267,6 +272,11 @@ export class Select implements ComponentInterface {
267
272
this . mutationO . disconnect ( ) ;
268
273
this . mutationO = undefined ;
269
274
}
275
+
276
+ if ( this . notchController ) {
277
+ this . notchController . destroy ( ) ;
278
+ this . notchController = undefined ;
279
+ }
270
280
}
271
281
272
282
/**
@@ -746,17 +756,7 @@ export class Select implements ComponentInterface {
746
756
}
747
757
748
758
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 ( ) ;
760
760
}
761
761
762
762
/**
@@ -777,120 +777,6 @@ export class Select implements ComponentInterface {
777
777
return this . label !== undefined || this . labelSlot !== null ;
778
778
}
779
779
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
-
894
780
/**
895
781
* Renders the border container
896
782
* when fill="outline".
0 commit comments