@khanacademy/wonder-blocks-modal 8.8.4 → 8.9.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,5 +1,5 @@
1
1
 
2
- > @khanacademy/wonder-blocks-modal@8.8.4 build:css /home/runner/work/wonder-blocks/wonder-blocks/packages/wonder-blocks-modal
2
+ > @khanacademy/wonder-blocks-modal@8.9.0 build:css /home/runner/work/wonder-blocks/wonder-blocks/packages/wonder-blocks-modal
3
3
  > pnpm exec wonder-blocks-tokens .
4
4
 
5
5
  CSS variables generated successfully in: /home/runner/work/wonder-blocks/wonder-blocks/packages/wonder-blocks-modal/dist/css
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @khanacademy/wonder-blocks-modal
2
2
 
3
+ ## 8.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c56e31b: ModalLauncher: add a `styles` prop with a `backdrop` slot so custom styles can be applied to the backdrop (the veil), matching the API DrawerLauncher already has. Useful for properties that must live on the veil element itself, such as a `viewTransitionName`.
8
+
3
9
  ## 8.8.4
4
10
 
5
11
  ### Patch Changes
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import type { StyleType } from "@khanacademy/wonder-blocks-core";
2
3
  import type { ModalElement } from "../util/types";
3
4
  type Props = {
4
5
  children: ModalElement;
@@ -13,6 +14,10 @@ type Props = {
13
14
  * Test ID used for e2e testing.
14
15
  */
15
16
  testId?: string;
17
+ /**
18
+ * Optional custom styles.
19
+ */
20
+ style?: StyleType;
16
21
  };
17
- declare const ModalBackdrop: ({ children, initialFocusId, onCloseModal, testId, }: Props) => React.ReactElement;
22
+ declare const ModalBackdrop: ({ children, initialFocusId, onCloseModal, testId, style, }: Props) => React.ReactElement;
18
23
  export default ModalBackdrop;
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import type { StyleType } from "@khanacademy/wonder-blocks-core";
2
3
  import type { ModalElement } from "../util/types";
3
4
  declare const _default: {
4
5
  (props: {
@@ -6,6 +7,9 @@ declare const _default: {
6
7
  closeModal: () => void;
7
8
  }) => ModalElement);
8
9
  readonly backdropDismissEnabled?: boolean;
10
+ readonly styles?: {
11
+ backdrop?: StyleType;
12
+ };
9
13
  readonly initialFocusId?: string;
10
14
  readonly closedFocusId?: string;
11
15
  readonly testId?: string;
package/dist/es/index.js CHANGED
@@ -29,13 +29,13 @@ const FOCUSABLE_ELEMENTS$1='button, [href], input, select, textarea, [tabindex]:
29
29
 
30
30
  const FOCUSABLE_ELEMENTS="a[href], details, input, textarea, select, button";function findFocusableNodes(root){return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS))}
31
31
 
