@react-aria/overlays 3.19.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"mappings":";;;;;AEoBA,kCAAmC,SAAQ,aAAa;IACtD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,SAAS,EAAE,UAAU,OAAO,CAAC,CAAC;IAC9B;;OAEG;IACH,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;IACE,+CAA+C;IAC/C,YAAY,EAAE,aAAa,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,EAAE,aAAa,CAAC;IAC1B,oEAAoE;IACpE,SAAS,EAAE,aAAa,CAAC;IACzB,2CAA2C;IAC3C,cAAc,IAAI,IAAI,CAAA;CACvB;AAKD;;;GAGG;AACH,mCAAmC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAmJzE;ACnND;IACE,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC7D;AAED;IACE,uDAAuD;IACvD,YAAY,EAAE,aAAa,CAAC;IAC5B,sDAAsD;IACtD,aAAa,EAAE,aAAa,CAAA;CAC7B;AAID;;;;GAIG;AACH,2BAA2B,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,UAAU,OAAO,CAAC,GAAG,WAAW,CAoGxF;AC/ID;IACE,qDAAqD;IACrD,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAA;CACtD;AAED;IACE,qCAAqC;IACrC,YAAY,EAAE,eAAe,CAAC;IAE9B,+CAA+C;IAC/C,YAAY,EAAE,QAAQ,CAAA;CACvB;AAED;;;GAGG;AACH,kCAAkC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,CAAC,EAAE,UAAU,OAAO,CAAC,GAAG,kBAAkB,CAmCtI;ACzDD;IACE,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAsBD;;;;GAIG;AACH,iCAAiC,OAAO,GAAE,oBAAyB,QAwBlE;ACnDD,mCAAoC,SAAQ,aAAa;IACvD,QAAQ,EAAE,SAAS,CAAA;CACpB;AAWD;;;;;;;GAOG;AACH,8BAA8B,KAAK,EAAE,kBAAkB,qBA0BtD;AAED;IACE;;OAEG;IACH,kBAAkB,EAAE,cAAc,CAAA;CACnC;AAED;;;GAGG;AACH,oCAAoC,iBAAiB,CAOpD;AAUD;;;;;;;GAOG;AACH,gCAAgC,KAAK,EAAE,kBAAkB,qBAMxD;AAED,sCAAuC,SAAQ,kBAAkB;IAC/D;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,iCAAiC,KAAK,EAAE,qBAAqB,GAAG,MAAM,WAAW,CAgBhF;AAED,wBAAyB,SAAQ,aAAa;IAC5C,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAA;CACxB;AAED;IACE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;IACE,2CAA2C;IAC3C,UAAU,EAAE,cAAc,CAAA;CAC3B;AAED;;;;;GAKG;AACH,yBAAyB,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CA2B9D;AC1KD,mCAAoC,SAAQ,iBAAiB,EAAE,QAAQ;IACrE,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;GAIG;AACH,8BAA8B,KAAK,EAAE,kBAAkB,qBAoBtD;ACjCD;;;;;;;GAOG;AACH,gCAAgC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,cAAgB,cAgJvE;ACnJD,iCAAkC,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,CAAC;IAClH;;OAEG;IACH,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;OAEG;IACH,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED;IACE,qCAAqC;IACrC,YAAY,EAAE,aAAa,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,EAAE,aAAa,CAAC;IAC1B,sDAAsD;IACtD,aAAa,EAAE,aAAa,CAAC;IAC7B,4DAA4D;IAC5D,SAAS,EAAE,aAAa,CAAA;CACzB;AAED;;;GAGG;AACH,2BAA2B,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,mBAAmB,GAAG,WAAW,CA4C3F;AC3FD;IACE;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2CAA2C;IAC3C,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAID;;;GAGG;AACH,wBAAwB,KAAK,EAAE,YAAY,qBA4B1C;AAED,eAAe;AACf,+CAMC;AC9DD;IACE;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED;IACE,mCAAmC;IACnC,UAAU,EAAE,aAAa,CAAC;IAC1B,sCAAsC;IACtC,aAAa,EAAE,aAAa,CAAA;CAC7B;AAED;;;GAGG;AACH,gCAAgC,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,UAAU,WAAW,CAAC,GAAG,gBAAgB,CAuBvI;ACtCD,YAAY,EAAC,SAAS,EAAE,aAAa,EAAE,aAAa,EAAC,MAAM,uBAAuB,CAAC","sources":["packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/calculatePosition.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useCloseOnScroll.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlayPosition.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlay.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlayTrigger.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/usePreventScroll.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useModal.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/DismissButton.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/ariaHideOutside.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/usePopover.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/Overlay.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useModalOverlay.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/index.ts","packages/@react-aria/overlays/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {useOverlayPosition} from './useOverlayPosition';\nexport {useOverlay} from './useOverlay';\nexport {useOverlayTrigger} from './useOverlayTrigger';\nexport {usePreventScroll} from './usePreventScroll';\nexport {ModalProvider, useModalProvider, OverlayProvider, OverlayContainer, useModal} from './useModal';\nexport {DismissButton} from './DismissButton';\nexport {ariaHideOutside} from './ariaHideOutside';\nexport {usePopover} from './usePopover';\nexport {useModalOverlay} from './useModalOverlay';\nexport {Overlay, useOverlayFocusContain} from './Overlay';\n\nexport type {AriaPositionProps, PositionAria} from './useOverlayPosition';\nexport type {AriaOverlayProps, OverlayAria} from './useOverlay';\nexport type {OverlayTriggerAria, OverlayTriggerProps} from './useOverlayTrigger';\nexport type {AriaModalOptions, ModalAria, ModalProviderAria, ModalProviderProps, OverlayContainerProps} from './useModal';\nexport type {DismissButtonProps} from './DismissButton';\nexport type {AriaPopoverProps, PopoverAria} from './usePopover';\nexport type {AriaModalOverlayProps, ModalOverlayAria} from './useModalOverlay';\nexport type {OverlayProps} from './Overlay';\nexport type {Placement, PlacementAxis, PositionProps} from '@react-types/overlays';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":";;;;;AEoBA,kCAAmC,SAAQ,aAAa;IACtD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,SAAS,EAAE,UAAU,OAAO,CAAC,CAAC;IAC9B;;OAEG;IACH,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;IACE,+CAA+C;IAC/C,YAAY,EAAE,aAAa,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,EAAE,aAAa,CAAC;IAC1B,oEAAoE;IACpE,SAAS,EAAE,aAAa,CAAC;IACzB,2CAA2C;IAC3C,cAAc,IAAI,IAAI,CAAA;CACvB;AAKD;;;GAGG;AACH,mCAAmC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA8KzE;AC9OD;IACE,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC7D;AAED;IACE,uDAAuD;IACvD,YAAY,EAAE,aAAa,CAAC;IAC5B,sDAAsD;IACtD,aAAa,EAAE,aAAa,CAAA;CAC7B;AAID;;;;GAIG;AACH,2BAA2B,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,UAAU,OAAO,CAAC,GAAG,WAAW,CAoGxF;AC/ID;IACE,qDAAqD;IACrD,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAA;CACtD;AAED;IACE,qCAAqC;IACrC,YAAY,EAAE,eAAe,CAAC;IAE9B,+CAA+C;IAC/C,YAAY,EAAE,QAAQ,CAAA;CACvB;AAED;;;GAGG;AACH,kCAAkC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,CAAC,EAAE,UAAU,OAAO,CAAC,GAAG,kBAAkB,CAmCtI;ACzDD;IACE,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAsBD;;;;GAIG;AACH,iCAAiC,OAAO,GAAE,oBAAyB,QAwBlE;ACnDD,mCAAoC,SAAQ,aAAa;IACvD,QAAQ,EAAE,SAAS,CAAA;CACpB;AAWD;;;;;;;GAOG;AACH,8BAA8B,KAAK,EAAE,kBAAkB,qBA0BtD;AAED;IACE;;OAEG;IACH,kBAAkB,EAAE,cAAc,CAAA;CACnC;AAED;;;GAGG;AACH,oCAAoC,iBAAiB,CAOpD;AAUD;;;;;;;GAOG;AACH,gCAAgC,KAAK,EAAE,kBAAkB,qBAMxD;AAED,sCAAuC,SAAQ,kBAAkB;IAC/D;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,iCAAiC,KAAK,EAAE,qBAAqB,GAAG,MAAM,WAAW,CAgBhF;AAED,wBAAyB,SAAQ,aAAa;IAC5C,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAA;CACxB;AAED;IACE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;IACE,2CAA2C;IAC3C,UAAU,EAAE,cAAc,CAAA;CAC3B;AAED;;;;;GAKG;AACH,yBAAyB,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CA2B9D;AC1KD,mCAAoC,SAAQ,iBAAiB,EAAE,QAAQ;IACrE,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;GAIG;AACH,8BAA8B,KAAK,EAAE,kBAAkB,qBAqBtD;AClCD;;;;;;;GAOG;AACH,gCAAgC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,cAAgB,cAgJvE;ACnJD,iCAAkC,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,CAAC;IAClH;;OAEG;IACH,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;OAEG;IACH,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC;IAC/B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC7D;AAED;IACE,qCAAqC;IACrC,YAAY,EAAE,aAAa,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,EAAE,aAAa,CAAC;IAC1B,sDAAsD;IACtD,aAAa,EAAE,aAAa,CAAC;IAC7B,4DAA4D;IAC5D,SAAS,EAAE,aAAa,CAAA;CACzB;AAED;;;GAGG;AACH,2BAA2B,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,mBAAmB,GAAG,WAAW,CA8C3F;ACpGD;IACE;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2CAA2C;IAC3C,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAID;;;GAGG;AACH,wBAAwB,KAAK,EAAE,YAAY,qBA4B1C;AAED,eAAe;AACf,+CAMC;AC9DD;IACE;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED;IACE,mCAAmC;IACnC,UAAU,EAAE,aAAa,CAAC;IAC1B,sCAAsC;IACtC,aAAa,EAAE,aAAa,CAAA;CAC7B;AAED;;;GAGG;AACH,gCAAgC,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,UAAU,WAAW,CAAC,GAAG,gBAAgB,CAuBvI;ACtCD,YAAY,EAAC,SAAS,EAAE,aAAa,EAAE,aAAa,EAAC,MAAM,uBAAuB,CAAC","sources":["packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/calculatePosition.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useCloseOnScroll.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlayPosition.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlay.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useOverlayTrigger.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/usePreventScroll.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useModal.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/DismissButton.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/ariaHideOutside.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/usePopover.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/Overlay.tsx","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/useModalOverlay.ts","packages/@react-aria/overlays/src/packages/@react-aria/overlays/src/index.ts","packages/@react-aria/overlays/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {useOverlayPosition} from './useOverlayPosition';\nexport {useOverlay} from './useOverlay';\nexport {useOverlayTrigger} from './useOverlayTrigger';\nexport {usePreventScroll} from './usePreventScroll';\nexport {ModalProvider, useModalProvider, OverlayProvider, OverlayContainer, useModal} from './useModal';\nexport {DismissButton} from './DismissButton';\nexport {ariaHideOutside} from './ariaHideOutside';\nexport {usePopover} from './usePopover';\nexport {useModalOverlay} from './useModalOverlay';\nexport {Overlay, useOverlayFocusContain} from './Overlay';\n\nexport type {AriaPositionProps, PositionAria} from './useOverlayPosition';\nexport type {AriaOverlayProps, OverlayAria} from './useOverlay';\nexport type {OverlayTriggerAria, OverlayTriggerProps} from './useOverlayTrigger';\nexport type {AriaModalOptions, ModalAria, ModalProviderAria, ModalProviderProps, OverlayContainerProps} from './useModal';\nexport type {DismissButtonProps} from './DismissButton';\nexport type {AriaPopoverProps, PopoverAria} from './usePopover';\nexport type {AriaModalOverlayProps, ModalOverlayAria} from './useModalOverlay';\nexport type {OverlayProps} from './Overlay';\nexport type {Placement, PlacementAxis, PositionProps} from '@react-types/overlays';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/overlays",
3
- "version": "3.19.0",
3
+ "version": "3.21.0",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -22,12 +22,12 @@
22
22
  "url": "https://github.com/adobe/react-spectrum"
23
23
  },
24
24
  "dependencies": {
25
- "@react-aria/focus": "^3.15.0",
26
- "@react-aria/i18n": "^3.9.0",
27
- "@react-aria/interactions": "^3.20.0",
28
- "@react-aria/ssr": "^3.9.0",
29
- "@react-aria/utils": "^3.22.0",
30
- "@react-aria/visually-hidden": "^3.8.7",
25
+ "@react-aria/focus": "^3.16.1",
26
+ "@react-aria/i18n": "^3.10.1",
27
+ "@react-aria/interactions": "^3.21.0",
28
+ "@react-aria/ssr": "^3.9.1",
29
+ "@react-aria/utils": "^3.23.1",
30
+ "@react-aria/visually-hidden": "^3.8.9",
31
31
  "@react-stately/overlays": "^3.6.4",
32
32
  "@react-types/button": "^3.9.1",
33
33
  "@react-types/overlays": "^3.8.4",
@@ -41,5 +41,5 @@
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  },
44
- "gitHead": "9ce2f674eab2cc8912800d3162dcf00a1ce94274"
44
+ "gitHead": "f040ff62678e6a31375b96c05396df0bae660350"
45
45
  }
