@khanacademy/wonder-blocks-modal 8.1.9 → 8.2.1
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/.turbo/turbo-build$colon$css.log +1 -1
- package/CHANGELOG.md +17 -0
- package/dist/components/flexible-dialog.d.ts +99 -0
- package/dist/components/flexible-panel.d.ts +70 -0
- package/dist/components/modal-dialog.d.ts +5 -0
- package/dist/es/index.js +8 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +6 -1
- package/package.json +6 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @khanacademy/wonder-blocks-modal@8.1
|
|
2
|
+
> @khanacademy/wonder-blocks-modal@8.2.1 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,22 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-modal
|
|
2
2
|
|
|
3
|
+
## 8.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [1334e74]
|
|
8
|
+
- @khanacademy/wonder-blocks-core@12.4.0
|
|
9
|
+
- @khanacademy/wonder-blocks-breadcrumbs@3.1.32
|
|
10
|
+
- @khanacademy/wonder-blocks-icon-button@10.3.16
|
|
11
|
+
- @khanacademy/wonder-blocks-layout@3.1.32
|
|
12
|
+
- @khanacademy/wonder-blocks-typography@4.2.17
|
|
13
|
+
|
|
14
|
+
## 8.2.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 72e9eed: Add new FlexibleModal variant for more flexible implementations
|
|
19
|
+
|
|
3
20
|
## 8.1.9
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
|
+
type AccessibleDialogProps = {
|
|
4
|
+
title: React.ReactElement | string;
|
|
5
|
+
"aria-label"?: never;
|
|
6
|
+
"aria-labelledby"?: string;
|
|
7
|
+
} | {
|
|
8
|
+
title?: never;
|
|
9
|
+
"aria-label": string;
|
|
10
|
+
"aria-labelledby"?: never;
|
|
11
|
+
} | {
|
|
12
|
+
title?: never;
|
|
13
|
+
"aria-label"?: never;
|
|
14
|
+
"aria-labelledby": string;
|
|
15
|
+
};
|
|
16
|
+
type Props = AccessibleDialogProps & {
|
|
17
|
+
/**
|
|
18
|
+
* An optional id parameter for the main heading. If one is not provided,
|
|
19
|
+
* an ID will be generated.
|
|
20
|
+
*/
|
|
21
|
+
titleId?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The content of the modal. Supports a render prop for placing the title in a slot.
|
|
24
|
+
*/
|
|
25
|
+
content: React.ReactElement | ((slots: RenderProps) => React.ReactElement);
|
|
26
|
+
/**
|
|
27
|
+
* Called when the close button is clicked.
|
|
28
|
+
*
|
|
29
|
+
* If you're using `ModalLauncher`, you probably shouldn't use this prop!
|
|
30
|
+
* Instead, to listen for when the modal closes, add an `onClose` handler
|
|
31
|
+
* to the `ModalLauncher`. Doing so will result in a console.warn().
|
|
32
|
+
*/
|
|
33
|
+
onClose?: () => unknown;
|
|
34
|
+
/**
|
|
35
|
+
* When true, the close button is shown; otherwise, the close button is not shown.
|
|
36
|
+
*/
|
|
37
|
+
closeButtonVisible?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* When set, overrides the default role value. Default role is "dialog"
|
|
40
|
+
* Roles other than dialog and alertdialog aren't appropriate for this
|
|
41
|
+
* component
|
|
42
|
+
*/
|
|
43
|
+
role?: "dialog" | "alertdialog";
|
|
44
|
+
/**
|
|
45
|
+
* Optional custom styles.
|
|
46
|
+
*/
|
|
47
|
+
styles?: {
|
|
48
|
+
root?: StyleType;
|
|
49
|
+
panel?: StyleType;
|
|
50
|
+
closeButton?: StyleType;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Test ID used for e2e testing. This ID will be passed down to the Dialog.
|
|
54
|
+
*/
|
|
55
|
+
testId?: string;
|
|
56
|
+
/**
|
|
57
|
+
* The ID of the content describing this dialog, if applicable.
|
|
58
|
+
*/
|
|
59
|
+
"aria-describedby"?: string;
|
|
60
|
+
};
|
|
61
|
+
type RenderProps = {
|
|
62
|
+
title: React.ReactNode | string;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* A more flexible modal variant with fewer layout constraints. It can receive
|
|
66
|
+
* a custom background (image or color), a title for the main heading, and that
|
|
67
|
+
* title can optionally render in the content area through a render prop.
|
|
68
|
+
*
|
|
69
|
+
* One of the following is required for labeling the dialog:
|
|
70
|
+
* - title content (React element or string)
|
|
71
|
+
* - aria-label (string)
|
|
72
|
+
* - aria-labelledby (string ID reference)
|
|
73
|
+
*
|
|
74
|
+
* ### Usage
|
|
75
|
+
*
|
|
76
|
+
* ```jsx
|
|
77
|
+
* import {FlexibleDialog} from "@khanacademy/wonder-blocks-modal";
|
|
78
|
+
* import {BodyText} from "@khanacademy/wonder-blocks-typography";
|
|
79
|
+
*
|
|
80
|
+
* <FlexibleDialog
|
|
81
|
+
* title={<Heading size="xxlarge" id="main-heading">Select mission</Heading>}
|
|
82
|
+
* content={
|
|
83
|
+
* <BodyText>
|
|
84
|
+
* {`Lorem ipsum dolor sit amet, consectetur adipiscing
|
|
85
|
+
* elit, sed do eiusmod tempor incididunt ut labore et
|
|
86
|
+
* dolore magna aliqua. Ut enim ad minim veniam,
|
|
87
|
+
* quis nostrud exercitation ullamco laboris nisi ut
|
|
88
|
+
* aliquip ex ea commodo consequat. Duis aute irure
|
|
89
|
+
* dolor in reprehenderit in voluptate velit esse
|
|
90
|
+
* cillum dolore eu fugiat nulla pariatur. Excepteur
|
|
91
|
+
* sint occaecat cupidatat non proident, sunt in culpa
|
|
92
|
+
* qui officia deserunt mollit anim id est.`}
|
|
93
|
+
* </BodyText>
|
|
94
|
+
* }
|
|
95
|
+
* />
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
declare const FlexibleDialog: ({ onClose, title, content, styles, closeButtonVisible, testId, titleId, role, ...accessibilityProps }: Props) => React.ReactElement;
|
|
99
|
+
export default FlexibleDialog;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { PropsFor } from "@khanacademy/wonder-blocks-core";
|
|
3
|
+
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
4
|
+
import ModalContent from "./modal-content";
|
|
5
|
+
type RenderProps = {
|
|
6
|
+
title: React.ReactNode | string;
|
|
7
|
+
};
|
|
8
|
+
type Props = {
|
|
9
|
+
/**
|
|
10
|
+
* The main heading of the FlexiblePanel. Used to label the dialog.
|
|
11
|
+
*/
|
|
12
|
+
title?: React.ReactNode | string;
|
|
13
|
+
/**
|
|
14
|
+
* The main contents of the FlexiblePanel. All other parts of the panel
|
|
15
|
+
* are positioned around it.
|
|
16
|
+
*/
|
|
17
|
+
content: React.ReactElement<PropsFor<typeof ModalContent>> | ((slots: RenderProps) => React.ReactElement) | React.ReactElement;
|
|
18
|
+
/**
|
|
19
|
+
* When true, the close button is shown; otherwise, the close button is not shown.
|
|
20
|
+
*/
|
|
21
|
+
closeButtonVisible: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Any optional styling to apply to the root (panel background) and close button.
|
|
24
|
+
*/
|
|
25
|
+
styles?: {
|
|
26
|
+
root?: StyleType;
|
|
27
|
+
closeButton?: StyleType;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Called when the close button is clicked.
|
|
31
|
+
*
|
|
32
|
+
* If you're using `ModalLauncher`, you should not use this prop!
|
|
33
|
+
* Instead, to listen for when the modal closes, add an `onClose` handler
|
|
34
|
+
* to the `ModalLauncher`. Doing so will throw an error.
|
|
35
|
+
*/
|
|
36
|
+
onClose?: () => unknown;
|
|
37
|
+
/**
|
|
38
|
+
* Test ID used for e2e testing.
|
|
39
|
+
*
|
|
40
|
+
* In this case, this `testId` comes from the `testId` prop defined in the
|
|
41
|
+
* Dialog variant (e.g. FlexibleDialog).
|
|
42
|
+
*/
|
|
43
|
+
testId?: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* FlexiblePanel is the content container.
|
|
47
|
+
*
|
|
48
|
+
* **Implementation notes:**
|
|
49
|
+
*
|
|
50
|
+
* If you are creating a custom Dialog, make sure to follow these guidelines:
|
|
51
|
+
* - Make sure to add this component inside the [FlexibleDialog](/#flexibledialog).
|
|
52
|
+
* - If you need to create e2e tests, make sure to pass a `testId` prop. This
|
|
53
|
+
* will be passed down to this component using a sufix: e.g.
|
|
54
|
+
* `some-random-id-FlexiblePanel`. This scope will be propagated to the
|
|
55
|
+
* CloseButton element as well: e.g. `some-random-id-CloseButton`.
|
|
56
|
+
*
|
|
57
|
+
* ```js
|
|
58
|
+
* <FlexibleDialog>
|
|
59
|
+
* <FlexiblePanel content={"custom content goes here"} />
|
|
60
|
+
* </FlexibleDialog>
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function FlexiblePanel({ closeButtonVisible, content, title, onClose, styles, testId, }: Props): React.JSX.Element;
|
|
64
|
+
declare namespace FlexiblePanel {
|
|
65
|
+
var defaultProps: {
|
|
66
|
+
closeButtonVisible: boolean;
|
|
67
|
+
scrollOverflow: boolean;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export default FlexiblePanel;
|
|
@@ -31,6 +31,11 @@ type Props = {
|
|
|
31
31
|
* Test ID used for e2e testing.
|
|
32
32
|
*/
|
|
33
33
|
testId?: string;
|
|
34
|
+
/**
|
|
35
|
+
* The accessible name of dialog.
|
|
36
|
+
* See WCAG 2.1: 4.1.2 Name, Role, Value
|
|
37
|
+
*/
|
|
38
|
+
"aria-label"?: string;
|
|
34
39
|
/**
|
|
35
40
|
* The ID of the title labelling this dialog. Required.
|
|
36
41
|
* See WCAG 2.1: 4.1.2 Name, Role, Value
|
package/dist/es/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsxs, jsx, 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';
|
|
5
|
-
import { border, sizing, mapValuesToCssVars, semanticColor } from '@khanacademy/wonder-blocks-tokens';
|
|
5
|
+
import { border, sizing, mapValuesToCssVars, semanticColor, breakpoint } from '@khanacademy/wonder-blocks-tokens';
|
|
6
6
|
import { Heading, BodyText } from '@khanacademy/wonder-blocks-typography';
|
|
7
7
|
import * as ReactDOM from 'react-dom';
|
|
8
8
|
import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
|
|
@@ -15,7 +15,7 @@ const theme$1={root:{border:{radius:border.radius.radius_040}},dialog:{layout:{p
|
|
|
15
15
|
|
|
16
16
|
var theme = mapValuesToCssVars(theme$1,"--wb-c-modal-");
|
|
17
17
|
|
|
18
|
-
const ModalDialog=React.forwardRef(function ModalDialog(props,ref){const{above,below,role="dialog",style,children,testId,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy}=props;return jsxs(View,{style:[styles$6.wrapper,style],children:[below&&jsx(View,{style:styles$6.below,children:below}),jsx(View,{role:role,"aria-modal":"true","aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:styles$6.dialog,testId:testId,children:children}),above&&jsx(View,{style:styles$6.above,children:above})]})});const small$2="@media (max-width: 767px)";const styles$6=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,[small$2]:{padding:theme.dialog.layout.padding,flexDirection:"column"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden"},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";
|
|
18
|
+
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:[styles$6.wrapper,style],children:[below&&jsx(View,{style:styles$6.below,children:below}),jsx(View,{role:role,"aria-modal":"true","aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:styles$6.dialog,testId:testId,children:children}),above&&jsx(View,{style:styles$6.above,children:above})]})});const small$2="@media (max-width: 767px)";const styles$6=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,[small$2]:{padding:theme.dialog.layout.padding,flexDirection:"column"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden"},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
19
|
|
|
20
20
|
function ModalFooter({children}){return jsx(View,{style:styles$5.footer,children:children})}ModalFooter.__IS_MODAL_FOOTER__=true;ModalFooter.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_FOOTER__};const styles$5=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
21
|
|
|
@@ -43,6 +43,10 @@ function ModalPanel({closeButtonVisible=true,scrollOverflow=true,content,footer,
|
|
|
43
43
|
|
|
44
44
|
class OnePaneDialog extends React.Component{renderHeader(uniqueId){const{title,breadcrumbs=undefined,subtitle=undefined,testId}=this.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`})}}render(){const{onClose,footer,content,above,below,style,closeButtonVisible,testId,titleId,role,"aria-describedby":ariaDescribedBy}=this.props;return jsx(MediaLayout,{styleSheets:styleSheets,children:({styles})=>jsx(Id,{id:titleId,children:uniqueId=>jsx(ModalDialog,{style:[styles.dialog,style],above:above,below:below,testId:testId,"aria-labelledby":uniqueId,"aria-describedby":ariaDescribedBy,role:role,children:jsx(ModalPanel,{onClose:onClose,header:this.renderHeader(uniqueId),content:content,footer:footer,closeButtonVisible:closeButtonVisible,testId:testId})})})})}}OnePaneDialog.defaultProps={closeButtonVisible:true};const styleSheets={small:StyleSheet.create({dialog:{width:"100%",height:"100%",overflow:"hidden"}}),mdOrLarger:StyleSheet.create({dialog:{width:"93.75%",maxWidth:576,height:"81.25%",maxHeight:624}})};
|
|
45
45
|
|
|
46
|
+
function FlexiblePanel({closeButtonVisible=true,content,title,onClose,styles,testId}){const renderMainContent=React.useCallback(()=>{const contentNode=typeof content==="function"?content({title}):jsxs(Fragment,{children:[title,content]});const mainContent=ModalContent.isComponentOf(contentNode)?contentNode:jsx(ModalContent,{children:contentNode});if(!mainContent){return mainContent}return React.cloneElement(mainContent,{style:[mainContent.props.style]})},[title,content]);const mainContent=renderMainContent();const defaultBackgroundStyle={backgroundColor:semanticColor.surface.primary};const combinedBackgroundStyles={...defaultBackgroundStyle,...styles?.root};return jsxs(View,{style:[componentStyles$1.wrapper,combinedBackgroundStyles],testId:testId&&`${testId}-panel`,children:[closeButtonVisible&&jsx(CloseButton,{onClick:onClose,style:[componentStyles$1.closeButton,styles?.closeButton],testId:testId&&`${testId}-close`}),mainContent]})}FlexiblePanel.defaultProps={closeButtonVisible:true,scrollOverflow: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",right:theme.closeButton.layout.gapRight,top:theme.closeButton.layout.gapTop,zIndex:1,":focus":focusStyles.focus[":focus-visible"]}});
|
|
47
|
+
|
|
48
|
+
const FlexibleDialog=({onClose,title,content,styles,closeButtonVisible=true,testId,titleId,role,...accessibilityProps})=>{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(ModalDialog,{style:[componentStyles.dialog,styles?.root],testId:testId,"aria-label":accessibilityProps["aria-label"],"aria-labelledby":headingId,"aria-describedby":accessibilityProps["aria-describedby"],role:role,children:jsx(FlexiblePanel,{styles:{root:styles?.panel},onClose:onClose,title:renderedTitle,content:content,closeButtonVisible:closeButtonVisible,testId:testId})})};const componentStyles=StyleSheet.create({dialog:{width:"93.75%",maxWidth:576,height:"auto",maxHeight:"100vh",position:"relative",overflow:"auto",[breakpoint.mediaQuery.sm]:{width:"100%",height:"100vh",maxHeight:"100vh"}}});
|
|
49
|
+
|
|
46
50
|
function maybeGetNextAncestorModalLauncherPortal(element){let candidateElement=element&&element.parentElement;while(candidateElement&&!candidateElement.hasAttribute(ModalLauncherPortalAttributeName)){candidateElement=candidateElement.parentElement;}return candidateElement}function maybeGetPortalMountedModalHostElement(element){return maybeGetNextAncestorModalLauncherPortal(element)}
|
|
47
51
|
|
|
48
|
-
export { ModalDialog, ModalFooter, ModalHeader, modalLauncher as ModalLauncher, ModalPanel, OnePaneDialog, maybeGetPortalMountedModalHostElement };
|
|
52
|
+
export { FlexibleDialog, ModalDialog, ModalFooter, ModalHeader, modalLauncher as ModalLauncher, ModalPanel, OnePaneDialog, maybeGetPortalMountedModalHostElement };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ import ModalHeader from "./components/modal-header";
|
|
|
4
4
|
import ModalLauncher from "./components/modal-launcher";
|
|
5
5
|
import ModalPanel from "./components/modal-panel";
|
|
6
6
|
import OnePaneDialog from "./components/one-pane-dialog";
|
|
7
|
+
import FlexibleDialog from "./components/flexible-dialog";
|
|
7
8
|
import maybeGetPortalMountedModalHostElement from "./util/maybe-get-portal-mounted-modal-host-element";
|
|
8
|
-
export { ModalHeader, ModalFooter, ModalDialog, ModalPanel, ModalLauncher, OnePaneDialog, maybeGetPortalMountedModalHostElement, };
|
|
9
|
+
export { ModalHeader, ModalFooter, ModalDialog, ModalPanel, ModalLauncher, OnePaneDialog, FlexibleDialog, maybeGetPortalMountedModalHostElement, };
|
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ const theme$1={root:{border:{radius:wonderBlocksTokens.border.radius.radius_040}
|
|
|
44
44
|
|
|
45
45
|
var theme = wonderBlocksTokens.mapValuesToCssVars(theme$1,"--wb-c-modal-");
|
|
46
46
|
|
|
47
|
-
const ModalDialog=React__namespace.forwardRef(function ModalDialog(props,ref){const{above,below,role="dialog",style,children,testId,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy}=props;return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[styles$6.wrapper,style],children:[below&&jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$6.below,children:below}),jsxRuntime.jsx(wonderBlocksCore.View,{role:role,"aria-modal":"true","aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:styles$6.dialog,testId:testId,children:children}),above&&jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$6.above,children:above})]})});const small$2="@media (max-width: 767px)";const styles$6=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,[small$2]:{padding:theme.dialog.layout.padding,flexDirection:"column"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden"},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";
|
|
47
|
+
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:[styles$6.wrapper,style],children:[below&&jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$6.below,children:below}),jsxRuntime.jsx(wonderBlocksCore.View,{role:role,"aria-modal":"true","aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,"aria-describedby":ariaDescribedBy,ref:ref,style:styles$6.dialog,testId:testId,children:children}),above&&jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$6.above,children:above})]})});const small$2="@media (max-width: 767px)";const styles$6=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,[small$2]:{padding:theme.dialog.layout.padding,flexDirection:"column"}},dialog:{width:"100%",height:"100%",borderRadius:theme.root.border.radius,overflow:"hidden"},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
48
|
|
|
49
49
|
function ModalFooter({children}){return jsxRuntime.jsx(wonderBlocksCore.View,{style:styles$5.footer,children:children})}ModalFooter.__IS_MODAL_FOOTER__=true;ModalFooter.isComponentOf=instance=>{return instance&&instance.type&&instance.type.__IS_MODAL_FOOTER__};const styles$5=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
50
|
|
|
@@ -72,8 +72,13 @@ function ModalPanel({closeButtonVisible=true,scrollOverflow=true,content,footer,
|
|
|
72
72
|
|
|
73
73
|
class OnePaneDialog extends React__namespace.Component{renderHeader(uniqueId){const{title,breadcrumbs=undefined,subtitle=undefined,testId}=this.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`})}}render(){const{onClose,footer,content,above,below,style,closeButtonVisible,testId,titleId,role,"aria-describedby":ariaDescribedBy}=this.props;return jsxRuntime.jsx(wonderBlocksLayout.MediaLayout,{styleSheets:styleSheets,children:({styles})=>jsxRuntime.jsx(wonderBlocksCore.Id,{id:titleId,children:uniqueId=>jsxRuntime.jsx(ModalDialog,{style:[styles.dialog,style],above:above,below:below,testId:testId,"aria-labelledby":uniqueId,"aria-describedby":ariaDescribedBy,role:role,children:jsxRuntime.jsx(ModalPanel,{onClose:onClose,header:this.renderHeader(uniqueId),content:content,footer:footer,closeButtonVisible:closeButtonVisible,testId:testId})})})})}}OnePaneDialog.defaultProps={closeButtonVisible:true};const styleSheets={small:aphrodite.StyleSheet.create({dialog:{width:"100%",height:"100%",overflow:"hidden"}}),mdOrLarger:aphrodite.StyleSheet.create({dialog:{width:"93.75%",maxWidth:576,height:"81.25%",maxHeight:624}})};
|
|
74
74
|
|
|
75
|
+
function FlexiblePanel({closeButtonVisible=true,content,title,onClose,styles,testId}){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,{children:contentNode});if(!mainContent){return mainContent}return React__namespace.cloneElement(mainContent,{style:[mainContent.props.style]})},[title,content]);const mainContent=renderMainContent();const defaultBackgroundStyle={backgroundColor:wonderBlocksTokens.semanticColor.surface.primary};const combinedBackgroundStyles={...defaultBackgroundStyle,...styles?.root};return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[componentStyles$1.wrapper,combinedBackgroundStyles],testId:testId&&`${testId}-panel`,children:[closeButtonVisible&&jsxRuntime.jsx(CloseButton,{onClick:onClose,style:[componentStyles$1.closeButton,styles?.closeButton],testId:testId&&`${testId}-close`}),mainContent]})}FlexiblePanel.defaultProps={closeButtonVisible:true,scrollOverflow: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",right:theme.closeButton.layout.gapRight,top:theme.closeButton.layout.gapTop,zIndex:1,":focus":wonderBlocksStyles.focusStyles.focus[":focus-visible"]}});
|
|
76
|
+
|
|
77
|
+
const FlexibleDialog=({onClose,title,content,styles,closeButtonVisible=true,testId,titleId,role,...accessibilityProps})=>{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(ModalDialog,{style:[componentStyles.dialog,styles?.root],testId:testId,"aria-label":accessibilityProps["aria-label"],"aria-labelledby":headingId,"aria-describedby":accessibilityProps["aria-describedby"],role:role,children:jsxRuntime.jsx(FlexiblePanel,{styles:{root:styles?.panel},onClose:onClose,title:renderedTitle,content:content,closeButtonVisible:closeButtonVisible,testId:testId})})};const componentStyles=aphrodite.StyleSheet.create({dialog:{width:"93.75%",maxWidth:576,height:"auto",maxHeight:"100vh",position:"relative",overflow:"auto",[wonderBlocksTokens.breakpoint.mediaQuery.sm]:{width:"100%",height:"100vh",maxHeight:"100vh"}}});
|
|
78
|
+
|
|
75
79
|
function maybeGetNextAncestorModalLauncherPortal(element){let candidateElement=element&&element.parentElement;while(candidateElement&&!candidateElement.hasAttribute(ModalLauncherPortalAttributeName)){candidateElement=candidateElement.parentElement;}return candidateElement}function maybeGetPortalMountedModalHostElement(element){return maybeGetNextAncestorModalLauncherPortal(element)}
|
|
76
80
|
|
|
81
|
+
exports.FlexibleDialog = FlexibleDialog;
|
|
77
82
|
exports.ModalDialog = ModalDialog;
|
|
78
83
|
exports.ModalFooter = ModalFooter;
|
|
79
84
|
exports.ModalHeader = ModalHeader;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-modal",
|
|
3
|
-
"version": "8.1
|
|
3
|
+
"version": "8.2.1",
|
|
4
4
|
"design": "v2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"author": "",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@khanacademy/wonder-blocks-breadcrumbs": "3.1.
|
|
24
|
-
"@khanacademy/wonder-blocks-core": "12.
|
|
25
|
-
"@khanacademy/wonder-blocks-icon-button": "10.3.
|
|
26
|
-
"@khanacademy/wonder-blocks-layout": "3.1.
|
|
23
|
+
"@khanacademy/wonder-blocks-breadcrumbs": "3.1.32",
|
|
24
|
+
"@khanacademy/wonder-blocks-core": "12.4.0",
|
|
25
|
+
"@khanacademy/wonder-blocks-icon-button": "10.3.16",
|
|
26
|
+
"@khanacademy/wonder-blocks-layout": "3.1.32",
|
|
27
27
|
"@khanacademy/wonder-blocks-styles": "0.2.27",
|
|
28
28
|
"@khanacademy/wonder-blocks-timing": "7.0.2",
|
|
29
29
|
"@khanacademy/wonder-blocks-tokens": "12.0.2",
|
|
30
|
-
"@khanacademy/wonder-blocks-typography": "4.2.
|
|
30
|
+
"@khanacademy/wonder-blocks-typography": "4.2.17"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@phosphor-icons/core": "^2.0.2",
|