32
- const getInitialFocusElement=(node,initialFocusId)=>{if(!initialFocusId){return null}return ReactDOM.findDOMNode(node.querySelector(`#${initialFocusId}`))};const getFirstFocusableElement=node=>{const focusableElements=findFocusableNodes(node);if(!focusableElements){return null}return focusableElements[0]};const getDialogElement=node=>{const dialogElement=ReactDOM.findDOMNode(node.querySelector('[role="dialog"]'));dialogElement?.setAttribute("tabindex","-1");return dialogElement};const ModalBackdrop=({children,initialFocusId,onCloseModal,testId})=>{const backdropRef=React.useRef(null);const[mousePressedOutside,setMousePressedOutside]=React.useState(false);React.useEffect(()=>{const node=ReactDOM.findDOMNode(backdropRef.current);if(!node){return}const firstFocusableElement=getInitialFocusElement(node,initialFocusId)||getFirstFocusableElement(node)||getDialogElement(node);setTimeout(()=>{firstFocusableElement?.focus();},0);},[initialFocusId]);const handleMouseDown=React.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");setMousePressedOutside(isBackdropClick||isPaddingLayerClick);},[]);const handleMouseUp=React.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");if((isBackdropClick||isPaddingLayerClick)&&mousePressedOutside){onCloseModal();}setMousePressedOutside(false);},[mousePressedOutside,onCloseModal]);const backdropProps={[ModalLauncherPortalAttributeName]:true};return jsx(View,{ref:backdropRef,style:styles$5.modalPositioner,onMouseDown:handleMouseDown,onMouseUp:handleMouseUp,testId:testId,...backdropProps,children:children})};const styles$5=StyleSheet.create({modalPositioner:{position:"fixed",insetInlineStart:0,insetBlockStart:0,width:"100%",height:"100%",alignItems:"center",justifyContent:"center",overflow:"auto",background:semanticColor.core.background.overlay.default}});
32
+ const getInitialFocusElement=(node,initialFocusId)=>{if(!initialFocusId){return null}return ReactDOM.findDOMNode(node.querySelector(`#${initialFocusId}`))};const getFirstFocusableElement=node=>{const focusableElements=findFocusableNodes(node);if(!focusableElements){return null}return focusableElements[0]};const getDialogElement=node=>{const dialogElement=ReactDOM.findDOMNode(node.querySelector('[role="dialog"]'));dialogElement?.setAttribute("tabindex","-1");return dialogElement};const ModalBackdrop=({children,initialFocusId,onCloseModal,testId,style})=>{const backdropRef=React.useRef(null);const[mousePressedOutside,setMousePressedOutside]=React.useState(false);React.useEffect(()=>{const node=ReactDOM.findDOMNode(backdropRef.current);if(!node){return}const firstFocusableElement=getInitialFocusElement(node,initialFocusId)||getFirstFocusableElement(node)||getDialogElement(node);setTimeout(()=>{firstFocusableElement?.focus();},0);},[initialFocusId]);const handleMouseDown=React.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");setMousePressedOutside(isBackdropClick||isPaddingLayerClick);},[]);const handleMouseUp=React.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");if((isBackdropClick||isPaddingLayerClick)&&mousePressedOutside){onCloseModal();}setMousePressedOutside(false);},[mousePressedOutside,onCloseModal]);const backdropProps={[ModalLauncherPortalAttributeName]:true};return jsx(View,{ref:backdropRef,style:[styles$5.modalPositioner,style],onMouseDown:handleMouseDown,onMouseUp:handleMouseUp,testId:testId,...backdropProps,children:children})};const styles$5=StyleSheet.create({modalPositioner:{position:"fixed",insetInlineStart:0,insetBlockStart:0,width:"100%",height:"100%",alignItems:"center",justifyContent:"center",overflow:"auto",background:semanticColor.core.background.overlay.default}});
33
33
 
34
34
  const needsHackyMobileSafariScrollDisabler=(()=>{if(typeof window==="undefined"){return false}const userAgent=window.navigator.userAgent;return userAgent.indexOf("iPad")>-1||userAgent.indexOf("iPhone")>-1})();let numModalsOpened=0;let oldOverflow;let oldPosition;let oldScrollY;let oldWidth;let oldTop;const ScrollDisabler=_props=>{React.useEffect(()=>{if(numModalsOpened===0){const body=document.body;if(!body){throw new Error("couldn't find document.body")}oldOverflow=body.style.overflow;oldScrollY=window.scrollY;if(needsHackyMobileSafariScrollDisabler){oldPosition=body.style.position;oldWidth=body.style.width;oldTop=body.style.top;}body.style.overflow="hidden";if(needsHackyMobileSafariScrollDisabler){body.style.position="fixed";body.style.width="100%";body.style.top=`${-oldScrollY}px`;}}numModalsOpened++;return ()=>{numModalsOpened--;if(numModalsOpened===0){const body=document.body;if(!body){throw new Error("couldn't find document.body")}body.style.overflow=oldOverflow;if(needsHackyMobileSafariScrollDisabler){body.style.position=oldPosition;body.style.width=oldWidth;body.style.top=oldTop;}if(typeof window!=="undefined"&&window.scrollTo){window.scrollTo(0,oldScrollY);}}}},[]);return null};
35
35
 
36
36
  const defaultContext={closeModal:undefined};const ModalContext=React.createContext(defaultContext);ModalContext.displayName="ModalContext";
37
37
 
