@sproutsocial/seeds-react-modal 2.4.9 → 2.5.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.log +27 -27
- package/CHANGELOG.md +70 -0
- package/dist/{Modal-ki8oiGbC.d.mts → Modal-DTeKLfEI.d.mts} +1 -1
- package/dist/{Modal-ki8oiGbC.d.ts → Modal-DTeKLfEI.d.ts} +1 -1
- package/dist/{ModalAction-BHG3Zbd9.d.mts → ModalExternalTrigger-BnbJk9zY.d.mts} +85 -3
- package/dist/{ModalAction-BHG3Zbd9.d.ts → ModalExternalTrigger-BnbJk9zY.d.ts} +85 -3
- package/dist/esm/{chunk-HOGEFGDN.js → chunk-62MRZAJV.js} +32 -10
- package/dist/esm/{chunk-HOGEFGDN.js.map → chunk-62MRZAJV.js.map} +1 -1
- package/dist/esm/{chunk-IYDY4OPB.js → chunk-72GBDCA2.js} +17 -1
- package/dist/esm/chunk-72GBDCA2.js.map +1 -0
- package/dist/esm/index.js +10 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v1/index.js +1 -1
- package/dist/esm/v2/index.js +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +81 -11
- package/dist/index.js.map +1 -1
- package/dist/v1/index.d.mts +2 -2
- package/dist/v1/index.d.ts +2 -2
- package/dist/v1/index.js +16 -0
- package/dist/v1/index.js.map +1 -1
- package/dist/v2/index.d.mts +4 -77
- package/dist/v2/index.d.ts +4 -77
- package/dist/v2/index.js +31 -9
- package/dist/v2/index.js.map +1 -1
- package/package.json +7 -7
- package/src/Modal.stories.tsx +64 -0
- package/src/__tests__/v1/Modal.test.tsx +146 -1
- package/src/__tests__/v2/Modal.test.tsx +77 -0
- package/src/index.ts +4 -0
- package/src/v1/Modal.tsx +30 -0
- package/src/v2/ModalTypes.ts +9 -2
- package/src/v2/ModalV2.stories.tsx +268 -49
- package/src/v2/components/ModalFooter.tsx +15 -4
- package/dist/esm/chunk-IYDY4OPB.js.map +0 -1
package/dist/v1/index.js
CHANGED
|
@@ -214,11 +214,27 @@ var Modal = (props) => {
|
|
|
214
214
|
} = props;
|
|
215
215
|
const isCloseable = Boolean(onClose);
|
|
216
216
|
const appElement = appElementSelector && document ? document.querySelector(appElementSelector) : void 0;
|
|
217
|
+
const handleContentRef = React2.useCallback(
|
|
218
|
+
(contentEl) => {
|
|
219
|
+
if (!contentEl) return;
|
|
220
|
+
const portal = contentEl.parentElement?.parentElement;
|
|
221
|
+
if (portal) {
|
|
222
|
+
portal.style.pointerEvents = "auto";
|
|
223
|
+
portal.addEventListener("pointerdown", (e) => {
|
|
224
|
+
if (document.body.style.pointerEvents === "none") {
|
|
225
|
+
e.stopPropagation();
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
[]
|
|
231
|
+
);
|
|
217
232
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
218
233
|
Container,
|
|
219
234
|
{
|
|
220
235
|
appElement,
|
|
221
236
|
ariaHideApp: !!appElement,
|
|
237
|
+
contentRef: handleContentRef,
|
|
222
238
|
isOpen,
|
|
223
239
|
contentLabel: label,
|
|
224
240
|
onRequestClose: onClose || (() => {
|
package/dist/v1/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/v1/index.ts","../../src/v1/Modal.tsx","../../src/v1/styles.tsx"],"sourcesContent":["// V1 Modal - Explicit exports for optimal tree shaking\nimport Modal from \"./Modal\";\n\nexport default Modal;\nexport { Modal };\n\n// Explicit type exports\nexport type {\n TypeModalProps,\n TypeModalHeaderProps,\n TypeModalFooterProps,\n TypeModalContentProps,\n TypeModalCloseButtonProps,\n} from \"./ModalTypes\";\n","import * as React from \"react\";\nimport { useContext } from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { Container, Content, Header, Footer, Body } from \"./styles\";\nimport type {\n TypeModalProps,\n TypeModalCloseButtonProps,\n TypeModalContentProps,\n TypeModalFooterProps,\n TypeModalHeaderProps,\n} from \"./ModalTypes\";\n\ntype TypeModalContext = Partial<{\n onClose: () => void;\n closeButtonLabel: string;\n label: string;\n}>;\n\nconst ModalContext = React.createContext<TypeModalContext>({});\n\nconst ModalHeader = (props: TypeModalHeaderProps) => {\n const { title, subtitle, children, bordered, ...rest } = props;\n return (\n <Header bordered={title || subtitle || bordered} {...rest}>\n {children ? (\n children\n ) : (\n <React.Fragment>\n <Box>\n {title && (\n <Text as=\"h1\" fontSize={400} fontWeight=\"semibold\">\n {title}\n </Text>\n )}\n {subtitle && (\n <Text as=\"div\" fontSize={200}>\n {subtitle}\n </Text>\n )}\n </Box>\n <Box display=\"flex\" alignItems=\"center\" justify-content=\"flex-end\">\n <ModalCloseButton ml={400} />\n </Box>\n </React.Fragment>\n )}\n </Header>\n );\n};\n\nconst ModalCloseButton = (props: TypeModalCloseButtonProps) => {\n const { onClose, closeButtonLabel } = useContext(ModalContext);\n if (!onClose) return null;\n return (\n <Button onClick={onClose} {...props}>\n <Icon name=\"x-outline\" ariaLabel={closeButtonLabel} />\n </Button>\n );\n};\n\nconst ModalFooter = ({\n bg = \"container.background.base\",\n ...rest\n}: TypeModalFooterProps) => (\n <Footer\n bg={bg}\n borderTop={500}\n borderColor=\"container.border.base\"\n {...rest}\n />\n);\n\nconst ModalContent = React.forwardRef(\n ({ children, ...rest }: TypeModalContentProps, ref) => {\n const { label } = useContext(ModalContext);\n return (\n <Content data-qa-modal data-qa-label={label} ref={ref} {...rest}>\n {children}\n </Content>\n );\n }\n);\n\n/**\n * The modal you want\n */\nconst Modal = (props: TypeModalProps) => {\n const {\n appElementSelector,\n children,\n isOpen,\n label,\n onClose,\n closeButtonLabel,\n width = \"800px\",\n zIndex = 6,\n data = {},\n ...rest\n } = props;\n\n const isCloseable = Boolean(onClose);\n const appElement =\n appElementSelector && document\n ? (document.querySelector(appElementSelector) as HTMLElement)\n : undefined;\n\n return (\n <Container\n appElement={appElement}\n ariaHideApp={!!appElement}\n isOpen={isOpen}\n contentLabel={label}\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n onRequestClose={onClose || (() => {})}\n shouldFocusAfterRender={true}\n shouldCloseOnOverlayClick={isCloseable}\n shouldCloseOnEsc={isCloseable}\n shouldReturnFocusAfterClose={true}\n closeTimeoutMS={200}\n role=\"dialog\"\n width={width}\n zIndex={zIndex}\n data={{\n \"qa-modal\": \"\",\n \"qa-modal-isopen\": isOpen,\n ...data,\n }}\n {...rest}\n >\n <React.Fragment>\n <Body />\n\n <ModalContext.Provider\n value={{\n onClose,\n closeButtonLabel,\n label,\n }}\n >\n {children}\n </ModalContext.Provider>\n </React.Fragment>\n </Container>\n );\n};\n\nModalHeader.displayName = \"Modal.Header\";\nModalFooter.displayName = \"Modal.Footer\";\nModalContent.displayName = \"Modal.Content\";\nModalCloseButton.displayName = \"Modal.CloseButton\";\n\nModal.Header = ModalHeader;\nModal.Footer = ModalFooter;\nModal.Content = ModalContent;\nModal.CloseButton = ModalCloseButton;\n\nexport default Modal;\n","import React from \"react\";\nimport styled, { createGlobalStyle } from \"styled-components\";\nimport { width, zIndex } from \"styled-system\";\nimport ReactModal from \"react-modal\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport Box, { type TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\n\n// This is the max space allowed between the modal and the edge of the browser\nconst BODY_PADDING = \"64px\";\n\nconst ReactModalAdapter = ({\n className = \"\",\n ...props\n}: { className?: string } & Omit<\n ReactModal.Props,\n \"portalClassName\" | \"className\" | \"overlayClassName\"\n>) => {\n // We want to create *__Content and *__Overlay class names on the subcomponents.\n // Because `className` could be a space-separated list of class names, we make\n // sure that we append `__Content` and `__Overlay` to every class name.\n const contentClassName = className\n .split(\" \")\n .map((className) => `${className} ${className}__Content`)\n .join(\" \");\n\n const overlayClassName = className\n .split(\" \")\n .map((className) => `${className} ${className}__Overlay`)\n .join(\" \");\n\n return (\n <ReactModal\n portalClassName={className}\n className={contentClassName}\n overlayClassName={overlayClassName}\n {...props}\n />\n );\n};\n\nexport const Body = createGlobalStyle`\n .ReactModal__Body--open {\n overflow: hidden;\n }\n`;\n\nexport const Container = styled(ReactModalAdapter)<TypeContainerProps>`\n &__Overlay {\n position: fixed;\n top: 0px;\n left: 0px;\n right: 0px;\n bottom: 0px;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: ${(props) => props.theme.colors.overlay.background.base};\n opacity: 0;\n will-change: opacity;\n transition: opacity ${(props) => props.theme.duration.medium}\n ${(props) => props.theme.easing.ease_inout};\n\n ${zIndex}\n\n &.ReactModal__Overlay--after-open {\n opacity: 1;\n }\n &.ReactModal__Overlay--before-close {\n opacity: 0;\n }\n }\n\n &__Content {\n display: flex;\n flex-direction: column;\n background: ${(props) => props.theme.colors.container.background.base};\n border-radius: ${(props) => props.theme.radii[600]};\n box-shadow: ${(props) => props.theme.shadows.medium};\n filter: blur(0);\n color: ${(props) => props.theme.colors.text.body};\n\n outline: none;\n max-width: calc(100vw - ${BODY_PADDING});\n max-height: calc(100vh - ${BODY_PADDING});\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n /**\n * This prevents the modal from being very short in IE11. Better too big\n * than too small.\n */\n height: calc(100vh - ${BODY_PADDING});\n }\n\n ${width}\n\n ${COMMON}\n }\n`;\n\nexport const Content = styled(Box)`\n font-family: ${(props) => props.theme.fontFamily};\n min-height: 80px;\n overflow-y: auto;\n flex: 1 1 auto;\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[450]};\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n /* 'flex-basis: auto' breaks overflow in IE11 */\n flex-basis: 100%;\n }\n`;\n\nexport const HeaderContainer = styled(Box)`\n font-family: ${(props) => props.theme.fontFamily};\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[450]};\n`;\n\nexport const Header = styled(HeaderContainer)<{ bordered?: boolean }>`\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\n border-bottom-width: ${(props) => props.theme.borderWidths[500]};\n border-bottom-color: ${(props) =>\n props.bordered ? props.theme.colors.container.border.base : \"transparent\"};\n border-bottom-style: solid;\n`;\n\nexport const Footer = styled(Box)`\n flex: 0 0 auto;\n font-family: ${(props) => props.theme.fontFamily};\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[450]};\n border-bottom-right-radius: ${(props) => props.theme.radii[500]};\n border-bottom-left-radius: ${(props) => props.theme.radii[500]};\n`;\n\nContainer.displayName = \"ModalContainer\";\nContent.displayName = \"Content\";\nHeader.displayName = \"Modal.Header\";\nFooter.displayName = \"Modal.Footer\";\n"],"mappings":"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","names":["React","import_react","import_seeds_react_box","className","ReactModal","styled","Box","import_jsx_runtime","Box","Text","Button","Icon","width","zIndex"]}
|
|
1
|
+
{"version":3,"sources":["../../src/v1/index.ts","../../src/v1/Modal.tsx","../../src/v1/styles.tsx"],"sourcesContent":["// V1 Modal - Explicit exports for optimal tree shaking\nimport Modal from \"./Modal\";\n\nexport default Modal;\nexport { Modal };\n\n// Explicit type exports\nexport type {\n TypeModalProps,\n TypeModalHeaderProps,\n TypeModalFooterProps,\n TypeModalContentProps,\n TypeModalCloseButtonProps,\n} from \"./ModalTypes\";\n","import * as React from \"react\";\nimport { useContext } from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { Container, Content, Header, Footer, Body } from \"./styles\";\nimport type {\n TypeModalProps,\n TypeModalCloseButtonProps,\n TypeModalContentProps,\n TypeModalFooterProps,\n TypeModalHeaderProps,\n} from \"./ModalTypes\";\n\ntype TypeModalContext = Partial<{\n onClose: () => void;\n closeButtonLabel: string;\n label: string;\n}>;\n\nconst ModalContext = React.createContext<TypeModalContext>({});\n\nconst ModalHeader = (props: TypeModalHeaderProps) => {\n const { title, subtitle, children, bordered, ...rest } = props;\n return (\n <Header bordered={title || subtitle || bordered} {...rest}>\n {children ? (\n children\n ) : (\n <React.Fragment>\n <Box>\n {title && (\n <Text as=\"h1\" fontSize={400} fontWeight=\"semibold\">\n {title}\n </Text>\n )}\n {subtitle && (\n <Text as=\"div\" fontSize={200}>\n {subtitle}\n </Text>\n )}\n </Box>\n <Box display=\"flex\" alignItems=\"center\" justify-content=\"flex-end\">\n <ModalCloseButton ml={400} />\n </Box>\n </React.Fragment>\n )}\n </Header>\n );\n};\n\nconst ModalCloseButton = (props: TypeModalCloseButtonProps) => {\n const { onClose, closeButtonLabel } = useContext(ModalContext);\n if (!onClose) return null;\n return (\n <Button onClick={onClose} {...props}>\n <Icon name=\"x-outline\" ariaLabel={closeButtonLabel} />\n </Button>\n );\n};\n\nconst ModalFooter = ({\n bg = \"container.background.base\",\n ...rest\n}: TypeModalFooterProps) => (\n <Footer\n bg={bg}\n borderTop={500}\n borderColor=\"container.border.base\"\n {...rest}\n />\n);\n\nconst ModalContent = React.forwardRef(\n ({ children, ...rest }: TypeModalContentProps, ref) => {\n const { label } = useContext(ModalContext);\n return (\n <Content data-qa-modal data-qa-label={label} ref={ref} {...rest}>\n {children}\n </Content>\n );\n }\n);\n\n/**\n * The modal you want\n */\nconst Modal = (props: TypeModalProps) => {\n const {\n appElementSelector,\n children,\n isOpen,\n label,\n onClose,\n closeButtonLabel,\n width = \"800px\",\n zIndex = 6,\n data = {},\n ...rest\n } = props;\n\n const isCloseable = Boolean(onClose);\n const appElement =\n appElementSelector && document\n ? (document.querySelector(appElementSelector) as HTMLElement)\n : undefined;\n\n /**\n * When a Radix Dialog (Modal V2) is open it sets `pointer-events: none` on\n * `document.body` and listens for `pointerdown` on the document to detect\n * \"outside\" clicks. react-modal portals its overlay to body, so:\n * 1. The overlay inherits `pointer-events: none` → unclickable\n * 2. Clicks on the overlay bubble to document → Radix dismisses Modal V2\n *\n * We use `contentRef` to reach the portal DOM and fix both issues.\n */\n const handleContentRef = React.useCallback(\n (contentEl: HTMLElement | null) => {\n if (!contentEl) return;\n // DOM structure: body > portal > overlay > content\n const portal = contentEl.parentElement?.parentElement;\n if (portal) {\n portal.style.pointerEvents = \"auto\";\n portal.addEventListener(\"pointerdown\", (e) => {\n // Only stop propagation when Radix Dialog has disabled body pointer events.\n // This avoids interfering with document-level listeners (analytics, other\n // click-outside patterns) when no Modal V2 is open.\n if (document.body.style.pointerEvents === \"none\") {\n e.stopPropagation();\n }\n });\n }\n },\n []\n );\n\n return (\n <Container\n appElement={appElement}\n ariaHideApp={!!appElement}\n contentRef={handleContentRef}\n isOpen={isOpen}\n contentLabel={label}\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n onRequestClose={onClose || (() => {})}\n shouldFocusAfterRender={true}\n shouldCloseOnOverlayClick={isCloseable}\n shouldCloseOnEsc={isCloseable}\n shouldReturnFocusAfterClose={true}\n closeTimeoutMS={200}\n role=\"dialog\"\n width={width}\n zIndex={zIndex}\n data={{\n \"qa-modal\": \"\",\n \"qa-modal-isopen\": isOpen,\n ...data,\n }}\n {...rest}\n >\n <React.Fragment>\n <Body />\n\n <ModalContext.Provider\n value={{\n onClose,\n closeButtonLabel,\n label,\n }}\n >\n {children}\n </ModalContext.Provider>\n </React.Fragment>\n </Container>\n );\n};\n\nModalHeader.displayName = \"Modal.Header\";\nModalFooter.displayName = \"Modal.Footer\";\nModalContent.displayName = \"Modal.Content\";\nModalCloseButton.displayName = \"Modal.CloseButton\";\n\nModal.Header = ModalHeader;\nModal.Footer = ModalFooter;\nModal.Content = ModalContent;\nModal.CloseButton = ModalCloseButton;\n\nexport default Modal;\n","import React from \"react\";\nimport styled, { createGlobalStyle } from \"styled-components\";\nimport { width, zIndex } from \"styled-system\";\nimport ReactModal from \"react-modal\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport Box, { type TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\n\n// This is the max space allowed between the modal and the edge of the browser\nconst BODY_PADDING = \"64px\";\n\nconst ReactModalAdapter = ({\n className = \"\",\n ...props\n}: { className?: string } & Omit<\n ReactModal.Props,\n \"portalClassName\" | \"className\" | \"overlayClassName\"\n>) => {\n // We want to create *__Content and *__Overlay class names on the subcomponents.\n // Because `className` could be a space-separated list of class names, we make\n // sure that we append `__Content` and `__Overlay` to every class name.\n const contentClassName = className\n .split(\" \")\n .map((className) => `${className} ${className}__Content`)\n .join(\" \");\n\n const overlayClassName = className\n .split(\" \")\n .map((className) => `${className} ${className}__Overlay`)\n .join(\" \");\n\n return (\n <ReactModal\n portalClassName={className}\n className={contentClassName}\n overlayClassName={overlayClassName}\n {...props}\n />\n );\n};\n\nexport const Body = createGlobalStyle`\n .ReactModal__Body--open {\n overflow: hidden;\n }\n`;\n\nexport const Container = styled(ReactModalAdapter)<TypeContainerProps>`\n &__Overlay {\n position: fixed;\n top: 0px;\n left: 0px;\n right: 0px;\n bottom: 0px;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: ${(props) => props.theme.colors.overlay.background.base};\n opacity: 0;\n will-change: opacity;\n transition: opacity ${(props) => props.theme.duration.medium}\n ${(props) => props.theme.easing.ease_inout};\n\n ${zIndex}\n\n &.ReactModal__Overlay--after-open {\n opacity: 1;\n }\n &.ReactModal__Overlay--before-close {\n opacity: 0;\n }\n }\n\n &__Content {\n display: flex;\n flex-direction: column;\n background: ${(props) => props.theme.colors.container.background.base};\n border-radius: ${(props) => props.theme.radii[600]};\n box-shadow: ${(props) => props.theme.shadows.medium};\n filter: blur(0);\n color: ${(props) => props.theme.colors.text.body};\n\n outline: none;\n max-width: calc(100vw - ${BODY_PADDING});\n max-height: calc(100vh - ${BODY_PADDING});\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n /**\n * This prevents the modal from being very short in IE11. Better too big\n * than too small.\n */\n height: calc(100vh - ${BODY_PADDING});\n }\n\n ${width}\n\n ${COMMON}\n }\n`;\n\nexport const Content = styled(Box)`\n font-family: ${(props) => props.theme.fontFamily};\n min-height: 80px;\n overflow-y: auto;\n flex: 1 1 auto;\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[450]};\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n /* 'flex-basis: auto' breaks overflow in IE11 */\n flex-basis: 100%;\n }\n`;\n\nexport const HeaderContainer = styled(Box)`\n font-family: ${(props) => props.theme.fontFamily};\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[450]};\n`;\n\nexport const Header = styled(HeaderContainer)<{ bordered?: boolean }>`\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\n border-bottom-width: ${(props) => props.theme.borderWidths[500]};\n border-bottom-color: ${(props) =>\n props.bordered ? props.theme.colors.container.border.base : \"transparent\"};\n border-bottom-style: solid;\n`;\n\nexport const Footer = styled(Box)`\n flex: 0 0 auto;\n font-family: ${(props) => props.theme.fontFamily};\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[450]};\n border-bottom-right-radius: ${(props) => props.theme.radii[500]};\n border-bottom-left-radius: ${(props) => props.theme.radii[500]};\n`;\n\nContainer.displayName = \"ModalContainer\";\nContent.displayName = \"Content\";\nHeader.displayName = \"Modal.Header\";\nFooter.displayName = \"Modal.Footer\";\n"],"mappings":"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","names":["React","import_react","import_seeds_react_box","className","ReactModal","styled","Box","import_jsx_runtime","Box","Text","Button","Icon","width","zIndex"]}
|
package/dist/v2/index.d.mts
CHANGED
|
@@ -1,84 +1,11 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { TypeButtonProps } from '@sproutsocial/seeds-react-button';
|
|
1
|
+
export { l as Modal, M as ModalAction, a as ModalBody, b as ModalCloseWrapper, c as ModalCloseWrapperProps, d as ModalCustomFooter, e as ModalCustomHeader, f as ModalDescription, g as ModalExternalTrigger, h as ModalExternalTriggerProps, i as ModalFooter, j as ModalHeader, k as ModalRail, T as TypeModalActionProps, n as TypeModalBodyProps, o as TypeModalDescriptionProps, p as TypeModalFooterProps, q as TypeModalHeaderProps, r as TypeModalProps, m as TypeModalRailProps, u as useModalExternalTrigger, s as useModalTriggerProps } from '../ModalExternalTrigger-BnbJk9zY.mjs';
|
|
4
2
|
import 'react/jsx-runtime';
|
|
3
|
+
import 'react';
|
|
5
4
|
import 'styled-components';
|
|
6
5
|
import '@sproutsocial/seeds-react-box';
|
|
7
6
|
import '@radix-ui/react-dialog';
|
|
8
7
|
import '@sproutsocial/seeds-react-icon';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Props for ModalExternalTrigger component.
|
|
12
|
-
*/
|
|
13
|
-
interface ModalExternalTriggerProps extends Omit<TypeButtonProps, "onClick"> {
|
|
14
|
-
/** Callback when button is clicked to trigger modal open */
|
|
15
|
-
onTrigger: () => void;
|
|
16
|
-
/** Whether the modal is currently open (for ARIA expanded state) */
|
|
17
|
-
isOpen: boolean;
|
|
18
|
-
/** Optional modal ID for aria-controls attribute */
|
|
19
|
-
modalId?: string;
|
|
20
|
-
/** Optional onClick handler (called before onTrigger) */
|
|
21
|
-
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* A Button component pre-configured for triggering modals from outside the Modal component tree.
|
|
25
|
-
*
|
|
26
|
-
* ⚠️ **NOT RECOMMENDED** - Prefer using modalTrigger prop or ModalTrigger component.
|
|
27
|
-
* Use this component ONLY as a last resort when architectural constraints prevent keeping
|
|
28
|
-
* the trigger inside the Modal component tree.
|
|
29
|
-
*
|
|
30
|
-
* This component wraps the Seeds Button with automatic ARIA attributes for modal triggers.
|
|
31
|
-
* However, focus restoration still requires manual handling via onCloseAutoFocus callback
|
|
32
|
-
* due to Radix UI's architectural limitations with external triggers.
|
|
33
|
-
*
|
|
34
|
-
* **Why modalTrigger prop is better:**
|
|
35
|
-
* - Automatic ARIA attributes
|
|
36
|
-
* - Automatic focus restoration (no onCloseAutoFocus needed)
|
|
37
|
-
* - Better touch device support
|
|
38
|
-
* - Follows WAI-ARIA Dialog best practices
|
|
39
|
-
*
|
|
40
|
-
* **When to use ModalExternalTrigger:**
|
|
41
|
-
* - Trigger must live outside Modal component tree (e.g., in a page header)
|
|
42
|
-
* - Using Seeds Button as the trigger
|
|
43
|
-
* - Want automatic ARIA attributes without manual hook usage
|
|
44
|
-
*
|
|
45
|
-
* **Usage pattern with focus restoration:**
|
|
46
|
-
* You must still handle focus restoration manually by passing a ref and implementing
|
|
47
|
-
* onCloseAutoFocus on the Modal component.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```tsx
|
|
51
|
-
* const [isOpen, setIsOpen] = useState(false);
|
|
52
|
-
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
53
|
-
*
|
|
54
|
-
* return (
|
|
55
|
-
* <>
|
|
56
|
-
* <ModalExternalTrigger
|
|
57
|
-
* ref={triggerRef}
|
|
58
|
-
* isOpen={isOpen}
|
|
59
|
-
* onTrigger={() => setIsOpen(true)}
|
|
60
|
-
* appearance="primary"
|
|
61
|
-
* >
|
|
62
|
-
* Open Modal
|
|
63
|
-
* </ModalExternalTrigger>
|
|
64
|
-
*
|
|
65
|
-
* <Modal
|
|
66
|
-
* open={isOpen}
|
|
67
|
-
* onOpenChange={setIsOpen}
|
|
68
|
-
* onCloseAutoFocus={(e) => {
|
|
69
|
-
* e.preventDefault();
|
|
70
|
-
* triggerRef.current?.focus();
|
|
71
|
-
* }}
|
|
72
|
-
* >
|
|
73
|
-
* <ModalBody>Content</ModalBody>
|
|
74
|
-
* </Modal>
|
|
75
|
-
* </>
|
|
76
|
-
* );
|
|
77
|
-
* ```
|
|
78
|
-
*
|
|
79
|
-
* @see useModalExternalTrigger - Hook alternative for non-Button triggers
|
|
80
|
-
*/
|
|
81
|
-
declare const ModalExternalTrigger: React.ForwardRefExoticComponent<Omit<ModalExternalTriggerProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
8
|
+
import '@sproutsocial/seeds-react-button';
|
|
82
9
|
|
|
83
10
|
declare const DEFAULT_MODAL_WIDTH = "800px";
|
|
84
11
|
declare const DEFAULT_MODAL_BG = "container.background.base";
|
|
@@ -90,4 +17,4 @@ declare const MODAL_SIZE_PRESETS: {
|
|
|
90
17
|
readonly full: "90vw";
|
|
91
18
|
};
|
|
92
19
|
|
|
93
|
-
export { BODY_PADDING, DEFAULT_MODAL_BG, DEFAULT_MODAL_WIDTH, MODAL_SIZE_PRESETS
|
|
20
|
+
export { BODY_PADDING, DEFAULT_MODAL_BG, DEFAULT_MODAL_WIDTH, MODAL_SIZE_PRESETS };
|
package/dist/v2/index.d.ts
CHANGED
|
@@ -1,84 +1,11 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { TypeButtonProps } from '@sproutsocial/seeds-react-button';
|
|
1
|
+
export { l as Modal, M as ModalAction, a as ModalBody, b as ModalCloseWrapper, c as ModalCloseWrapperProps, d as ModalCustomFooter, e as ModalCustomHeader, f as ModalDescription, g as ModalExternalTrigger, h as ModalExternalTriggerProps, i as ModalFooter, j as ModalHeader, k as ModalRail, T as TypeModalActionProps, n as TypeModalBodyProps, o as TypeModalDescriptionProps, p as TypeModalFooterProps, q as TypeModalHeaderProps, r as TypeModalProps, m as TypeModalRailProps, u as useModalExternalTrigger, s as useModalTriggerProps } from '../ModalExternalTrigger-BnbJk9zY.js';
|
|
4
2
|
import 'react/jsx-runtime';
|
|
3
|
+
import 'react';
|
|
5
4
|
import 'styled-components';
|
|
6
5
|
import '@sproutsocial/seeds-react-box';
|
|
7
6
|
import '@radix-ui/react-dialog';
|
|
8
7
|
import '@sproutsocial/seeds-react-icon';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Props for ModalExternalTrigger component.
|
|
12
|
-
*/
|
|
13
|
-
interface ModalExternalTriggerProps extends Omit<TypeButtonProps, "onClick"> {
|
|
14
|
-
/** Callback when button is clicked to trigger modal open */
|
|
15
|
-
onTrigger: () => void;
|
|
16
|
-
/** Whether the modal is currently open (for ARIA expanded state) */
|
|
17
|
-
isOpen: boolean;
|
|
18
|
-
/** Optional modal ID for aria-controls attribute */
|
|
19
|
-
modalId?: string;
|
|
20
|
-
/** Optional onClick handler (called before onTrigger) */
|
|
21
|
-
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* A Button component pre-configured for triggering modals from outside the Modal component tree.
|
|
25
|
-
*
|
|
26
|
-
* ⚠️ **NOT RECOMMENDED** - Prefer using modalTrigger prop or ModalTrigger component.
|
|
27
|
-
* Use this component ONLY as a last resort when architectural constraints prevent keeping
|
|
28
|
-
* the trigger inside the Modal component tree.
|
|
29
|
-
*
|
|
30
|
-
* This component wraps the Seeds Button with automatic ARIA attributes for modal triggers.
|
|
31
|
-
* However, focus restoration still requires manual handling via onCloseAutoFocus callback
|
|
32
|
-
* due to Radix UI's architectural limitations with external triggers.
|
|
33
|
-
*
|
|
34
|
-
* **Why modalTrigger prop is better:**
|
|
35
|
-
* - Automatic ARIA attributes
|
|
36
|
-
* - Automatic focus restoration (no onCloseAutoFocus needed)
|
|
37
|
-
* - Better touch device support
|
|
38
|
-
* - Follows WAI-ARIA Dialog best practices
|
|
39
|
-
*
|
|
40
|
-
* **When to use ModalExternalTrigger:**
|
|
41
|
-
* - Trigger must live outside Modal component tree (e.g., in a page header)
|
|
42
|
-
* - Using Seeds Button as the trigger
|
|
43
|
-
* - Want automatic ARIA attributes without manual hook usage
|
|
44
|
-
*
|
|
45
|
-
* **Usage pattern with focus restoration:**
|
|
46
|
-
* You must still handle focus restoration manually by passing a ref and implementing
|
|
47
|
-
* onCloseAutoFocus on the Modal component.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```tsx
|
|
51
|
-
* const [isOpen, setIsOpen] = useState(false);
|
|
52
|
-
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
53
|
-
*
|
|
54
|
-
* return (
|
|
55
|
-
* <>
|
|
56
|
-
* <ModalExternalTrigger
|
|
57
|
-
* ref={triggerRef}
|
|
58
|
-
* isOpen={isOpen}
|
|
59
|
-
* onTrigger={() => setIsOpen(true)}
|
|
60
|
-
* appearance="primary"
|
|
61
|
-
* >
|
|
62
|
-
* Open Modal
|
|
63
|
-
* </ModalExternalTrigger>
|
|
64
|
-
*
|
|
65
|
-
* <Modal
|
|
66
|
-
* open={isOpen}
|
|
67
|
-
* onOpenChange={setIsOpen}
|
|
68
|
-
* onCloseAutoFocus={(e) => {
|
|
69
|
-
* e.preventDefault();
|
|
70
|
-
* triggerRef.current?.focus();
|
|
71
|
-
* }}
|
|
72
|
-
* >
|
|
73
|
-
* <ModalBody>Content</ModalBody>
|
|
74
|
-
* </Modal>
|
|
75
|
-
* </>
|
|
76
|
-
* );
|
|
77
|
-
* ```
|
|
78
|
-
*
|
|
79
|
-
* @see useModalExternalTrigger - Hook alternative for non-Button triggers
|
|
80
|
-
*/
|
|
81
|
-
declare const ModalExternalTrigger: React.ForwardRefExoticComponent<Omit<ModalExternalTriggerProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
8
|
+
import '@sproutsocial/seeds-react-button';
|
|
82
9
|
|
|
83
10
|
declare const DEFAULT_MODAL_WIDTH = "800px";
|
|
84
11
|
declare const DEFAULT_MODAL_BG = "container.background.base";
|
|
@@ -90,4 +17,4 @@ declare const MODAL_SIZE_PRESETS: {
|
|
|
90
17
|
readonly full: "90vw";
|
|
91
18
|
};
|
|
92
19
|
|
|
93
|
-
export { BODY_PADDING, DEFAULT_MODAL_BG, DEFAULT_MODAL_WIDTH, MODAL_SIZE_PRESETS
|
|
20
|
+
export { BODY_PADDING, DEFAULT_MODAL_BG, DEFAULT_MODAL_WIDTH, MODAL_SIZE_PRESETS };
|
package/dist/v2/index.js
CHANGED
|
@@ -523,15 +523,22 @@ var ModalCustomFooter = (0, import_styled_components3.default)(import_seeds_reac
|
|
|
523
523
|
`;
|
|
524
524
|
ModalCustomFooter.displayName = "ModalCustomFooter";
|
|
525
525
|
var ModalFooter = (props) => {
|
|
526
|
-
const {
|
|
526
|
+
const {
|
|
527
|
+
cancelButton,
|
|
528
|
+
primaryButton,
|
|
529
|
+
leftAction,
|
|
530
|
+
closeOnPrimaryAction = true,
|
|
531
|
+
...rest
|
|
532
|
+
} = props;
|
|
527
533
|
if (!cancelButton && !primaryButton && !leftAction) {
|
|
528
534
|
return null;
|
|
529
535
|
}
|
|
536
|
+
const wrappedPrimaryButton = primaryButton && closeOnPrimaryAction ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ModalCloseWrapper, { children: primaryButton }) : primaryButton;
|
|
530
537
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ModalCustomFooter, { "data-slot": "modal-footer", "data-qa-modal-footer": true, ...rest, children: [
|
|
531
538
|
leftAction ? leftAction : null,
|
|
532
539
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_seeds_react_box2.default, { display: "flex", gap: 300, marginLeft: "auto", children: [
|
|
533
540
|
cancelButton && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ModalCloseWrapper, { children: cancelButton }),
|
|
534
|
-
|
|
541
|
+
wrappedPrimaryButton
|
|
535
542
|
] })
|
|
536
543
|
] });
|
|
537
544
|
};
|
|
@@ -639,7 +646,6 @@ var import_seeds_react_icon = __toESM(require("@sproutsocial/seeds-react-icon"))
|
|
|
639
646
|
|
|
640
647
|
// ../seeds-react-mixins/dist/esm/index.js
|
|
641
648
|
var import_styled_components6 = require("styled-components");
|
|
642
|
-
var import_seeds_react_theme = require("@sproutsocial/seeds-react-theme");
|
|
643
649
|
var visuallyHidden = import_styled_components6.css`
|
|
644
650
|
position: absolute;
|
|
645
651
|
width: 1px;
|
|
@@ -651,11 +657,12 @@ var visuallyHidden = import_styled_components6.css`
|
|
|
651
657
|
border: 0;
|
|
652
658
|
`;
|
|
653
659
|
var focusRing = import_styled_components6.css`
|
|
654
|
-
box-shadow: 0 0 0 1px
|
|
660
|
+
box-shadow: 0 0 0 1px
|
|
661
|
+
${({ theme }) => theme.colors.button.primary.background.base},
|
|
655
662
|
0 0px 0px 4px
|
|
656
663
|
color-mix(
|
|
657
664
|
in srgb,
|
|
658
|
-
${
|
|
665
|
+
${({ theme }) => theme.colors.button.primary.background.base},
|
|
659
666
|
transparent 70%
|
|
660
667
|
);
|
|
661
668
|
outline: none;
|
|
@@ -665,15 +672,30 @@ var focusRing = import_styled_components6.css`
|
|
|
665
672
|
}
|
|
666
673
|
`;
|
|
667
674
|
var pill = import_styled_components6.css`
|
|
668
|
-
min-width: ${
|
|
669
|
-
min-height: ${
|
|
670
|
-
padding: ${
|
|
671
|
-
border-radius: ${
|
|
675
|
+
min-width: ${({ theme }) => theme.space[600]};
|
|
676
|
+
min-height: ${({ theme }) => theme.space[600]};
|
|
677
|
+
padding: ${({ theme }) => theme.space[300]};
|
|
678
|
+
border-radius: ${({ theme }) => theme.radii.pill};
|
|
672
679
|
`;
|
|
673
680
|
var disabled = import_styled_components6.css`
|
|
674
681
|
opacity: 0.4;
|
|
675
682
|
pointer-events: none;
|
|
676
683
|
`;
|
|
684
|
+
var container = import_styled_components6.css`
|
|
685
|
+
background: ${({ theme }) => theme.colors.container.background.base};
|
|
686
|
+
border: ${({ theme }) => theme.borders[500]}
|
|
687
|
+
${({ theme }) => theme.colors.container.border.base};
|
|
688
|
+
border-radius: ${({ theme }) => theme.radii.outer};
|
|
689
|
+
`;
|
|
690
|
+
var divider = import_styled_components6.css`
|
|
691
|
+
border-bottom: ${({ theme }) => theme.borderWidths[500]} solid
|
|
692
|
+
${({ theme }) => theme.colors.container.border.base};
|
|
693
|
+
`;
|
|
694
|
+
var truncate = import_styled_components6.css`
|
|
695
|
+
text-overflow: ellipsis;
|
|
696
|
+
overflow: hidden;
|
|
697
|
+
white-space: nowrap;
|
|
698
|
+
`;
|
|
677
699
|
|
|
678
700
|
// src/v2/components/ModalAction.tsx
|
|
679
701
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|