@khanacademy/wonder-blocks-modal 0.0.0-PR2918-20260106212409 → 0.0.0-PR2918-20260108160834

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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # @khanacademy/wonder-blocks-modal
2
2
 
3
- ## 0.0.0-PR2918-20260106212409
3
+ ## 0.0.0-PR2918-20260108160834
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - @khanacademy/wonder-blocks-icon-button@0.0.0-PR2918-20260106212409
7
+ - f6457be: Adjust scroll behavior for small screens in DrawerDialog and FlexibleDialog
8
+ - @khanacademy/wonder-blocks-icon-button@0.0.0-PR2918-20260108160834
8
9
 
9
10
  ## 8.5.10
10
11
 
@@ -7,6 +7,13 @@ type Props = {
7
7
  children: React.ReactNode;
8
8
  /** Optional styling to apply to the contents. */
9
9
  style?: StyleType;
10
+ /**
11
+ * When true, allows the small-height media query to unset overflow/flex behavior.
12
+ * This fixes layout issues in OnePaneDialog on small screens, but should be
13
+ * disabled for FlexibleDialog/DrawerDialog which need scrolling at all times.
14
+ * @defaultValue true
15
+ */
16
+ applySmallHeightStyles?: boolean;
10
17
  };
11
18
  /**
12
19
  * The Modal content included after the header
@@ -17,6 +24,7 @@ declare namespace ModalContent {
17
24
  var isComponentOf: (instance: any) => boolean;
18
25
  var defaultProps: {
19
26
  scrollOverflow: boolean;
27
+ applySmallHeightStyles: boolean;
20
28
  };
21
29
  }
22
30
  export default ModalContent;
package/dist/es/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { View, Id } from '@khanacademy/wonder-blocks-core';
4
4
  import { StyleSheet } from 'aphrodite';
@@ -16,9 +16,9 @@ const theme$1={root:{border:{radius:border.radius.radius_040}},dialog:{layout:{p
16
16
 
17
17
  var theme = mapValuesToCssVars(theme$1,"--wb-c-modal-");
18
18
 
19
- const ModalDialog=React.forwardRef(function ModalDialog(props,ref){const{above,below,role="dialog",style,children,testId,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy}=props;return jsxs(View,{style:[componentStyles$2.wrapper,style],children:[below&&jsx(View,{style:componentStyles$2.below,children:below}),jsx(View,{role:role,"aria-modal":"true","aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:[componentStyles$2.dialog],testId:testId,children:children}),above&&jsx(View,{style:componentStyles$2.above,children:above})]})});const componentStyles$2=StyleSheet.create({wrapper:{color:semanticColor.core.foreground.neutral.strong,flexDirection:"row",alignItems:"stretch",width:"100%",height:"100%",position:"relative",boxShadow:theme.dialog.shadow.default,borderRadius:theme.root.border.radius,[modalMediaQuery.midOrSmaller]:{padding:theme.dialog.layout.padding,flexDirection:"column"},[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden",[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},above:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:1},below:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:-1}});ModalDialog.displayName="ModalDialog";
19
+ const ModalDialog=React.forwardRef(function ModalDialog(props,ref){const{above,below,role="dialog",style,children,testId,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy}=props;return jsx(View,{style:componentStyles$2.paddingLayer,children:jsxs(View,{style:[componentStyles$2.wrapper,style],children:[below&&jsx(View,{style:componentStyles$2.below,children:below}),jsx(View,{role:role,"aria-modal":"true","aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:[componentStyles$2.dialog],testId:testId,children:children}),above&&jsx(View,{style:componentStyles$2.above,children:above})]})})});const componentStyles$2=StyleSheet.create({paddingLayer:{alignItems:"center",justifyContent:"center",height:"100%",width:"100%",[modalMediaQuery.midOrSmaller]:{padding:theme.dialog.layout.padding}},wrapper:{color:semanticColor.core.foreground.neutral.strong,flexDirection:"row",alignItems:"stretch",width:"100%",height:"100%",position:"relative",boxShadow:theme.dialog.shadow.default,borderRadius:theme.root.border.radius,[modalMediaQuery.midOrSmaller]:{flexDirection:"column"},[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden",[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},above:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:1},below:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:-1}});ModalDialog.displayName="ModalDialog";
20
20
 
21
- function ModalFooter({children}){return jsx(View,{style:styles$7.footer,children:children})}ModalFooter.__IS_MODAL_FOOTER__=true;ModalFooter.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_FOOTER__};const styles$7=StyleSheet.create({footer:{flex:"0 0 auto",boxSizing:"border-box",minHeight:sizing.size_640,paddingInline:theme.footer.layout.padding.inline,paddingBlock:theme.footer.layout.padding.block,display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"flex-end",boxShadow:`0px -1px 0px ${semanticColor.core.border.neutral.subtle}`}});
21
+ function ModalFooter({children}){return jsx(View,{style:styles$7.footer,children:children})}ModalFooter.__IS_MODAL_FOOTER__=true;ModalFooter.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_FOOTER__};const styles$7=StyleSheet.create({footer:{flex:"0 0 auto",boxSizing:"border-box",marginBlockStart:"auto",minHeight:sizing.size_640,paddingInline:theme.footer.layout.padding.inline,paddingBlock:theme.footer.layout.padding.block,display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"flex-end",boxShadow:`0px -1px 0px ${semanticColor.core.border.neutral.subtle}`}});
22
22
 
23
23
  function ModalHeader(props){const{breadcrumbs=undefined,subtitle=undefined,testId,title,titleId}=props;if(subtitle&&breadcrumbs){throw new Error("'subtitle' and 'breadcrumbs' can't be used together")}return jsxs(View,{style:[styles$6.header],testId:testId,children:[breadcrumbs&&jsx(View,{style:styles$6.breadcrumbs,children:breadcrumbs}),jsx(Heading,{size:"large",tag:"h2",style:styles$6.title,id:titleId,testId:testId&&`${testId}-title`,children:title}),subtitle&&jsx(BodyText,{size:"small",style:styles$6.subtitle,testId:testId&&`${testId}-subtitle`,children:subtitle})]})}const styles$6=StyleSheet.create({header:{boxShadow:`0px 1px 0px ${semanticColor.core.border.neutral.subtle}`,display:"flex",flexDirection:"column",minHeight:66,paddingBlock:theme.header.layout.padding.block,paddingInline:theme.header.layout.padding.inline.default,position:"relative",width:"100%",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.header.layout.padding.inline.small},[modalMediaQuery.smMinOrSmallerHeight]:{minHeight:"unset"}},breadcrumbs:{color:semanticColor.core.foreground.neutral.default,marginBlockEnd:theme.header.layout.gap.default},title:{paddingInlineEnd:theme.header.layout.gap.title.default,[modalMediaQuery.midOrSmaller]:{paddingInlineEnd:theme.header.layout.gap.title.small}},subtitle:{color:semanticColor.core.foreground.neutral.default,marginBlockStart:theme.header.layout.gap.default}});
24
24
 
@@ -34,7 +34,7 @@ const defaultContext={closeModal:undefined};const ModalContext=React.createConte
34
34
 
35
35
  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);
36
36
 
37
- function ModalContent(props){const{scrollOverflow,style,children}=props;return jsx(View,{style:[styles$3.wrapper,scrollOverflow&&styles$3.scrollOverflow],children:jsx(View,{style:[styles$3.content,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",[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minHeight:"unset",overflow:"unset"}},scrollOverflow:{overflow:"auto"},content:{flex:1,minHeight:"100%",padding:theme.panel.layout.gap.default,boxSizing:"border-box",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.panel.layout.gap.small},[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minHeight:"unset",overflow:"unset"}}});ModalContent.defaultProps={scrollOverflow:true};
37
+ 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",minHeight:"unset",overflow:"unset"}},scrollOverflow:{overflow:"auto"},content:{flex:1,minHeight:"100%",padding:theme.panel.layout.gap.default,boxSizing:"border-box",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.panel.layout.gap.small}},contentSmallHeight:{[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minHeight:"unset",overflow:"unset"}}});ModalContent.defaultProps={scrollOverflow:true,applySmallHeightStyles:true};
38
38
 
39
39
  const CloseButton=({onClick,style,testId})=>{return jsx(ModalContext.Consumer,{children:({closeModal})=>{if(closeModal&&onClick){throw new Error("You've specified 'onClose' on a modal when using ModalLauncher. Please specify 'onClose' on the ModalLauncher instead")}return jsx(IconButton,{icon:xIcon,"aria-label":"Close modal",onClick:onClick||closeModal,kind:"tertiary",actionType:"neutral",style:style,testId:testId})}})};
40
40
 
@@ -42,7 +42,7 @@ function ModalPanel({closeButtonVisible=true,scrollOverflow=true,content,footer,
42
42
 
43
43
  const renderHeader=(props,uniqueId)=>{const{title,breadcrumbs=undefined,subtitle=undefined,testId}=props;if(breadcrumbs){return jsx(ModalHeader,{title:title,breadcrumbs:breadcrumbs,titleId:uniqueId,testId:testId&&`${testId}-header`})}else if(subtitle){return jsx(ModalHeader,{title:title,subtitle:subtitle,titleId:uniqueId,testId:testId&&`${testId}-header`})}else {return jsx(ModalHeader,{title:title,titleId:uniqueId,testId:testId&&`${testId}-header`})}};const OnePaneDialog=props=>{const{onClose,footer,content,above,below,style,closeButtonVisible=true,testId,titleId,role,"aria-describedby":ariaDescribedBy}=props;return jsx(Id,{id:titleId,children:uniqueId=>jsx(ModalDialog,{style:[styles$1.dialog,style],above:above,below:below,testId:testId,"aria-labelledby":uniqueId,"aria-describedby":ariaDescribedBy,role:role,children:jsx(ModalPanel,{onClose:onClose,header:renderHeader(props,uniqueId),content:content,footer:footer,closeButtonVisible:closeButtonVisible,testId:testId})})})};const styles$1=StyleSheet.create({dialog:{maxInlineSize:576,width:"93.75%",height:"81.25%",maxBlockSize:624,[modalMediaQuery.midOrSmaller]:{width:"100%",height:"100%",overflow:"hidden"}}});
44
44
 
45
- function FlexiblePanel({closeButtonVisible=true,content,title,onClose,styles,testId}){const panelRef=React.useRef(null);const renderMainContent=React.useCallback(()=>{const contentNode=typeof content==="function"?content({title}):jsxs(Fragment,{children:[title,content]});const mainContent=ModalContent.isComponentOf(contentNode)?contentNode:jsx(ModalContent,{style:styles?.content,children:contentNode});if(!mainContent){return mainContent}return React.cloneElement(mainContent,{style:[mainContent.props.style]})},[title,content,styles?.content]);const mainContent=renderMainContent();const defaultBackgroundStyle={backgroundColor:semanticColor.core.background.base.default};const combinedBackgroundStyles={...defaultBackgroundStyle,...styles?.panel};return jsxs(View,{style:[componentStyles$1.wrapper,combinedBackgroundStyles],testId:testId&&`${testId}-panel`,ref:panelRef,children:[closeButtonVisible&&jsx(CloseButton,{onClick:onClose,style:[componentStyles$1.closeButton,styles?.closeButton],testId:testId&&`${testId}-close`}),mainContent]})}FlexiblePanel.defaultProps={closeButtonVisible:true};const componentStyles$1=StyleSheet.create({wrapper:{flex:"1 1 auto",flexDirection:"column",boxSizing:"border-box",overflow:"hidden",height:"100%",width:"100%"},closeButton:{position:"absolute",insetInlineEnd:theme.closeButton.layout.gapRight,top:theme.closeButton.layout.gapTop,zIndex:1,":focus":focusStyles.focus[":focus-visible"]}});
45
+ function FlexiblePanel({closeButtonVisible=true,content,title,onClose,styles,testId}){const panelRef=React.useRef(null);const renderMainContent=React.useCallback(()=>{const contentNode=typeof content==="function"?content({title}):jsxs(Fragment,{children:[title,content]});const mainContent=ModalContent.isComponentOf(contentNode)?contentNode:jsx(ModalContent,{style:styles?.content,applySmallHeightStyles:false,children:contentNode});if(!mainContent){return mainContent}return React.cloneElement(mainContent,{applySmallHeightStyles:false,style:[mainContent.props.style]})},[title,content,styles?.content]);const mainContent=renderMainContent();const defaultBackgroundStyle={backgroundColor:semanticColor.core.background.base.default};const combinedBackgroundStyles={...defaultBackgroundStyle,...styles?.panel};return jsxs(View,{style:[componentStyles$1.wrapper,combinedBackgroundStyles],testId:testId&&`${testId}-panel`,ref:panelRef,children:[closeButtonVisible&&jsx(CloseButton,{onClick:onClose,style:[componentStyles$1.closeButton,styles?.closeButton],testId:testId&&`${testId}-close`}),mainContent]})}FlexiblePanel.defaultProps={closeButtonVisible:true};const componentStyles$1=StyleSheet.create({wrapper:{flex:"1 1 auto",flexDirection:"column",boxSizing:"border-box",overflow:"hidden",height:"100%",width:"100%"},closeButton:{position:"absolute",insetInlineEnd:theme.closeButton.layout.gapRight,top:theme.closeButton.layout.gapTop,zIndex:1,":focus":focusStyles.focus[":focus-visible"]}});
46
46
 
47
47
  const FlexibleDialog=React.forwardRef(function FlexibleDialog(props,ref){const{onClose,title,content,styles,closeButtonVisible=true,testId,titleId,role="dialog",...accessibilityProps}=props;const uniqueId=React.useId();const headingId=titleId??uniqueId;const renderedTitle=title==null?null:typeof title==="string"?jsx(Heading,{id:headingId,children:title}):React.cloneElement(title,{id:headingId,testId:"title-heading-wrapper"});return jsx(View,{style:[componentStyles.root,styles?.root],children:jsx(View,{role:role,"aria-modal":"true","aria-label":accessibilityProps["aria-label"],"aria-labelledby":headingId,"aria-describedby":accessibilityProps["aria-describedby"],ref:ref,testId:testId,style:[componentStyles.dialog,styles?.dialog],children:jsx(FlexiblePanel,{styles:{panel:styles?.panel,content:styles?.content,closeButton:styles?.closeButton},onClose:onClose,title:renderedTitle,content:content,closeButtonVisible:closeButtonVisible,testId:testId})})})});const componentStyles=StyleSheet.create({root:{boxShadow:theme.dialog.shadow.default,color:semanticColor.core.foreground.neutral.strong,overflow:"auto",position:"relative",willChange:"transform, opacity",height:"auto",maxHeight:"100vh",maxWidth:576,width:"93.75%"}});
48
48
 
package/dist/index.js CHANGED
@@ -45,9 +45,9 @@ const theme$1={root:{border:{radius:wonderBlocksTokens.border.radius.radius_040}
45
45
 
46
46
  var theme = wonderBlocksTokens.mapValuesToCssVars(theme$1,"--wb-c-modal-");
47
47
 
48
- const ModalDialog=React__namespace.forwardRef(function ModalDialog(props,ref){const{above,below,role="dialog",style,children,testId,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy}=props;return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[componentStyles$2.wrapper,style],children:[below&&jsxRuntime.jsx(wonderBlocksCore.View,{style:componentStyles$2.below,children:below}),jsxRuntime.jsx(wonderBlocksCore.View,{role:role,"aria-modal":"true","aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:[componentStyles$2.dialog],testId:testId,children:children}),above&&jsxRuntime.jsx(wonderBlocksCore.View,{style:componentStyles$2.above,children:above})]})});const componentStyles$2=aphrodite.StyleSheet.create({wrapper:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.strong,flexDirection:"row",alignItems:"stretch",width:"100%",height:"100%",position:"relative",boxShadow:theme.dialog.shadow.default,borderRadius:theme.root.border.radius,[modalMediaQuery.midOrSmaller]:{padding:theme.dialog.layout.padding,flexDirection:"column"},[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden",[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},above:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:1},below:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:-1}});ModalDialog.displayName="ModalDialog";
48
+ const ModalDialog=React__namespace.forwardRef(function ModalDialog(props,ref){const{above,below,role="dialog",style,children,testId,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy}=props;return jsxRuntime.jsx(wonderBlocksCore.View,{style:componentStyles$2.paddingLayer,children:jsxRuntime.jsxs(wonderBlocksCore.View,{style:[componentStyles$2.wrapper,style],children:[below&&jsxRuntime.jsx(wonderBlocksCore.View,{style:componentStyles$2.below,children:below}),jsxRuntime.jsx(wonderBlocksCore.View,{role:role,"aria-modal":"true","aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:[componentStyles$2.dialog],testId:testId,children:children}),above&&jsxRuntime.jsx(wonderBlocksCore.View,{style:componentStyles$2.above,children:above})]})})});const componentStyles$2=aphrodite.StyleSheet.create({paddingLayer:{alignItems:"center",justifyContent:"center",height:"100%",width:"100%",[modalMediaQuery.midOrSmaller]:{padding:theme.dialog.layout.padding}},wrapper:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.strong,flexDirection:"row",alignItems:"stretch",width:"100%",height:"100%",position:"relative",boxShadow:theme.dialog.shadow.default,borderRadius:theme.root.border.radius,[modalMediaQuery.midOrSmaller]:{flexDirection:"column"},[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden",[modalMediaQuery.smMinOrSmallerHeight]:{overflow:"auto"}},above:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:1},below:{pointerEvents:"none",position:"absolute",top:0,left:0,bottom:0,right:0,zIndex:-1}});ModalDialog.displayName="ModalDialog";
49
49
 
50
- function ModalFooter({children}){return jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$7.footer,children:children})}ModalFooter.__IS_MODAL_FOOTER__=true;ModalFooter.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_FOOTER__};const styles$7=aphrodite.StyleSheet.create({footer:{flex:"0 0 auto",boxSizing:"border-box",minHeight:wonderBlocksTokens.sizing.size_640,paddingInline:theme.footer.layout.padding.inline,paddingBlock:theme.footer.layout.padding.block,display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"flex-end",boxShadow:`0px -1px 0px ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`}});
50
+ function ModalFooter({children}){return jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$7.footer,children:children})}ModalFooter.__IS_MODAL_FOOTER__=true;ModalFooter.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_FOOTER__};const styles$7=aphrodite.StyleSheet.create({footer:{flex:"0 0 auto",boxSizing:"border-box",marginBlockStart:"auto",minHeight:wonderBlocksTokens.sizing.size_640,paddingInline:theme.footer.layout.padding.inline,paddingBlock:theme.footer.layout.padding.block,display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"flex-end",boxShadow:`0px -1px 0px ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`}});
51
51
 
52
52
  function ModalHeader(props){const{breadcrumbs=undefined,subtitle=undefined,testId,title,titleId}=props;if(subtitle&&breadcrumbs){throw new Error("'subtitle' and 'breadcrumbs' can't be used together")}return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[styles$6.header],testId:testId,children:[breadcrumbs&&jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$6.breadcrumbs,children:breadcrumbs}),jsxRuntime.jsx(wonderBlocksTypography.Heading,{size:"large",tag:"h2",style:styles$6.title,id:titleId,testId:testId&&`${testId}-title`,children:title}),subtitle&&jsxRuntime.jsx(wonderBlocksTypography.BodyText,{size:"small",style:styles$6.subtitle,testId:testId&&`${testId}-subtitle`,children:subtitle})]})}const styles$6=aphrodite.StyleSheet.create({header:{boxShadow:`0px 1px 0px ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,display:"flex",flexDirection:"column",minHeight:66,paddingBlock:theme.header.layout.padding.block,paddingInline:theme.header.layout.padding.inline.default,position:"relative",width:"100%",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.header.layout.padding.inline.small},[modalMediaQuery.smMinOrSmallerHeight]:{minHeight:"unset"}},breadcrumbs:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,marginBlockEnd:theme.header.layout.gap.default},title:{paddingInlineEnd:theme.header.layout.gap.title.default,[modalMediaQuery.midOrSmaller]:{paddingInlineEnd:theme.header.layout.gap.title.small}},subtitle:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,marginBlockStart:theme.header.layout.gap.default}});
53
53
 
@@ -63,7 +63,7 @@ const defaultContext={closeModal:undefined};const ModalContext=React__namespace.
63
63
 
64
64
  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);
65
65
 
66
- function ModalContent(props){const{scrollOverflow,style,children}=props;return jsxRuntime.jsx(wonderBlocksCore.View,{style:[styles$3.wrapper,scrollOverflow&&styles$3.scrollOverflow],children:jsxRuntime.jsx(wonderBlocksCore.View,{style:[styles$3.content,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",[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minHeight:"unset",overflow:"unset"}},scrollOverflow:{overflow:"auto"},content:{flex:1,minHeight:"100%",padding:theme.panel.layout.gap.default,boxSizing:"border-box",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.panel.layout.gap.small},[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minHeight:"unset",overflow:"unset"}}});ModalContent.defaultProps={scrollOverflow:true};
66
+ 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",minHeight:"unset",overflow:"unset"}},scrollOverflow:{overflow:"auto"},content:{flex:1,minHeight:"100%",padding:theme.panel.layout.gap.default,boxSizing:"border-box",[modalMediaQuery.midOrSmaller]:{paddingInline:theme.panel.layout.gap.small}},contentSmallHeight:{[modalMediaQuery.smMinOrSmallerHeight]:{flex:"unset",minHeight:"unset",overflow:"unset"}}});ModalContent.defaultProps={scrollOverflow:true,applySmallHeightStyles:true};
67
67
 
68
68
  const CloseButton=({onClick,style,testId})=>{return jsxRuntime.jsx(ModalContext.Consumer,{children:({closeModal})=>{if(closeModal&&onClick){throw new Error("You've specified 'onClose' on a modal when using ModalLauncher. Please specify 'onClose' on the ModalLauncher instead")}return jsxRuntime.jsx(IconButton__default["default"],{icon:xIcon__default["default"],"aria-label":"Close modal",onClick:onClick||closeModal,kind:"tertiary",actionType:"neutral",style:style,testId:testId})}})};
69
69
 
@@ -71,7 +71,7 @@ function ModalPanel({closeButtonVisible=true,scrollOverflow=true,content,footer,
71
71
 
72
72
  const renderHeader=(props,uniqueId)=>{const{title,breadcrumbs=undefined,subtitle=undefined,testId}=props;if(breadcrumbs){return jsxRuntime.jsx(ModalHeader,{title:title,breadcrumbs:breadcrumbs,titleId:uniqueId,testId:testId&&`${testId}-header`})}else if(subtitle){return jsxRuntime.jsx(ModalHeader,{title:title,subtitle:subtitle,titleId:uniqueId,testId:testId&&`${testId}-header`})}else {return jsxRuntime.jsx(ModalHeader,{title:title,titleId:uniqueId,testId:testId&&`${testId}-header`})}};const OnePaneDialog=props=>{const{onClose,footer,content,above,below,style,closeButtonVisible=true,testId,titleId,role,"aria-describedby":ariaDescribedBy}=props;return jsxRuntime.jsx(wonderBlocksCore.Id,{id:titleId,children:uniqueId=>jsxRuntime.jsx(ModalDialog,{style:[styles$1.dialog,style],above:above,below:below,testId:testId,"aria-labelledby":uniqueId,"aria-describedby":ariaDescribedBy,role:role,children:jsxRuntime.jsx(ModalPanel,{onClose:onClose,header:renderHeader(props,uniqueId),content:content,footer:footer,closeButtonVisible:closeButtonVisible,testId:testId})})})};const styles$1=aphrodite.StyleSheet.create({dialog:{maxInlineSize:576,width:"93.75%",height:"81.25%",maxBlockSize:624,[modalMediaQuery.midOrSmaller]:{width:"100%",height:"100%",overflow:"hidden"}}});
73
73
 
74
- function FlexiblePanel({closeButtonVisible=true,content,title,onClose,styles,testId}){const panelRef=React__namespace.useRef(null);const renderMainContent=React__namespace.useCallback(()=>{const contentNode=typeof content==="function"?content({title}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[title,content]});const mainContent=ModalContent.isComponentOf(contentNode)?contentNode:jsxRuntime.jsx(ModalContent,{style:styles?.content,children:contentNode});if(!mainContent){return mainContent}return React__namespace.cloneElement(mainContent,{style:[mainContent.props.style]})},[title,content,styles?.content]);const mainContent=renderMainContent();const defaultBackgroundStyle={backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default};const combinedBackgroundStyles={...defaultBackgroundStyle,...styles?.panel};return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[componentStyles$1.wrapper,combinedBackgroundStyles],testId:testId&&`${testId}-panel`,ref:panelRef,children:[closeButtonVisible&&jsxRuntime.jsx(CloseButton,{onClick:onClose,style:[componentStyles$1.closeButton,styles?.closeButton],testId:testId&&`${testId}-close`}),mainContent]})}FlexiblePanel.defaultProps={closeButtonVisible:true};const componentStyles$1=aphrodite.StyleSheet.create({wrapper:{flex:"1 1 auto",flexDirection:"column",boxSizing:"border-box",overflow:"hidden",height:"100%",width:"100%"},closeButton:{position:"absolute",insetInlineEnd:theme.closeButton.layout.gapRight,top:theme.closeButton.layout.gapTop,zIndex:1,":focus":wonderBlocksStyles.focusStyles.focus[":focus-visible"]}});
74
+ function FlexiblePanel({closeButtonVisible=true,content,title,onClose,styles,testId}){const panelRef=React__namespace.useRef(null);const renderMainContent=React__namespace.useCallback(()=>{const contentNode=typeof content==="function"?content({title}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[title,content]});const mainContent=ModalContent.isComponentOf(contentNode)?contentNode:jsxRuntime.jsx(ModalContent,{style:styles?.content,applySmallHeightStyles:false,children:contentNode});if(!mainContent){return mainContent}return React__namespace.cloneElement(mainContent,{applySmallHeightStyles:false,style:[mainContent.props.style]})},[title,content,styles?.content]);const mainContent=renderMainContent();const defaultBackgroundStyle={backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default};const combinedBackgroundStyles={...defaultBackgroundStyle,...styles?.panel};return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[componentStyles$1.wrapper,combinedBackgroundStyles],testId:testId&&`${testId}-panel`,ref:panelRef,children:[closeButtonVisible&&jsxRuntime.jsx(CloseButton,{onClick:onClose,style:[componentStyles$1.closeButton,styles?.closeButton],testId:testId&&`${testId}-close`}),mainContent]})}FlexiblePanel.defaultProps={closeButtonVisible:true};const componentStyles$1=aphrodite.StyleSheet.create({wrapper:{flex:"1 1 auto",flexDirection:"column",boxSizing:"border-box",overflow:"hidden",height:"100%",width:"100%"},closeButton:{position:"absolute",insetInlineEnd:theme.closeButton.layout.gapRight,top:theme.closeButton.layout.gapTop,zIndex:1,":focus":wonderBlocksStyles.focusStyles.focus[":focus-visible"]}});
75
75
 
76
76
  const FlexibleDialog=React__namespace.forwardRef(function FlexibleDialog(props,ref){const{onClose,title,content,styles,closeButtonVisible=true,testId,titleId,role="dialog",...accessibilityProps}=props;const uniqueId=React__namespace.useId();const headingId=titleId??uniqueId;const renderedTitle=title==null?null:typeof title==="string"?jsxRuntime.jsx(wonderBlocksTypography.Heading,{id:headingId,children:title}):React__namespace.cloneElement(title,{id:headingId,testId:"title-heading-wrapper"});return jsxRuntime.jsx(wonderBlocksCore.View,{style:[componentStyles.root,styles?.root],children:jsxRuntime.jsx(wonderBlocksCore.View,{role:role,"aria-modal":"true","aria-label":accessibilityProps["aria-label"],"aria-labelledby":headingId,"aria-describedby":accessibilityProps["aria-describedby"],ref:ref,testId:testId,style:[componentStyles.dialog,styles?.dialog],children:jsxRuntime.jsx(FlexiblePanel,{styles:{panel:styles?.panel,content:styles?.content,closeButton:styles?.closeButton},onClose:onClose,title:renderedTitle,content:content,closeButtonVisible:closeButtonVisible,testId:testId})})})});const componentStyles=aphrodite.StyleSheet.create({root:{boxShadow:theme.dialog.shadow.default,color:wonderBlocksTokens.semanticColor.core.foreground.neutral.strong,overflow:"auto",position:"relative",willChange:"transform, opacity",height:"auto",maxHeight:"100vh",maxWidth:576,width:"93.75%"}});
77
77
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "0.0.0-PR2918-20260106212409",
6
+ "version": "0.0.0-PR2918-20260108160834",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@khanacademy/wonder-blocks-breadcrumbs": "3.2.9",
32
32
  "@khanacademy/wonder-blocks-core": "12.4.2",
33
- "@khanacademy/wonder-blocks-icon-button": "0.0.0-PR2918-20260106212409",
33
+ "@khanacademy/wonder-blocks-icon-button": "0.0.0-PR2918-20260108160834",
34
34
  "@khanacademy/wonder-blocks-layout": "3.1.42",
35
35
  "@khanacademy/wonder-blocks-styles": "0.2.37",
36
36
  "@khanacademy/wonder-blocks-timing": "7.0.4",