38
- const ModalLauncher=props=>{const{backdropDismissEnabled=true,children,closedFocusId,initialFocusId,modal,onClose,opened:controlledOpened,schedule,testId}=props;const lastElementFocusedOutsideModalRef=React.useRef(null);const[opened,setOpened]=React.useState(false);const isOpened=typeof controlledOpened==="boolean"?controlledOpened:opened;React.useEffect(()=>{if(typeof controlledOpened==="boolean"&&children){console.warn("'children' and 'opened' can't be used together");}if(typeof controlledOpened==="boolean"&&!onClose){console.warn("'onClose' should be used with 'opened'");}if(typeof controlledOpened!=="boolean"&&!children){console.warn("either 'children' or 'opened' must be set");}},[controlledOpened,children,onClose]);const saveLastElementFocused=React.useCallback(()=>{lastElementFocusedOutsideModalRef.current=document.activeElement;},[]);React.useEffect(()=>{if(!opened&&controlledOpened){saveLastElementFocused();}},[controlledOpened,opened,saveLastElementFocused]);const openModal=React.useCallback(()=>{saveLastElementFocused();setOpened(true);},[saveLastElementFocused]);const returnFocus=React.useCallback(()=>{if(closedFocusId){const focusElement=ReactDOM.findDOMNode(document.getElementById(closedFocusId));if(focusElement){schedule.animationFrame(()=>focusElement.focus(),{schedulePolicy:SchedulePolicy.Immediately,clearPolicy:ClearPolicy.Resolve});return}}const lastElement=lastElementFocusedOutsideModalRef.current;if(lastElement!=null){schedule.animationFrame(()=>{lastElement.focus();});}},[closedFocusId,schedule]);const handleCloseModal=React.useCallback(()=>{setOpened(false);onClose?.();returnFocus();},[onClose,returnFocus]);const renderModal=React.useCallback(()=>{if(typeof modal==="function"){return modal({closeModal:handleCloseModal})}else {return modal}},[modal,handleCloseModal]);const renderedChildren=children?children({openModal}):null;const{body}=document;if(!body){return null}return jsxs(ModalContext.Provider,{value:{closeModal:handleCloseModal},children:[renderedChildren,isOpened&&ReactDOM.createPortal(jsx(FocusTrap,{style:styles$4.container,children:jsx(ModalBackdrop,{initialFocusId:initialFocusId,testId:testId,onCloseModal:backdropDismissEnabled?handleCloseModal:()=>{},children:renderModal()})}),body),isOpened&&jsx(ModalLauncherKeypressListener,{onClose:handleCloseModal}),isOpened&&jsx(ScrollDisabler,{})]})};const ModalLauncherKeypressListener=({onClose})=>{const handleKeyup=React.useCallback(e=>{if(e.key==="Escape"){e.preventDefault();e.stopPropagation();onClose();}},[onClose]);React.useEffect(()=>{window.addEventListener("keyup",handleKeyup);return ()=>{window.removeEventListener("keyup",handleKeyup);}},[handleKeyup]);return null};const styles$4=StyleSheet.create({container:{zIndex:1080}});var modalLauncher = withActionScheduler(ModalLauncher);
38
+ const ModalLauncher=props=>{const{backdropDismissEnabled=true,children,closedFocusId,initialFocusId,modal,onClose,opened:controlledOpened,schedule,styles:stylesProp,testId}=props;const lastElementFocusedOutsideModalRef=React.useRef(null);const[opened,setOpened]=React.useState(false);const isOpened=typeof controlledOpened==="boolean"?controlledOpened:opened;React.useEffect(()=>{if(typeof controlledOpened==="boolean"&&children){console.warn("'children' and 'opened' can't be used together");}if(typeof controlledOpened==="boolean"&&!onClose){console.warn("'onClose' should be used with 'opened'");}if(typeof controlledOpened!=="boolean"&&!children){console.warn("either 'children' or 'opened' must be set");}},[controlledOpened,children,onClose]);const saveLastElementFocused=React.useCallback(()=>{lastElementFocusedOutsideModalRef.current=document.activeElement;},[]);React.useEffect(()=>{if(!opened&&controlledOpened){saveLastElementFocused();}},[controlledOpened,opened,saveLastElementFocused]);const openModal=React.useCallback(()=>{saveLastElementFocused();setOpened(true);},[saveLastElementFocused]);const returnFocus=React.useCallback(()=>{if(closedFocusId){const focusElement=ReactDOM.findDOMNode(document.getElementById(closedFocusId));if(focusElement){schedule.animationFrame(()=>focusElement.focus(),{schedulePolicy:SchedulePolicy.Immediately,clearPolicy:ClearPolicy.Resolve});return}}const lastElement=lastElementFocusedOutsideModalRef.current;if(lastElement!=null){schedule.animationFrame(()=>{lastElement.focus();});}},[closedFocusId,schedule]);const handleCloseModal=React.useCallback(()=>{setOpened(false);onClose?.();returnFocus();},[onClose,returnFocus]);const renderModal=React.useCallback(()=>{if(typeof modal==="function"){return modal({closeModal:handleCloseModal})}else {return modal}},[modal,handleCloseModal]);const renderedChildren=children?children({openModal}):null;const{body}=document;if(!body){return null}return jsxs(ModalContext.Provider,{value:{closeModal:handleCloseModal},children:[renderedChildren,isOpened&&ReactDOM.createPortal(jsx(FocusTrap,{style:styles$4.container,children:jsx(ModalBackdrop,{initialFocusId:initialFocusId,testId:testId,style:stylesProp?.backdrop,onCloseModal:backdropDismissEnabled?handleCloseModal:()=>{},children:renderModal()})}),body),isOpened&&jsx(ModalLauncherKeypressListener,{onClose:handleCloseModal}),isOpened&&jsx(ScrollDisabler,{})]})};const ModalLauncherKeypressListener=({onClose})=>{const handleKeyup=React.useCallback(e=>{if(e.key==="Escape"){e.preventDefault();e.stopPropagation();onClose();}},[onClose]);React.useEffect(()=>{window.addEventListener("keyup",handleKeyup);return ()=>{window.removeEventListener("keyup",handleKeyup);}},[handleKeyup]);return null};const styles$4=StyleSheet.create({container:{zIndex:1080}});var modalLauncher = withActionScheduler(ModalLauncher);
39
39
 