@@ -30,7 +30,7 @@ export interface DismissButtonProps extends AriaLabelingProps, DOMProps {
30
30
  */
31
31
  export function DismissButton(props: DismissButtonProps) {
32
32
  let {onDismiss, ...otherProps} = props;
33
- let stringFormatter = useLocalizedStringFormatter(intlMessages);
33
+ let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/overlays');
34
34
 
35
35
  let labels = useLabels(otherProps, stringFormatter.format('dismiss'));
36
36
 
@@ -45,7 +45,8 @@ export function DismissButton(props: DismissButtonProps) {
45
45
  <button
46
46
  {...labels}
47
47
  tabIndex={-1}
48
- onClick={onClick} />
48
+ onClick={onClick}
49
+ style={{width: 1, height: 1}} />
49
50
  </VisuallyHidden>
50
51
  );
51
52
  }
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import {Axis, Placement, PlacementAxis, SizeAxis} from '@react-types/overlays';
14
- import {clamp} from '@react-aria/utils';
14
+ import {clamp, isWebKit} from '@react-aria/utils';
15
15
 
16
16
  interface Position {
17
17
  top?: number,
@@ -61,6 +61,8 @@ interface PositionOpts {
61
61
  arrowBoundaryOffset?: number
62
62
  }
63
63
 
64
+ type HeightGrowthDirection = 'top' | 'bottom';
65
+
64
66
  export interface PositionResult {
65
67
  position?: Position,
66
68
  arrowOffsetLeft?: number,
@@ -106,6 +108,7 @@ let visualViewport = typeof document !== 'undefined' && window.visualViewport;
106
108
  function getContainerDimensions(containerNode: Element): Dimensions {
107
109
  let width = 0, height = 0, totalWidth = 0, totalHeight = 0, top = 0, left = 0;
108
110
  let scroll: Position = {};
111
+ let isPinchZoomedIn = visualViewport?.scale > 1;
109
112
 
110
113
  if (containerNode.tagName === 'BODY') {
111
114
  let documentElement = document.documentElement;
@@ -113,9 +116,16 @@ function getContainerDimensions(containerNode: Element): Dimensions {
113
116
  totalHeight = documentElement.clientHeight;
114
117
  width = visualViewport?.width ?? totalWidth;
115
118
  height = visualViewport?.height ?? totalHeight;
116
-
117
119
  scroll.top = documentElement.scrollTop || containerNode.scrollTop;
118
120
  scroll.left = documentElement.scrollLeft || containerNode.scrollLeft;
121
+
122
+ // The goal of the below is to get a top/left value that represents the top/left of the visual viewport with
123
+ // respect to the layout viewport origin. This combined with the scrollTop/scrollLeft will allow us to calculate
124
+ // coordinates/values with respect to the visual viewport or with respect to the layout viewport.
125
+ if (visualViewport) {
126
+ top = visualViewport.offsetTop;
127
+ left = visualViewport.offsetLeft;
128
+ }
119
129
  } else {
120
130
  ({width, height, top, left} = getOffset(containerNode));
121
131
  scroll.top = containerNode.scrollTop;
@@ -124,6 +134,17 @@ function getContainerDimensions(containerNode: Element): Dimensions {
124
134
  totalHeight = height;
125
135
  }
126
136
 
137
+ if (isWebKit() && (containerNode.tagName === 'BODY' || containerNode.tagName === 'HTML') && isPinchZoomedIn) {
138
+ // Safari will report a non-zero scrollTop/Left for the non-scrolling body/HTML element when pinch zoomed in unlike other browsers.
139
+ // Set to zero for parity calculations so we get consistent positioning of overlays across all browsers.
140
+ // Also switch to visualViewport.pageTop/pageLeft so that we still accomodate for scroll positioning for body/HTML elements that are actually scrollable
141
+ // before pinch zoom happens
142
+ scroll.top = 0;
143
+ scroll.left = 0;
144
+ top = visualViewport.pageTop;
145
+ left = visualViewport.pageLeft;
146
+ }
147
+
127
148
  return {width, height, totalWidth, totalHeight, scroll, top, left};
128
149
  }
129
150
 
@@ -136,6 +157,7 @@ function getScroll(node: Element): Offset {
136
157
  };
137
158
  }
138
159
 
160
+ // Determines the amount of space required when moving the overlay to ensure it remains in the boundary
139
161
  function getDelta(
140
162
  axis: Axis,
141
163
  offset: number,
@@ -149,17 +171,25 @@ function getDelta(
149
171
  // is portaled somewhere other than the body and has an ancestor with
150
172
  // position: relative/absolute, it will be different.
151
173
  containerDimensions: Dimensions,
152
- padding: number
174
+ padding: number,
175
+ containerOffsetWithBoundary: Offset
153
176
  ) {
154
177
  let containerScroll = containerDimensions.scroll[axis];
155
- let boundaryHeight = boundaryDimensions[AXIS_SIZE[axis]];
156
- let startEdgeOffset = offset - padding - containerScroll;
157
- let endEdgeOffset = offset + padding - containerScroll + size;
158
-
159
- if (startEdgeOffset < 0) {
160
- return -startEdgeOffset;
161
- } else if (endEdgeOffset > boundaryHeight) {
162
- return Math.max(boundaryHeight - endEdgeOffset, -startEdgeOffset);
178
+ // The height/width of the boundary. Matches the axis along which we are adjusting the overlay position
179
+ let boundarySize = boundaryDimensions[AXIS_SIZE[axis]];
180
+ // Calculate the edges of the boundary (accomodating for the boundary padding) and the edges of the overlay.
181
+ // Note that these values are with respect to the visual viewport (aka 0,0 is the top left of the viewport)
182
+ let boundaryStartEdge = boundaryDimensions.scroll[AXIS[axis]] + padding;
183
+ let boundaryEndEdge = boundarySize + boundaryDimensions.scroll[AXIS[axis]] - padding;
184
+ let startEdgeOffset = offset - containerScroll + containerOffsetWithBoundary[axis] - boundaryDimensions[AXIS[axis]];
185
+ let endEdgeOffset = offset - containerScroll + size + containerOffsetWithBoundary[axis] - boundaryDimensions[AXIS[axis]];
186
+
187
+ // If any of the overlay edges falls outside of the boundary, shift the overlay the required amount to align one of the overlay's
188
+ // edges with the closest boundary edge.
189
+ if (startEdgeOffset < boundaryStartEdge) {
190
+ return boundaryStartEdge - startEdgeOffset;
191
+ } else if (endEdgeOffset > boundaryEndEdge) {
192
+ return Math.max(boundaryEndEdge - endEdgeOffset, boundaryStartEdge - startEdgeOffset);
163
193
  } else {
164
194
  return 0;
165
195
  }
@@ -222,7 +252,7 @@ function computePosition(
222
252
  }/* else {
223
253
  the overlay top should match the button top
224
254
  } */
225
- // add the crossOffset from props
255
+
226
256
  position[crossAxis] += crossOffset;
227
257
 
228
258
  // overlay top overlapping arrow with button bottom
@@ -242,7 +272,6 @@ function computePosition(
242
272
  } else {
243
273
  position[axis] = Math.floor(childOffset[axis] + childOffset[size] + offset);
244
274
  }
245
-
246
275
  return position;
247
276
  }
248
277
 
@@ -250,23 +279,30 @@ function getMaxHeight(
250
279
  position: Position,
251
280
  boundaryDimensions: Dimensions,
252
281
  containerOffsetWithBoundary: Offset,
253
- childOffset: Offset,
282
+ isContainerPositioned: boolean,
254
283
  margins: Position,
255
- padding: number
284
+ padding: number,
285
+ overlayHeight: number,
286
+ heightGrowthDirection: HeightGrowthDirection
256
287
  ) {
257
- return position.top != null
288
+ const containerHeight = (isContainerPositioned ? containerOffsetWithBoundary.height : boundaryDimensions[TOTAL_SIZE.height]);
289
+ // For cases where position is set via "bottom" instead of "top", we need to calculate the true overlay top with respect to the boundary. Reverse calculate this with the same method
290
+ // used in computePosition.
291
+ let overlayTop = position.top != null ? containerOffsetWithBoundary.top + position.top : containerOffsetWithBoundary.top + (containerHeight - position.bottom - overlayHeight);
292
+ let maxHeight = heightGrowthDirection !== 'top' ?
258
293
  // We want the distance between the top of the overlay to the bottom of the boundary
259
- ? Math.max(0,
294
+ Math.max(0,
260
295
  (boundaryDimensions.height + boundaryDimensions.top + boundaryDimensions.scroll.top) // this is the bottom of the boundary
261
- - (containerOffsetWithBoundary.top + position.top) // this is the top of the overlay
296
+ - overlayTop // this is the top of the overlay
262
297
  - (margins.top + margins.bottom + padding) // save additional space for margin and padding
263
298
  )
264
- // We want the distance between the top of the trigger to the top of the boundary
299
+ // We want the distance between the bottom of the overlay to the top of the boundary
265
300
  : Math.max(0,
266
- (childOffset.top + containerOffsetWithBoundary.top) // this is the top of the trigger
301
+ (overlayTop + overlayHeight) // this is the bottom of the overlay
267
302
  - (boundaryDimensions.top + boundaryDimensions.scroll.top) // this is the top of the boundary
268
303
  - (margins.top + margins.bottom + padding) // save additional space for margin and padding
269
304
  );
305
+ return Math.min(boundaryDimensions.height - (padding * 2), maxHeight);
270
306
  }
271
307
 
272
308
  function getAvailableSpace(
@@ -337,16 +373,34 @@ export function calculatePositionInternal(
337
373
  }
338
374
  }
339
375
 
340
- let delta = getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, containerDimensions, padding);
376
+ // Determine the direction the height of the overlay can grow so that we can choose how to calculate the max height
377
+ let heightGrowthDirection: HeightGrowthDirection = 'bottom';
378
+ if (placementInfo.axis === 'top') {
379
+ if (placementInfo.placement === 'top') {
380
+ heightGrowthDirection = 'top';
381
+ } else if (placementInfo.placement === 'bottom') {
382
+ heightGrowthDirection = 'bottom';
383
+ }
384
+ } else if (placementInfo.crossAxis === 'top') {
385
+ if (placementInfo.crossPlacement === 'top') {
386
+ heightGrowthDirection = 'bottom';
387
+ } else if (placementInfo.crossPlacement === 'bottom') {
388
+ heightGrowthDirection = 'top';
389
+ }
390
+ }
391
+
392
+ let delta = getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, containerDimensions, padding, containerOffsetWithBoundary);
341
393
  position[crossAxis] += delta;
342
394
 
343
395
  let maxHeight = getMaxHeight(
344
396
  position,
345
397
  boundaryDimensions,
346
398
  containerOffsetWithBoundary,
347
- childOffset,
399
+ isContainerPositioned,
348
400
  margins,
349
- padding
401
+ padding,
402
+ overlaySize.height,
403
+ heightGrowthDirection
350
404
  );
351
405
 
352
406
  if (userSetMaxHeight && userSetMaxHeight < maxHeight) {
@@ -356,7 +410,7 @@ export function calculatePositionInternal(
356
410
  overlaySize.height = Math.min(overlaySize.height, maxHeight);
357
411
 
358
412
  position = computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, normalizedOffset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
359
- delta = getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, containerDimensions, padding);
413
+ delta = getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, containerDimensions, padding, containerOffsetWithBoundary);
360
414
  position[crossAxis] += delta;
361
415
 
362
416
  let arrowPosition: Position = {};
@@ -425,7 +479,14 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
425
479
  let scrollSize = getScroll(scrollNode);
426
480
  let boundaryDimensions = getContainerDimensions(boundaryElement);
427
481
  let containerDimensions = getContainerDimensions(container);
482
+ // If the container is the HTML element wrapping the body element, the retrieved scrollTop/scrollLeft will be equal to the
483
+ // body element's scroll. Set the container's scroll values to 0 since the overlay's edge position value in getDelta don't then need to be further offset
484
+ // by the container scroll since they are essentially the same containing element and thus in the same coordinate system
428
485
  let containerOffsetWithBoundary: Offset = boundaryElement.tagName === 'BODY' ? getOffset(container) : getPosition(container, boundaryElement);
486
+ if (container.tagName === 'HTML' && boundaryElement.tagName === 'BODY') {
487
+ containerDimensions.scroll.top = 0;
488
+ containerDimensions.scroll.left = 0;
489
+ }
429
490
 
430
491
  return calculatePositionInternal(
431
492
  placement,
package/src/useOverlay.ts CHANGED
@@ -84,7 +84,7 @@ export function useOverlay(props: AriaOverlayProps, ref: RefObject<Element>): Ov
84
84
  };
85
85
  }, [isOpen, ref]);
86
86
 
87
- // Only hide the overlay when it is the topmost visible overlay in the stack.
87
+ // Only hide the overlay when it is the topmost visible overlay in the stack
88
88
  let onHide = () => {
89
89
  if (visibleOverlays[visibleOverlays.length - 1] === ref && onClose) {
90
90
  onClose();
@@ -13,7 +13,7 @@
13
13
  import {calculatePosition, PositionResult} from './calculatePosition';
14
14
  import {DOMAttributes} from '@react-types/shared';
15
15
  import {Placement, PlacementAxis, PositionProps} from '@react-types/overlays';
16
- import {RefObject, useCallback, useRef, useState} from 'react';
16
+ import {RefObject, useCallback, useEffect, useRef, useState} from 'react';
17
17
  import {useCloseOnScroll} from './useCloseOnScroll';
18
18
  import {useLayoutEffect, useResizeObserver} from '@react-aria/utils';
19
19
  import {useLocale} from '@react-aria/i18n';
@@ -124,11 +124,31 @@ export function useOverlayPosition(props: AriaPositionProps): PositionAria {
124
124
  arrowSize
125
125
  ];
126
126
 
127
+ // Note, the position freezing breaks if body sizes itself dynamicly with the visual viewport but that might
128
+ // just be a non-realistic use case
129
+ // Upon opening a overlay, record the current visual viewport scale so we can freeze the overlay styles
130
+ let lastScale = useRef(visualViewport?.scale);
131
+ useEffect(() => {
132
+ if (isOpen) {
133
+ lastScale.current = visualViewport?.scale;
134
+ }
135
+ }, [isOpen]);
136
+
127
137
  let updatePosition = useCallback(() => {
128
138
  if (shouldUpdatePosition === false || !isOpen || !overlayRef.current || !targetRef.current || !scrollRef.current || !boundaryElement) {
129
139
  return;
130
140
  }
131
141
 
142
+ if (visualViewport?.scale !== lastScale.current) {
143
+ return;
144
+ }
145
+
146
+ // Always reset the overlay's previous max height if not defined by the user so that we can compensate for
147
+ // RAC collections populating after a second render and properly set a correct max height + positioning when it populates.
148
+ if (!maxHeight && overlayRef.current) {
149
+ (overlayRef.current as HTMLElement).style.maxHeight = 'none';
150
+ }
151
+
132
152
  let position = calculatePosition({
133
153
  placement: translateRTL(placement, direction),
134
154
  overlayNode: overlayRef.current,
@@ -183,12 +203,19 @@ export function useOverlayPosition(props: AriaPositionProps): PositionAria {
183
203
  updatePosition();
184
204
  };
185
205
 
186
- visualViewport?.addEventListener('resize', onResize);
187
- visualViewport?.addEventListener('scroll', onResize);
206
+ // Only reposition the overlay if a scroll event happens immediately as a result of resize (aka the virtual keyboard has appears)
207
+ // We don't want to reposition the overlay if the user has pinch zoomed in and is scrolling the viewport around.
208
+ let onScroll = () => {
209
+ if (isResizing.current) {
210
+ onResize();
211
+ }
212
+ };
188
213
 
214
+ visualViewport?.addEventListener('resize', onResize);
215
+ visualViewport?.addEventListener('scroll', onScroll);
189
216
  return () => {
190
217
  visualViewport?.removeEventListener('resize', onResize);
191
- visualViewport?.removeEventListener('scroll', onResize);
218
+ visualViewport?.removeEventListener('scroll', onScroll);
192
219
  };
193
220
  }, [updatePosition]);
194
221
 
package/src/usePopover.ts CHANGED
@@ -46,7 +46,14 @@ export interface AriaPopoverProps extends Omit<AriaPositionProps, 'isOpen' | 'on
46
46
  *
47
47
  * @default false
48
48
  */
49
- isKeyboardDismissDisabled?: boolean
49
+ isKeyboardDismissDisabled?: boolean,
50
+ /**
51
+ * When user interacts with the argument element outside of the popover ref,
52
+ * return true if onClose should be called. This gives you a chance to filter
53
+ * out interaction with elements that should not dismiss the popover.
54
+ * By default, onClose will always be called on interaction outside the popover ref.
55
+ */
56
+ shouldCloseOnInteractOutside?: (element: Element) => boolean
50
57
  }
51
58
 
52
59
  export interface PopoverAria {
@@ -70,6 +77,7 @@ export function usePopover(props: AriaPopoverProps, state: OverlayTriggerState):
70
77
  popoverRef,
71
78
  isNonModal,
72
79
  isKeyboardDismissDisabled,
80
+ shouldCloseOnInteractOutside,
73
81
  ...otherProps
74
82
  } = props;
75
83
 
@@ -79,7 +87,8 @@ export function usePopover(props: AriaPopoverProps, state: OverlayTriggerState):
79
87
  onClose: state.close,
80
88
  shouldCloseOnBlur: true,
81
89
  isDismissable: !isNonModal,
82
- isKeyboardDismissDisabled
90
+ isKeyboardDismissDisabled,
91
+ shouldCloseOnInteractOutside
83
92
  },
84
93
  popoverRef
85
94
  );
@@ -89,11 +98,11 @@ export function usePopover(props: AriaPopoverProps, state: OverlayTriggerState):
89
98
  targetRef: triggerRef,
90
99
  overlayRef: popoverRef,
91
100
  isOpen: state.isOpen,
92
- onClose: null
101
+ onClose: isNonModal ? state.close : null
93
102
  });
94
103
 
95
104
  usePreventScroll({
96
- isDisabled: isNonModal
105
+ isDisabled: isNonModal || !state.isOpen
97
106
  });
98
107
 
99
108
  useLayoutEffect(() => {
@@ -92,8 +92,9 @@ function preventScrollStandard() {
92
92
  //
93
93
  // 1. Prevent default on `touchmove` events that are not in a scrollable element. This prevents touch scrolling
94
94
  // on the window.
95
- // 2. Prevent default on `touchmove` events inside a scrollable element when the scroll position is at the
96
- // top or bottom. This avoids the whole page scrolling instead, but does prevent overscrolling.
95
+ // 2. Set `overscroll-behavior: contain` on nested scrollable regions so they do not scroll the page when at
96
+ // the top or bottom. Work around a bug where this does not work when the element does not actually overflow
97
+ // by preventing default in a `touchmove` event.
97
98
  // 3. Prevent default on `touchend` events on input elements and handle focusing the element ourselves.
98
99
  // 4. When focusing an input, apply a transform to trick Safari into thinking the input is at the top
99
100
  // of the page, which prevents it from scrolling the page. After the input is focused, scroll the element
@@ -105,15 +106,20 @@ function preventScrollStandard() {
105
106
  // to navigate to an input with the next/previous buttons that's outside a modal.
106
107
  function preventScrollMobileSafari() {
107
108
  let scrollable: Element;
108
- let lastY = 0;
109
+ let restoreScrollableStyles;
109
110
  let onTouchStart = (e: TouchEvent) => {
110
111
  // Store the nearest scrollable parent element from the element that the user touched.
111
- scrollable = getScrollParent(e.target as Element);
112
+ scrollable = getScrollParent(e.target as Element, true);
112
113
  if (scrollable === document.documentElement && scrollable === document.body) {
113
114
  return;
114
115
  }
115
116
 
116
- lastY = e.changedTouches[0].pageY;
117
+ // Prevent scrolling up when at the top and scrolling down when at the bottom
118
+ // of a nested scrollable area, otherwise mobile Safari will start scrolling
119
+ // the window instead.
120
+ if (scrollable instanceof HTMLElement && window.getComputedStyle(scrollable).overscrollBehavior === 'auto') {
121
+ restoreScrollableStyles = setStyle(scrollable, 'overscrollBehavior', 'contain');
122
+ }
117
123
  };
118
124
 
119
125
  let onTouchMove = (e: TouchEvent) => {
@@ -123,23 +129,15 @@ function preventScrollMobileSafari() {
123
129
  return;
124
130
  }
125
131
 
126
- // Prevent scrolling up when at the top and scrolling down when at the bottom
127
- // of a nested scrollable area, otherwise mobile Safari will start scrolling
128
- // the window instead. Unfortunately, this disables bounce scrolling when at
129
- // the top but it's the best we can do.
130
- let y = e.changedTouches[0].pageY;
131
- let scrollTop = scrollable.scrollTop;
132
- let bottom = scrollable.scrollHeight - scrollable.clientHeight;
133
-
134
- if (bottom === 0) {
135
- return;
136
- }
137
-
138
- if ((scrollTop <= 0 && y > lastY) || (scrollTop >= bottom && y < lastY)) {
132
+ // overscroll-behavior should prevent scroll chaining, but currently does not
133
+ // if the element doesn't actually overflow. https://bugs.webkit.org/show_bug.cgi?id=243452
134
+ // This checks that both the width and height do not overflow, otherwise we might
135
+ // block horizontal scrolling too. In that case, adding `touch-action: pan-x` to
136
+ // the element will prevent vertical page scrolling. We can't add that automatically
137
+ // because it must be set before the touchstart event.
138
+ if (scrollable.scrollHeight === scrollable.clientHeight && scrollable.scrollWidth === scrollable.clientWidth) {
139
139
  e.preventDefault();
140
140
  }
141
-
142
- lastY = y;
143
141
  };
144
142
 
145
143
  let onTouchEnd = (e: TouchEvent) => {
@@ -148,6 +146,7 @@ function preventScrollMobileSafari() {
148
146
  // Apply this change if we're not already focused on the target element
149
147
  if (willOpenKeyboard(target) && target !== document.activeElement) {
150
148
  e.preventDefault();
149
+ setupStyles();
151
150
 
152
151
  // Apply a transform to trick Safari into thinking the input is at the top of the page
153
152
  // so it doesn't try to scroll it into view. When tapping on an input, this needs to
@@ -158,11 +157,17 @@ function preventScrollMobileSafari() {
158
157
  target.style.transform = '';
159
158
  });
160
159
  }
160
+
161
+ if (restoreScrollableStyles) {
162
+ restoreScrollableStyles();
163
+ }
161
164
  };
162
165
 
163
166
  let onFocus = (e: FocusEvent) => {
164
167
  let target = e.target as HTMLElement;
165
168
  if (willOpenKeyboard(target)) {
169
+ setupStyles();
170
+
166
171
  // Transform also needs to be applied in the focus event in cases where focus moves
167
172
  // other than tapping on an input directly, e.g. the next/previous buttons in the
168
173
  // software keyboard. In these cases, it seems applying the transform in the focus event
@@ -190,40 +195,50 @@ function preventScrollMobileSafari() {
190
195
  }
191
196
  };
192
197
 
193
- let onWindowScroll = () => {
194
- // Last resort. If the window scrolled, scroll it back to the top.
195
- // It should always be at the top because the body will have a negative margin (see below).
196
- window.scrollTo(0, 0);
197
- };
198
+ let restoreStyles = null;
199
+ let setupStyles = () => {
200
+ if (restoreStyles) {
201
+ return;
202
+ }
198
203
 
199
- // Record the original scroll position so we can restore it.
200
- // Then apply a negative margin to the body to offset it by the scroll position. This will
201
- // enable us to scroll the window to the top, which is required for the rest of this to work.
202
- let scrollX = window.pageXOffset;
203
- let scrollY = window.pageYOffset;
204
+ let onWindowScroll = () => {
205
+ // Last resort. If the window scrolled, scroll it back to the top.
206
+ // It should always be at the top because the body will have a negative margin (see below).
207
+ window.scrollTo(0, 0);
208
+ };
204
209
 
205
- let restoreStyles = chain(
206
- setStyle(document.documentElement, 'paddingRight', `${window.innerWidth - document.documentElement.clientWidth}px`),
207
- setStyle(document.documentElement, 'overflow', 'hidden'),
208
- setStyle(document.body, 'marginTop', `-${scrollY}px`)
209
- );
210
+ // Record the original scroll position so we can restore it.
211
+ // Then apply a negative margin to the body to offset it by the scroll position. This will
212
+ // enable us to scroll the window to the top, which is required for the rest of this to work.
213
+ let scrollX = window.pageXOffset;
214
+ let scrollY = window.pageYOffset;
215
+
216
+ restoreStyles = chain(
217
+ addEvent(window, 'scroll', onWindowScroll),
218
+ setStyle(document.documentElement, 'paddingRight', `${window.innerWidth - document.documentElement.clientWidth}px`),
219
+ setStyle(document.documentElement, 'overflow', 'hidden'),
220
+ setStyle(document.body, 'marginTop', `-${scrollY}px`),
221
+ () => {
222
+ window.scrollTo(scrollX, scrollY);
223
+ }
224
+ );
210
225
 
211
- // Scroll to the top. The negative margin on the body will make this appear the same.
212
- window.scrollTo(0, 0);
226
+ // Scroll to the top. The negative margin on the body will make this appear the same.
227
+ window.scrollTo(0, 0);
228
+ };
213
229
 
214
230
  let removeEvents = chain(
215
231
  addEvent(document, 'touchstart', onTouchStart, {passive: false, capture: true}),
216
232
  addEvent(document, 'touchmove', onTouchMove, {passive: false, capture: true}),
217
233
  addEvent(document, 'touchend', onTouchEnd, {passive: false, capture: true}),
218
- addEvent(document, 'focus', onFocus, true),
219
- addEvent(window, 'scroll', onWindowScroll)
234
+ addEvent(document, 'focus', onFocus, true)
220
235
  );
221
236
 
222
237
  return () => {
223
238
  // Restore styles and scroll the page back to where it was.
224
- restoreStyles();
239
+ restoreScrollableStyles?.();
240
+ restoreStyles?.();
225
241
  removeEvents();
226
- window.scrollTo(scrollX, scrollY);
227
242
  };
228
243
  }
229
244