Repository: ionic-team/ionic-framework
File: core/src/components/modal/modal.tsx (TypeScript)

Code before:
          [`modal-sheet`]: isSheetModal,
          'overlay-hidden': true,
          ...getClassMap(this.cssClass),
        }}
        id={modalId}
        onIonBackdropTap={this.onBackdropTap}
        onIonModalDidPresent={this.onLifecycle}
        onIonModalWillPresent={this.onLifecycle}
        onIonModalWillDismiss={this.onLifecycle}
        onIonModalDidDismiss={this.onLifecycle}
      >
        <ion-backdrop
          ref={(el) => (this.backdropEl = el)}
          visible={this.showBackdrop}
          tappable={this.backdropDismiss}
          part="backdrop"
        />

        {mode === 'ios' && <div class="modal-shadow"></div>}

        <div role="dialog" class="modal-wrapper ion-overlay-wrapper" part="content" ref={(el) => (this.wrapperEl = el)}>
          {showHandle && (
            <button
              class={{
                'modal-handle': true,
                'modal-handle--clickable': isHandleCycle,
              }}
              // Prevents the handle receiving focus when it is not clickable
              tabIndex={!isHandleCycle ? -1 : 0}
              aria-label={isHandleCycle ? 'Activate to adjust the size of the dialog overlaying the screen' : null}
              aria-controls={isHandleCycle ? modalId : null}
              onClick={this.onHandleClick}
              part="handle"
            ></button>
          )}
          <slot></slot>
        </div>
      </Host>
    );
  }
}

const LIFECYCLE_MAP: any = {
  ionModalDidPresent: 'ionViewDidEnter',
  ionModalWillPresent: 'ionViewWillEnter',
  ionModalWillDismiss: 'ionViewWillLeave',
  ionModalDidDismiss: 'ionViewDidLeave',
};

let modalIds = 0;


Review comment (suggestion):
Shouldn't the handle always be clickable? Users can double tap here to drag and adjust the size of the sheet manually:

https://user-images.githubusercontent.com/2721089/176693672-56bc2053-2b86-41f8-bc11-90629233190e.mp4

I know you can drag the entire header, but the handle was added as a cue for how to expand/collapse the sheet. Even if the handle cycle is 'none' you should still be able to click and drag on it.

Code after:
    const isCardModal = presentingElement !== undefined && mode === 'ios';
    const isHandleCycle = handleBehavior === 'cycle';

    return (
      <Host
        no-router
        aria-modal="true"
        tabindex="-1"
        {...(htmlAttributes as any)}
        style={{
          zIndex: `${20000 + this.overlayIndex}`,
        }}
        class={{
          [mode]: true,
          ['modal-default']: !isCardModal && !isSheetModal,
          [`modal-card`]: isCardModal,
          [`modal-sheet`]: isSheetModal,
          'overlay-hidden': true,
          ...getClassMap(this.cssClass),
        }}
        id={modalId}
        onIonBackdropTap={this.onBackdropTap}
        onIonModalDidPresent={this.onLifecycle}
        onIonModalWillPresent={this.onLifecycle}
        onIonModalWillDismiss={this.onLifecycle}
        onIonModalDidDismiss={this.onLifecycle}
      >
        <ion-backdrop
          ref={(el) => (this.backdropEl = el)}
          visible={this.showBackdrop}
          tappable={this.backdropDismiss}
          part="backdrop"
        />

        {mode === 'ios' && <div class="modal-shadow"></div>}

        <div role="dialog" class="modal-wrapper ion-overlay-wrapper" part="content" ref={(el) => (this.wrapperEl = el)}>
          {showHandle && (
            <button
              class="modal-handle"
              // Prevents the handle from receiving keyboard focus when it does not cycle
              tabIndex={!isHandleCycle ? -1 : 0}
              aria-label="Activate to adjust the size of the dialog overlaying the screen"
              onClick={isHandleCycle ? this.onHandleClick : undefined}
              part="handle"
            ></button>
          )}
          <slot></slot>
        </div>
      </Host>
    );