40
40
  function ModalContent(props){const{scrollOverflow,style,children,applySmallHeightStyles=true}=props;return jsx(View,{style:[styles$3.wrapper,scrollOverflow&&styles$3.scrollOverflow,applySmallHeightStyles&&styles$3.wrapperSmallHeight],children:jsx(View,{style:[styles$3.content,applySmallHeightStyles&&styles$3.contentSmallHeight,style],children:children})})}ModalContent.__IS_MODAL_CONTENT__=true;ModalContent.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_CONTENT__};const styles$3=StyleSheet.create({wrapper:{flex:1,display:"block"},wrapperSmallHeight:{[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minBlockSize:"unset",overflow:"unset"}},scrollOverflow:{overflow:"auto"},content:{flex:1,minBlockSize:"100%",padding:theme.panel.layout.gap.default,boxSizing:"border-box",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.panel.layout.gap.small}},contentSmallHeight:{[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minBlockSize:"unset",overflow:"unset"}}});ModalContent.defaultProps={scrollOverflow:true,applySmallHeightStyles:true};
41
41
 
package/dist/index.js CHANGED
@@ -58,13 +58,13 @@ const FOCUSABLE_ELEMENTS$1='button, [href], input, select, textarea, [tabindex]:
58
58
 
59
59
  const FOCUSABLE_ELEMENTS="a[href], details, input, textarea, select, button";function findFocusableNodes(root){return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS))}
60
60
 
61
- const getInitialFocusElement=(node,initialFocusId)=>{if(!initialFocusId){return null}return ReactDOM__namespace.findDOMNode(node.querySelector(`#${initialFocusId}`))};const getFirstFocusableElement=node=>{const focusableElements=findFocusableNodes(node);if(!focusableElements){return null}return focusableElements[0]};const getDialogElement=node=>{const dialogElement=ReactDOM__namespace.findDOMNode(node.querySelector('[role="dialog"]'));dialogElement?.setAttribute("tabindex","-1");return dialogElement};const ModalBackdrop=({children,initialFocusId,onCloseModal,testId})=>{const backdropRef=React__namespace.useRef(null);const[mousePressedOutside,setMousePressedOutside]=React__namespace.useState(false);React__namespace.useEffect(()=>{const node=ReactDOM__namespace.findDOMNode(backdropRef.current);if(!node){return}const firstFocusableElement=getInitialFocusElement(node,initialFocusId)||getFirstFocusableElement(node)||getDialogElement(node);setTimeout(()=>{firstFocusableElement?.focus();},0);},[initialFocusId]);const handleMouseDown=React__namespace.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");setMousePressedOutside(isBackdropClick||isPaddingLayerClick);},[]);const handleMouseUp=React__namespace.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");if((isBackdropClick||isPaddingLayerClick)&&mousePressedOutside){onCloseModal();}setMousePressedOutside(false);},[mousePressedOutside,onCloseModal]);const backdropProps={[ModalLauncherPortalAttributeName]:true};return jsxRuntime.jsx(wonderBlocksCore.View,{ref:backdropRef,style:styles$5.modalPositioner,onMouseDown:handleMouseDown,onMouseUp:handleMouseUp,testId:testId,...backdropProps,children:children})};const styles$5=aphrodite.StyleSheet.create({modalPositioner:{position:"fixed",insetInlineStart:0,insetBlockStart:0,width:"100%",height:"100%",alignItems:"center",justifyContent:"center",overflow:"auto",background:wonderBlocksTokens.semanticColor.core.background.overlay.default}});
61
+ const getInitialFocusElement=(node,initialFocusId)=>{if(!initialFocusId){return null}return ReactDOM__namespace.findDOMNode(node.querySelector(`#${initialFocusId}`))};const getFirstFocusableElement=node=>{const focusableElements=findFocusableNodes(node);if(!focusableElements){return null}return focusableElements[0]};const getDialogElement=node=>{const dialogElement=ReactDOM__namespace.findDOMNode(node.querySelector('[role="dialog"]'));dialogElement?.setAttribute("tabindex","-1");return dialogElement};const ModalBackdrop=({children,initialFocusId,onCloseModal,testId,style})=>{const backdropRef=React__namespace.useRef(null);const[mousePressedOutside,setMousePressedOutside]=React__namespace.useState(false);React__namespace.useEffect(()=>{const node=ReactDOM__namespace.findDOMNode(backdropRef.current);if(!node){return}const firstFocusableElement=getInitialFocusElement(node,initialFocusId)||getFirstFocusableElement(node)||getDialogElement(node);setTimeout(()=>{firstFocusableElement?.focus();},0);},[initialFocusId]);const handleMouseDown=React__namespace.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");setMousePressedOutside(isBackdropClick||isPaddingLayerClick);},[]);const handleMouseUp=React__namespace.useCallback(e=>{const target=e.target;const isBackdropClick=e.target===e.currentTarget;const isPaddingLayerClick=target?.hasAttribute?.("data-modal-padding-layer");if((isBackdropClick||isPaddingLayerClick)&&mousePressedOutside){onCloseModal();}setMousePressedOutside(false);},[mousePressedOutside,onCloseModal]);const backdropProps={[ModalLauncherPortalAttributeName]:true};return jsxRuntime.jsx(wonderBlocksCore.View,{ref:backdropRef,style:[styles$5.modalPositioner,style],onMouseDown:handleMouseDown,onMouseUp:handleMouseUp,testId:testId,...backdropProps,children:children})};const styles$5=aphrodite.StyleSheet.create({modalPositioner:{position:"fixed",insetInlineStart:0,insetBlockStart:0,width:"100%",height:"100%",alignItems:"center",justifyContent:"center",overflow:"auto",background:wonderBlocksTokens.semanticColor.core.background.overlay.default}});
62
62
 
63
63
  const needsHackyMobileSafariScrollDisabler=(()=>{if(typeof window==="undefined"){return false}const userAgent=window.navigator.userAgent;return userAgent.indexOf("iPad")>-1||userAgent.indexOf("iPhone")>-1})();let numModalsOpened=0;let oldOverflow;let oldPosition;let oldScrollY;let oldWidth;let oldTop;const ScrollDisabler=_props=>{React__namespace.useEffect(()=>{if(numModalsOpened===0){const body=document.body;if(!body){throw new Error("couldn't find document.body")}oldOverflow=body.style.overflow;oldScrollY=window.scrollY;if(needsHackyMobileSafariScrollDisabler){oldPosition=body.style.position;oldWidth=body.style.width;oldTop=body.style.top;}body.style.overflow="hidden";if(needsHackyMobileSafariScrollDisabler){body.style.position="fixed";body.style.width="100%";body.style.top=`${-oldScrollY}px`;}}numModalsOpened++;return ()=>{numModalsOpened--;if(numModalsOpened===0){const body=document.body;if(!body){throw new Error("couldn't find document.body")}body.style.overflow=oldOverflow;if(needsHackyMobileSafariScrollDisabler){body.style.position=oldPosition;body.style.width=oldWidth;body.style.top=oldTop;}if(typeof window!=="undefined"&&window.scrollTo){window.scrollTo(0,oldScrollY);}}}},[]);return null};
64
64
 
65
65
  const defaultContext={closeModal:undefined};const ModalContext=React__namespace.createContext(defaultContext);ModalContext.displayName="ModalContext";
66
66
 
67
- const ModalLauncher=props=>{const{backdropDismissEnabled=true,children,closedFocusId,initialFocusId,modal,onClose,opened:controlledOpened,schedule,testId}=props;const lastElementFocusedOutsideModalRef=React__namespace.useRef(null);const[opened,setOpened]=React__namespace.useState(false);const isOpened=typeof controlledOpened==="boolean"?controlledOpened:opened;React__namespace.useEffect(()=>{if(typeof controlledOpened==="boolean"&&children){console.warn("'children' and 'opened' can't be used together");}if(typeof controlledOpened==="boolean"&&!onClose){console.warn("'onClose' should be used with 'opened'");}if(typeof controlledOpened!=="boolean"&&!children){console.warn("either 'children' or 'opened' must be set");}},[controlledOpened,children,onClose]);const saveLastElementFocused=React__namespace.useCallback(()=>{lastElementFocusedOutsideModalRef.current=document.activeElement;},[]);React__namespace.useEffect(()=>{if(!opened&&controlledOpened){saveLastElementFocused();}},[controlledOpened,opened,saveLastElementFocused]);const openModal=React__namespace.useCallback(()=>{saveLastElementFocused();setOpened(true);},[saveLastElementFocused]);const returnFocus=React__namespace.useCallback(()=>{if(closedFocusId){const focusElement=ReactDOM__namespace.findDOMNode(document.getElementById(closedFocusId));if(focusElement){schedule.animationFrame(()=>focusElement.focus(),{schedulePolicy:wonderBlocksTiming.SchedulePolicy.Immediately,clearPolicy:wonderBlocksTiming.ClearPolicy.Resolve});return}}const lastElement=lastElementFocusedOutsideModalRef.current;if(lastElement!=null){schedule.animationFrame(()=>{lastElement.focus();});}},[closedFocusId,schedule]);const handleCloseModal=React__namespace.useCallback(()=>{setOpened(false);onClose?.();returnFocus();},[onClose,returnFocus]);const renderModal=React__namespace.useCallback(()=>{if(typeof modal==="function"){return modal({closeModal:handleCloseModal})}else {return modal}},[modal,handleCloseModal]);const renderedChildren=children?children({openModal}):null;const{body}=document;if(!body){return null}return jsxRuntime.jsxs(ModalContext.Provider,{value:{closeModal:handleCloseModal},children:[renderedChildren,isOpened&&ReactDOM__namespace.createPortal(jsxRuntime.jsx(FocusTrap,{style:styles$4.container,children:jsxRuntime.jsx(ModalBackdrop,{initialFocusId:initialFocusId,testId:testId,onCloseModal:backdropDismissEnabled?handleCloseModal:()=>{},children:renderModal()})}),body),isOpened&&jsxRuntime.jsx(ModalLauncherKeypressListener,{onClose:handleCloseModal}),isOpened&&jsxRuntime.jsx(ScrollDisabler,{})]})};const ModalLauncherKeypressListener=({onClose})=>{const handleKeyup=React__namespace.useCallback(e=>{if(e.key==="Escape"){e.preventDefault();e.stopPropagation();onClose();}},[onClose]);React__namespace.useEffect(()=>{window.addEventListener("keyup",handleKeyup);return ()=>{window.removeEventListener("keyup",handleKeyup);}},[handleKeyup]);return null};const styles$4=aphrodite.StyleSheet.create({container:{zIndex:1080}});var modalLauncher = wonderBlocksTiming.withActionScheduler(ModalLauncher);
67
+ const ModalLauncher=props=>{const{backdropDismissEnabled=true,children,closedFocusId,initialFocusId,modal,onClose,opened:controlledOpened,schedule,styles:stylesProp,testId}=props;const lastElementFocusedOutsideModalRef=React__namespace.useRef(null);const[opened,setOpened]=React__namespace.useState(false);const isOpened=typeof controlledOpened==="boolean"?controlledOpened:opened;React__namespace.useEffect(()=>{if(typeof controlledOpened==="boolean"&&children){console.warn("'children' and 'opened' can't be used together");}if(typeof controlledOpened==="boolean"&&!onClose){console.warn("'onClose' should be used with 'opened'");}if(typeof controlledOpened!=="boolean"&&!children){console.warn("either 'children' or 'opened' must be set");}},[controlledOpened,children,onClose]);const saveLastElementFocused=React__namespace.useCallback(()=>{lastElementFocusedOutsideModalRef.current=document.activeElement;},[]);React__namespace.useEffect(()=>{if(!opened&&controlledOpened){saveLastElementFocused();}},[controlledOpened,opened,saveLastElementFocused]);const openModal=React__namespace.useCallback(()=>{saveLastElementFocused();setOpened(true);},[saveLastElementFocused]);const returnFocus=React__namespace.useCallback(()=>{if(closedFocusId){const focusElement=ReactDOM__namespace.findDOMNode(document.getElementById(closedFocusId));if(focusElement){schedule.animationFrame(()=>focusElement.focus(),{schedulePolicy:wonderBlocksTiming.SchedulePolicy.Immediately,clearPolicy:wonderBlocksTiming.ClearPolicy.Resolve});return}}const lastElement=lastElementFocusedOutsideModalRef.current;if(lastElement!=null){schedule.animationFrame(()=>{lastElement.focus();});}},[closedFocusId,schedule]);const handleCloseModal=React__namespace.useCallback(()=>{setOpened(false);onClose?.();returnFocus();},[onClose,returnFocus]);const renderModal=React__namespace.useCallback(()=>{if(typeof modal==="function"){return modal({closeModal:handleCloseModal})}else {return modal}},[modal,handleCloseModal]);const renderedChildren=children?children({openModal}):null;const{body}=document;if(!body){return null}return jsxRuntime.jsxs(ModalContext.Provider,{value:{closeModal:handleCloseModal},children:[renderedChildren,isOpened&&ReactDOM__namespace.createPortal(jsxRuntime.jsx(FocusTrap,{style:styles$4.container,children:jsxRuntime.jsx(ModalBackdrop,{initialFocusId:initialFocusId,testId:testId,style:stylesProp?.backdrop,onCloseModal:backdropDismissEnabled?handleCloseModal:()=>{},children:renderModal()})}),body),isOpened&&jsxRuntime.jsx(ModalLauncherKeypressListener,{onClose:handleCloseModal}),isOpened&&jsxRuntime.jsx(ScrollDisabler,{})]})};const ModalLauncherKeypressListener=({onClose})=>{const handleKeyup=React__namespace.useCallback(e=>{if(e.key==="Escape"){e.preventDefault();e.stopPropagation();onClose();}},[onClose]);React__namespace.useEffect(()=>{window.addEventListener("keyup",handleKeyup);return ()=>{window.removeEventListener("keyup",handleKeyup);}},[handleKeyup]);return null};const styles$4=aphrodite.StyleSheet.create({container:{zIndex:1080}});var modalLauncher = wonderBlocksTiming.withActionScheduler(ModalLauncher);
68
68
 
69
69
  function ModalContent(props){const{scrollOverflow,style,children,applySmallHeightStyles=true}=props;return jsxRuntime.jsx(wonderBlocksCore.View,{style:[styles$3.wrapper,scrollOverflow&&styles$3.scrollOverflow,applySmallHeightStyles&&styles$3.wrapperSmallHeight],children:jsxRuntime.jsx(wonderBlocksCore.View,{style:[styles$3.content,applySmallHeightStyles&&styles$3.contentSmallHeight,style],children:children})})}ModalContent.__IS_MODAL_CONTENT__=true;ModalContent.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_CONTENT__};const styles$3=aphrodite.StyleSheet.create({wrapper:{flex:1,display:"block"},wrapperSmallHeight:{[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minBlockSize:"unset",overflow:"unset"}},scrollOverflow:{overflow:"auto"},content:{flex:1,minBlockSize:"100%",padding:theme.panel.layout.gap.default,boxSizing:"border-box",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.panel.layout.gap.small}},contentSmallHeight:{[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minBlockSize:"unset",overflow:"unset"}}});ModalContent.defaultProps={scrollOverflow:true,applySmallHeightStyles:true};
70
70
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "8.8.4",
6
+ "version": "8.9.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },