@sproutsocial/seeds-react-modal 1.0.2 → 1.0.4
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 +39 -19
- package/CHANGELOG.md +19 -0
- package/dist/Modal-ki8oiGbC.d.mts +69 -0
- package/dist/Modal-ki8oiGbC.d.ts +69 -0
- package/dist/ModalRail-OQ8DZ1vH.d.mts +178 -0
- package/dist/ModalRail-OQ8DZ1vH.d.ts +178 -0
- package/dist/esm/chunk-GKQRFPCX.js +642 -0
- package/dist/esm/chunk-GKQRFPCX.js.map +1 -0
- package/dist/esm/chunk-IYDY4OPB.js +237 -0
- package/dist/esm/chunk-IYDY4OPB.js.map +1 -0
- package/dist/esm/index.js +28 -235
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v1/index.js +9 -0
- package/dist/esm/v1/index.js.map +1 -0
- package/dist/esm/v2/index.js +39 -0
- package/dist/esm/v2/index.js.map +1 -0
- package/dist/index.d.mts +11 -66
- package/dist/index.d.ts +11 -66
- package/dist/index.js +658 -17
- package/dist/index.js.map +1 -1
- package/dist/v1/index.d.mts +11 -0
- package/dist/v1/index.d.ts +11 -0
- package/dist/v1/index.js +273 -0
- package/dist/v1/index.js.map +1 -0
- package/dist/v2/index.d.mts +26 -0
- package/dist/v2/index.d.ts +26 -0
- package/dist/v2/index.js +694 -0
- package/dist/v2/index.js.map +1 -0
- package/package.json +36 -16
- package/src/Modal.stories.tsx +1 -1
- package/src/__tests__/v1/Modal.test.tsx +134 -0
- package/src/__tests__/v1/Modal.typetest.tsx +209 -0
- package/src/index.ts +36 -3
- package/src/shared/constants.ts +28 -0
- package/src/v1/Modal.tsx +159 -0
- package/src/v1/ModalTypes.ts +67 -0
- package/src/v1/index.ts +14 -0
- package/src/v1/styles.tsx +141 -0
- package/src/v2/ModalV2.stories.tsx +282 -0
- package/src/v2/ModalV2.tsx +306 -0
- package/src/v2/ModalV2Styles.tsx +150 -0
- package/src/v2/ModalV2Types.ts +158 -0
- package/src/v2/components/ModalClose.tsx +29 -0
- package/src/v2/components/ModalCloseButton.tsx +100 -0
- package/src/v2/components/ModalContent.tsx +16 -0
- package/src/v2/components/ModalDescription.tsx +19 -0
- package/src/v2/components/ModalFooter.tsx +20 -0
- package/src/v2/components/ModalHeader.tsx +52 -0
- package/src/v2/components/ModalRail.tsx +121 -0
- package/src/v2/components/ModalTrigger.tsx +39 -0
- package/src/v2/components/index.ts +8 -0
- package/src/v2/index.ts +37 -0
- package/tsconfig.json +7 -1
- package/tsup.config.ts +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/v2/index.ts","../../src/v2/ModalV2.tsx","../../src/v2/ModalV2Styles.tsx","../../src/shared/constants.ts","../../src/v2/components/ModalHeader.tsx","../../src/v2/components/ModalCloseButton.tsx","../../src/v2/components/ModalFooter.tsx","../../src/v2/components/ModalContent.tsx","../../src/v2/components/ModalDescription.tsx","../../src/v2/components/ModalTrigger.tsx","../../src/v2/components/ModalClose.tsx","../../src/v2/components/ModalRail.tsx"],"sourcesContent":["// Modal - Explicit named exports for optimal tree shaking\nexport { default as Modal } from \"./ModalV2\";\nexport {\n ModalHeader,\n ModalFooter,\n ModalContent,\n ModalDescription,\n ModalCloseButton,\n ModalTrigger,\n ModalClose,\n ModalRail,\n ModalAction,\n} from \"./components\";\n\n// Explicit type exports\nexport type {\n TypeModalV2Props,\n TypeModalV2TriggerProps,\n TypeModalV2HeaderProps,\n TypeModalV2FooterProps,\n TypeModalV2ContentProps,\n TypeModalV2DescriptionProps,\n TypeModalV2CloseButtonProps,\n TypeModalRailProps,\n TypeModalActionProps,\n} from \"./ModalV2Types\";\n\n// Explicit constant exports\nexport {\n DEFAULT_MODAL_Z_INDEX,\n DEFAULT_OVERLAY_Z_INDEX_OFFSET,\n DEFAULT_MODAL_WIDTH,\n DEFAULT_MODAL_BG,\n BODY_PADDING,\n MODAL_SIZE_PRESETS,\n MODAL_PRIORITY_Z_INDEX,\n} from \"../shared/constants\";\n","import * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { StyledOverlay, StyledContent } from \"./ModalV2Styles\";\nimport {\n ModalHeader,\n ModalDescription,\n ModalTrigger,\n ModalRail,\n ModalAction,\n} from \"./components\";\nimport {\n DEFAULT_MODAL_WIDTH,\n DEFAULT_MODAL_BG,\n DEFAULT_MODAL_Z_INDEX,\n MODAL_SIZE_PRESETS,\n MODAL_PRIORITY_Z_INDEX,\n} from \"../shared/constants\";\nimport type { TypeModalV2Props } from \"./ModalV2Types\";\n\ninterface DraggableModalContentProps {\n children: React.ReactNode;\n computedWidth: any;\n bg: any;\n computedZIndex: number;\n label?: string;\n dataAttributes: Record<string, string>;\n draggable?: boolean;\n rest: any;\n}\n\nconst DraggableModalContent: React.FC<DraggableModalContentProps> = ({\n children,\n computedWidth,\n bg,\n computedZIndex,\n label,\n dataAttributes,\n draggable,\n rest,\n}) => {\n const [position, setPosition] = React.useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = React.useState(false);\n const contentRef = React.useRef<HTMLDivElement>(null);\n\n const handleMouseDown = React.useCallback(\n (e: React.MouseEvent) => {\n if (!draggable) return;\n\n // Only allow dragging from certain areas (not interactive elements)\n const target = e.target as HTMLElement;\n if (\n target.tagName === \"BUTTON\" ||\n target.tagName === \"INPUT\" ||\n target.closest(\"button\")\n ) {\n return;\n }\n\n e.preventDefault();\n setIsDragging(true);\n\n const rect = contentRef.current?.getBoundingClientRect();\n if (!rect) return;\n\n // Calculate offset from mouse to current modal position\n const offsetX = e.clientX - rect.left;\n const offsetY = e.clientY - rect.top;\n\n const handleMouseMove = (e: MouseEvent) => {\n e.preventDefault();\n\n // Calculate new position based on mouse position minus offset\n const newX = e.clientX - offsetX;\n const newY = e.clientY - offsetY;\n\n // Constrain to viewport bounds (keeping modal fully visible)\n const modalWidth = rect.width;\n const modalHeight = rect.height;\n const maxX = window.innerWidth - modalWidth;\n const minX = 0;\n const maxY = window.innerHeight - modalHeight;\n const minY = 0;\n\n const constrainedX = Math.max(minX, Math.min(maxX, newX));\n const constrainedY = Math.max(minY, Math.min(maxY, newY));\n\n // Convert to offset from center for our transform\n const centerX = window.innerWidth / 2 - modalWidth / 2;\n const centerY = window.innerHeight / 2 - modalHeight / 2;\n\n setPosition({\n x: constrainedX - centerX,\n y: constrainedY - centerY,\n });\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n },\n [draggable]\n );\n\n return (\n <StyledContent\n ref={contentRef}\n width={computedWidth}\n bg={bg}\n zIndex={computedZIndex}\n aria-label={label}\n draggable={draggable}\n isDragging={isDragging}\n onMouseDown={handleMouseDown}\n style={\n draggable\n ? {\n transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))`,\n transition: isDragging ? \"none\" : undefined,\n }\n : undefined\n }\n {...dataAttributes}\n {...rest}\n >\n {children}\n </StyledContent>\n );\n};\n\n/**\n * The modal you want - with Radix UI Dialog\n *\n * Features:\n * - Built with Radix UI Dialog for superior accessibility\n * - Same API as the original Modal component\n * - Automatic focus management and keyboard navigation\n * - Portal rendering for proper z-index layering\n * - Customizable styling through system props\n * - Optional draggable functionality using react-dnd\n */\nconst Modal = (props: TypeModalV2Props) => {\n const {\n children,\n modalTrigger,\n draggable = false,\n open,\n defaultOpen,\n onOpenChange,\n \"aria-label\": label,\n title,\n subtitle,\n description,\n size,\n priority,\n data = {},\n bg = DEFAULT_MODAL_BG,\n showOverlay = true,\n actions,\n railProps,\n ...rest\n } = props;\n\n const handleOpenChange = React.useCallback(\n (newOpen: boolean) => {\n onOpenChange?.(newOpen);\n },\n [onOpenChange]\n );\n\n // Compute actual width\n const computedWidth = React.useMemo(() => {\n if (size) {\n // Handle preset sizes\n if (typeof size === \"string\" && size in MODAL_SIZE_PRESETS) {\n return MODAL_SIZE_PRESETS[size as keyof typeof MODAL_SIZE_PRESETS];\n }\n // Handle custom size values\n return size;\n }\n // Fall back to default width\n return DEFAULT_MODAL_WIDTH;\n }, [size]);\n\n // Compute actual z-index\n const computedZIndex = React.useMemo(() => {\n if (priority) {\n return MODAL_PRIORITY_Z_INDEX[priority];\n }\n return DEFAULT_MODAL_Z_INDEX;\n }, [priority]);\n\n // Create data attributes object\n const dataAttributes = React.useMemo(() => {\n const attrs: Record<string, string> = {};\n Object.entries(data).forEach(([key, value]) => {\n attrs[`data-${key}`] = String(value);\n });\n attrs[\"data-qa-modal\"] = \"\";\n // Only add open attribute if in controlled mode\n if (open !== undefined) {\n attrs[\"data-qa-modal-open\"] = String(open);\n }\n return attrs;\n }, [data, open]);\n\n // Determine if we should auto-render the header from provided props\n const shouldRenderHeader = Boolean(title || subtitle);\n\n // Build Dialog.Root props conditionally\n const dialogRootProps = React.useMemo(() => {\n const props: any = {};\n\n // If controlled (open prop provided), use it\n if (open !== undefined) {\n props.open = open;\n }\n // If uncontrolled with explicit defaultOpen, use it\n else if (defaultOpen !== undefined) {\n props.defaultOpen = defaultOpen;\n }\n // If completely uncontrolled (neither open nor defaultOpen provided), default to closed\n else {\n props.defaultOpen = false;\n }\n\n // Always add onOpenChange if provided\n if (onOpenChange) {\n props.onOpenChange = handleOpenChange;\n }\n\n return props;\n }, [open, defaultOpen, handleOpenChange, onOpenChange]);\n\n // Handle trigger - use modalTrigger prop if provided, otherwise look for ModalTrigger children (backward compatibility)\n const triggers: React.ReactNode[] = [];\n const content: React.ReactNode[] = [];\n\n if (modalTrigger) {\n // New prop-based approach: wrap the provided element with Dialog.Trigger\n triggers.push(\n <Dialog.Trigger key=\"modal-trigger\" asChild>\n {modalTrigger}\n </Dialog.Trigger>\n );\n // All children are content\n content.push(children);\n } else {\n // Legacy approach: separate ModalTrigger children from content children\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === ModalTrigger) {\n triggers.push(child);\n } else {\n content.push(child);\n }\n });\n }\n\n return (\n <Dialog.Root {...dialogRootProps}>\n {/* Render triggers as direct children of Dialog.Root */}\n {triggers}\n\n <Dialog.Portal>\n {showOverlay && <StyledOverlay zIndex={computedZIndex} />}\n <DraggableModalContent\n computedWidth={computedWidth}\n bg={bg}\n computedZIndex={computedZIndex}\n label={label}\n dataAttributes={dataAttributes}\n draggable={draggable}\n rest={rest}\n >\n {/* Floating actions rail - always show a close by default */}\n <ModalRail {...railProps}>\n <ModalAction\n actionType=\"close\"\n aria-label=\"Close\"\n iconName=\"x-outline\"\n />\n {actions?.map((action, idx) => (\n <ModalAction key={idx} {...action} />\n ))}\n </ModalRail>\n {/* Auto-render header when title or subtitle is provided */}\n {shouldRenderHeader && (\n <ModalHeader title={title} subtitle={subtitle} />\n )}\n\n {/* Auto-render description when provided */}\n {description && <ModalDescription>{description}</ModalDescription>}\n\n {/* Main content (everything except triggers) */}\n {content}\n </DraggableModalContent>\n </Dialog.Portal>\n </Dialog.Root>\n );\n};\n\nexport default Modal;\n","import React from \"react\";\nimport styled from \"styled-components\";\nimport { width, zIndex } from \"styled-system\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport Box, { type TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\nimport {\n BODY_PADDING,\n DEFAULT_OVERLAY_Z_INDEX_OFFSET,\n} from \"../shared/constants\";\n\ninterface StyledOverlayProps extends TypeContainerProps {\n zIndex?: number;\n}\n\nexport const StyledOverlay = styled(Dialog.Overlay)<StyledOverlayProps>`\n position: fixed;\n top: 0px;\n left: 0px;\n right: 0px;\n bottom: 0px;\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 z-index: ${(props) =>\n props.zIndex ? props.zIndex + DEFAULT_OVERLAY_Z_INDEX_OFFSET : 999};\n\n ${zIndex}\n\n &[data-state=\"open\"] {\n opacity: 1;\n }\n &[data-state=\"closed\"] {\n opacity: 0;\n }\n`;\n\ninterface StyledContentProps extends TypeContainerProps {\n zIndex?: number;\n isDragging?: boolean;\n draggable?: boolean;\n}\n\nexport const StyledContent = styled(Dialog.Content)<StyledContentProps>`\n position: fixed;\n ${(props) =>\n props.draggable\n ? `\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n `\n : `\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n `}\n display: flex;\n flex-direction: column;\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 outline: none;\n max-width: calc(100vw - ${BODY_PADDING});\n max-height: calc(100vh - ${BODY_PADDING});\n z-index: ${(props) => props.zIndex || 1000};\n\n /* Draggable styling */\n ${(props) =>\n props.draggable &&\n `\n cursor: ${props.isDragging ? \"grabbing\" : \"grab\"};\n user-select: none;\n `}\n\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n height: calc(100vh - ${BODY_PADDING});\n }\n\n ${width}\n ${COMMON}\n\n /* Enhanced Radix Dialog animations */\n opacity: 0;\n ${(props) =>\n !props.draggable\n ? `\n transform: translate(-50%, -50%) scale(0.95);\n transition: opacity ${props.theme.duration.medium} ${props.theme.easing.ease_inout},\n transform ${props.theme.duration.medium} ${props.theme.easing.ease_inout};\n `\n : `\n transition: opacity ${props.theme.duration.medium} ${props.theme.easing.ease_inout};\n `}\n\n &[data-state=\"open\"] {\n opacity: 1;\n ${(props) =>\n !props.draggable ? `transform: translate(-50%, -50%) scale(1);` : ``}\n }\n &[data-state=\"closed\"] {\n opacity: 0;\n ${(props) =>\n !props.draggable ? `transform: translate(-50%, -50%) scale(0.95);` : ``}\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: 0 ${(props) => props.theme.space[300]}\n ${(props) => props.theme.space[300]} ${(props) => props.theme.space[300]};\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n flex-basis: 100%;\n }\n`;\n\nexport const Header = styled(Box)`\n font-family: ${(props) => props.theme.fontFamily};\n padding: ${(props) => props.theme.space[400]}\n ${(props) => props.theme.space[300]};\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\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[300]};\n border-bottom-right-radius: ${(props) => props.theme.radii[500]};\n border-bottom-left-radius: ${(props) => props.theme.radii[500]};\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: ${(props) => props.theme.space[100]};\n`;\n\nStyledOverlay.displayName = \"ModalOverlay\";\nStyledContent.displayName = \"ModalContent\";\nContent.displayName = \"ModalContent\";\nHeader.displayName = \"ModalHeader\";\nFooter.displayName = \"ModalFooter\";\n","// Shared constants for both Modal versions\n\n// Default z-index values\nexport const DEFAULT_MODAL_Z_INDEX = 6;\nexport const DEFAULT_OVERLAY_Z_INDEX_OFFSET = -1;\n\n// Default styling values\nexport const DEFAULT_MODAL_WIDTH = \"600px\";\nexport const DEFAULT_MODAL_BG = \"container.background.base\";\nexport const DEFAULT_CLOSE_BUTTON_LABEL = \"Close dialog\";\n\n// Max space allowed between the modal and the edge of the browser\nexport const BODY_PADDING = \"64px\";\n\n// Size presets for simplified API\nexport const MODAL_SIZE_PRESETS = {\n small: \"400px\",\n medium: \"600px\",\n large: \"800px\",\n full: \"90vw\",\n} as const;\n\n// Priority level z-index mappings\nexport const MODAL_PRIORITY_Z_INDEX = {\n low: 100,\n medium: 1000,\n high: 2000,\n} as const;\n","import * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { Header } from \"../ModalV2Styles\";\nimport { ModalCloseButton } from \"./ModalCloseButton\";\nimport type { TypeModalV2HeaderProps } from \"../ModalV2Types\";\n\nexport const ModalHeader = (props: TypeModalV2HeaderProps) => {\n const {\n title,\n subtitle,\n children,\n bordered,\n titleProps = {},\n subtitleProps = {},\n showInlineClose,\n ...rest\n } = props;\n\n return (\n <Header {...rest}>\n {children ? (\n children\n ) : (\n <React.Fragment>\n <Box>\n {title && (\n <Dialog.Title asChild {...titleProps}>\n <Text.Headline>{title}</Text.Headline>\n </Dialog.Title>\n )}\n {subtitle && (\n <Dialog.Description asChild {...subtitleProps}>\n <Text as=\"div\" fontSize={200}>\n {subtitle}\n </Text>\n </Dialog.Description>\n )}\n </Box>\n {showInlineClose && (\n <Box display=\"flex\" alignItems=\"center\" justifyContent=\"flex-end\">\n <ModalCloseButton position=\"relative\" offset={0} />\n </Box>\n )}\n </React.Fragment>\n )}\n </Header>\n );\n};\n\nModalHeader.displayName = \"ModalHeader\";\n","import * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport styled from \"styled-components\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport type { TypeModalV2CloseButtonProps } from \"../ModalV2Types\";\n\nconst CloseButtonWrapper = styled.button<{\n size?: number;\n position?: \"absolute\" | \"relative\";\n side?: \"right\" | \"left\";\n offset?: number;\n}>`\n width: ${(p) => p.size || 44}px;\n height: ${(p) => p.size || 44}px;\n display: inline-grid;\n place-items: center;\n border-radius: 8px;\n border: none;\n background: rgba(22, 32, 32, 0.56);\n color: #ffffff;\n cursor: pointer;\n outline: none;\n transition: all 0.2s ease;\n\n ${(p) =>\n p.position === \"absolute\" &&\n `\n position: absolute;\n top: 0px;\n ${p.side || \"right\"}: ${p.offset || -48}px;\n z-index: 1;\n `}\n\n &:hover {\n background: rgba(22, 32, 32, 0.7);\n transform: translateY(-1px);\n }\n\n &:active {\n transform: translateY(0);\n }\n\n &:focus-visible {\n box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #205bc3;\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\n\nexport const ModalCloseButton = (props: TypeModalV2CloseButtonProps) => {\n const {\n children,\n onClick,\n asChild,\n closeButtonLabel = \"Close modal\",\n size = 44,\n position = \"absolute\",\n side = \"right\",\n offset = -48,\n ...rest\n } = props;\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n // Dialog.Close automatically handles closing\n };\n\n if (asChild) {\n return (\n <Dialog.Close asChild>\n {React.cloneElement(children as React.ReactElement, {\n onClick: handleClick,\n ...rest,\n })}\n </Dialog.Close>\n );\n }\n\n return (\n <Dialog.Close asChild>\n <CloseButtonWrapper\n onClick={handleClick}\n size={size}\n position={position}\n side={side}\n offset={offset}\n aria-label={closeButtonLabel}\n title={closeButtonLabel}\n {...rest}\n >\n {children || <Icon name=\"x-outline\" size=\"small\" />}\n </CloseButtonWrapper>\n </Dialog.Close>\n );\n};\n\nModalCloseButton.displayName = \"ModalCloseButton\";\n","import * as React from \"react\";\nimport { Footer } from \"../ModalV2Styles\";\nimport { DEFAULT_MODAL_BG } from \"../../shared/constants\";\nimport type { TypeModalV2FooterProps } from \"../ModalV2Types\";\n\nexport const ModalFooter = (props: TypeModalV2FooterProps) => {\n const { bg = DEFAULT_MODAL_BG, children, ...rest } = props;\n return (\n <Footer\n bg={bg}\n borderTop={500}\n borderColor=\"container.border.base\"\n {...rest}\n >\n {children}\n </Footer>\n );\n};\n\nModalFooter.displayName = \"ModalFooter\";\n","import * as React from \"react\";\nimport { Content } from \"../ModalV2Styles\";\nimport type { TypeModalV2ContentProps } from \"../ModalV2Types\";\n\nexport const ModalContent = React.forwardRef<\n HTMLDivElement,\n TypeModalV2ContentProps\n>(({ children, ...rest }, ref) => {\n return (\n <Content data-qa-modal ref={ref} {...rest}>\n {children}\n </Content>\n );\n});\n\nModalContent.displayName = \"ModalContent\";\n","import * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeModalV2DescriptionProps } from \"../ModalV2Types\";\n\nexport const ModalDescription = React.forwardRef<\n HTMLDivElement,\n TypeModalV2DescriptionProps\n>(({ children, descriptionProps = {}, ...rest }, ref) => {\n return (\n <Dialog.Description asChild {...descriptionProps}>\n <Box ref={ref} {...rest}>\n {children}\n </Box>\n </Dialog.Description>\n );\n});\n\nModalDescription.displayName = \"ModalDescription\";\n","import * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport type { TypeModalV2TriggerProps } from \"../ModalV2Types\";\n\n/**\n * A trigger button that opens the modal when clicked.\n * Must be used inside a Modal component's Dialog.Root context.\n * Uses Seeds Button by default but supports asChild for custom elements.\n */\nexport const ModalTrigger = (props: TypeModalV2TriggerProps) => {\n const { children, onClick, asChild, ...rest } = props;\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n // Dialog.Trigger automatically handles modal opening\n };\n\n if (asChild) {\n return (\n <Dialog.Trigger asChild>\n {React.cloneElement(children as React.ReactElement, {\n onClick: handleClick,\n ...rest,\n })}\n </Dialog.Trigger>\n );\n }\n\n return (\n <Dialog.Trigger asChild>\n <Button onClick={handleClick} {...rest}>\n {children}\n </Button>\n </Dialog.Trigger>\n );\n};\n\nModalTrigger.displayName = \"ModalTrigger\";\n","import * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\n\nexport interface ModalCloseProps {\n children: React.ReactNode;\n onClick?: (e: React.MouseEvent) => void;\n asChild?: boolean;\n}\n\n/**\n * A component that closes the modal when clicked.\n * Uses asChild pattern like Radix primitives.\n */\nexport const ModalClose = (props: ModalCloseProps) => {\n const { children, onClick, asChild = false, ...rest } = props;\n\n const handleClick = (e: React.MouseEvent) => {\n onClick?.(e);\n // Dialog.Close automatically handles closing\n };\n\n return (\n <Dialog.Close asChild={asChild} onClick={handleClick} {...rest}>\n {children}\n </Dialog.Close>\n );\n};\n\nModalClose.displayName = \"ModalClose\";\n","// components/ModalRail.tsx\nimport * as React from \"react\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport styled from \"styled-components\";\nimport Icon from \"@sproutsocial/seeds-react-icon\"; // adjust import if path differs\nimport type { TypeModalRailProps, TypeModalActionProps } from \"../ModalV2Types\";\n\n// --- styled wrappers ---\nconst Rail = styled.div<{\n side: \"right\" | \"left\";\n offset: number;\n gap: number;\n size: number;\n collapseAt: number;\n}>`\n position: absolute;\n top: ${(p) => p.offset}px;\n ${(p) =>\n p.side === \"right\"\n ? `right: calc(-1 * (${p.size}px + ${p.offset}px));`\n : `left: calc(-1 * (${p.size}px + ${p.offset}px));`}\n display: grid;\n grid-auto-flow: row;\n gap: ${(p) => p.gap}px;\n z-index: 1;\n\n @media (max-width: ${(p) => p.collapseAt}px) {\n ${(p) =>\n p.side === \"right\" ? `right: ${p.offset}px;` : `left: ${p.offset}px;`}\n }\n`;\n\nconst RailBtn = styled.button<{ size: number }>`\n width: ${(p) => p.size}px;\n height: ${(p) => p.size}px;\n display: inline-grid;\n place-items: center;\n border-radius: 8px;\n border: none;\n background: rgba(22, 32, 32, 0.56);\n color: #ffffff;\n cursor: pointer;\n outline: none;\n transition: all 0.2s ease;\n\n &:hover {\n background: rgba(22, 32, 32, 0.7);\n transform: translateY(-1px);\n }\n\n &:active {\n transform: translateY(0);\n }\n\n &:focus-visible {\n box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #205bc3;\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\n\n// --- components ---\nexport const ModalRail: React.FC<TypeModalRailProps> = ({\n side = \"right\",\n offset = 12,\n gap = 12,\n size = 44,\n collapseAt = 640,\n children,\n}) => {\n return (\n <Rail\n data-slot=\"modal-rail\"\n side={side}\n offset={offset}\n gap={gap}\n size={size}\n collapseAt={collapseAt}\n aria-label=\"Modal quick actions\"\n >\n {React.Children.map(children, (child) =>\n React.isValidElement(child)\n ? React.cloneElement(child as any, { size })\n : child\n )}\n </Rail>\n );\n};\n\nexport const ModalAction: React.FC<\n TypeModalActionProps & { size?: number }\n> = ({\n \"aria-label\": ariaLabel,\n iconName,\n disabled,\n size = 44,\n actionType,\n onClick,\n ...rest\n}) => {\n const Btn = (\n <RailBtn\n size={size}\n aria-label={ariaLabel}\n title={ariaLabel}\n disabled={disabled}\n {...rest}\n >\n {iconName ? <Icon name={iconName} size=\"small\" /> : ariaLabel}\n </RailBtn>\n );\n\n return actionType === \"close\" ? (\n <Dialog.Close asChild>{Btn}</Dialog.Close>\n ) : (\n React.cloneElement(Btn, { onClick })\n );\n};\n"],"mappings":"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","names":["React","Dialog","styled","Content","Box","React","Dialog","import_seeds_react_box","React","Dialog","import_styled_components","styled","Icon","import_jsx_runtime","Box","Text","React","import_jsx_runtime","React","import_jsx_runtime","Content","React","Dialog","import_seeds_react_box","import_jsx_runtime","Box","React","Dialog","import_jsx_runtime","Button","React","Dialog","import_jsx_runtime","React","Dialog","import_styled_components","import_seeds_react_icon","import_jsx_runtime","styled","Icon","import_jsx_runtime","e","props"]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sproutsocial/seeds-react-modal",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Seeds React Modal",
|
|
5
5
|
"author": "Sprout Social, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/esm/index.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/esm/index.js",
|
|
14
|
+
"require": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./v1": {
|
|
17
|
+
"types": "./dist/v1/index.d.ts",
|
|
18
|
+
"import": "./dist/esm/v1/index.js",
|
|
19
|
+
"require": "./dist/v1/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./v2": {
|
|
22
|
+
"types": "./dist/v2/index.d.ts",
|
|
23
|
+
"import": "./dist/esm/v2/index.js",
|
|
24
|
+
"require": "./dist/v2/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
10
27
|
"scripts": {
|
|
11
28
|
"build": "tsup --dts",
|
|
12
29
|
"build:debug": "tsup --dts --metafile",
|
|
@@ -18,30 +35,33 @@
|
|
|
18
35
|
"test:watch": "jest --watch --coverage=false"
|
|
19
36
|
},
|
|
20
37
|
"dependencies": {
|
|
21
|
-
"@
|
|
38
|
+
"@radix-ui/react-dialog": "^1.1.14",
|
|
39
|
+
"@sproutsocial/seeds-react-box": "^1.1.3",
|
|
40
|
+
"@sproutsocial/seeds-react-button": "^1.2.2",
|
|
41
|
+
"@sproutsocial/seeds-react-icon": "^1.1.3",
|
|
22
42
|
"@sproutsocial/seeds-react-system-props": "^3.0.1",
|
|
23
|
-
"@sproutsocial/seeds-react-
|
|
24
|
-
"@sproutsocial/seeds-react-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
43
|
+
"@sproutsocial/seeds-react-text": "^1.3.2",
|
|
44
|
+
"@sproutsocial/seeds-react-theme": "^3.0.1",
|
|
45
|
+
"react-dnd": "^16.0.1",
|
|
46
|
+
"react-dnd-html5-backend": "^16.0.1",
|
|
27
47
|
"react-modal": "^3.16.1",
|
|
28
48
|
"styled-system": "^5.1.5"
|
|
29
49
|
},
|
|
30
50
|
"devDependencies": {
|
|
51
|
+
"@sproutsocial/eslint-config-seeds": "*",
|
|
52
|
+
"@sproutsocial/seeds-react-form-field": "^1.0.2",
|
|
53
|
+
"@sproutsocial/seeds-react-input": "^1.4.4",
|
|
54
|
+
"@sproutsocial/seeds-react-testing-library": "*",
|
|
55
|
+
"@sproutsocial/seeds-testing": "*",
|
|
56
|
+
"@sproutsocial/seeds-tsconfig": "*",
|
|
31
57
|
"@types/react": "^18.0.0",
|
|
58
|
+
"@types/react-modal": "^3.16.0",
|
|
32
59
|
"@types/styled-components": "^5.1.26",
|
|
33
|
-
"@
|
|
60
|
+
"@types/styled-system": "^5.1.15",
|
|
34
61
|
"react": "^18.0.0",
|
|
35
62
|
"styled-components": "^5.2.3",
|
|
36
|
-
"tsup": "^8.
|
|
37
|
-
"typescript": "^5.6.2"
|
|
38
|
-
"@sproutsocial/seeds-tsconfig": "*",
|
|
39
|
-
"@sproutsocial/seeds-testing": "*",
|
|
40
|
-
"@sproutsocial/seeds-react-testing-library": "*",
|
|
41
|
-
"@sproutsocial/seeds-react-input": "^1.3.1",
|
|
42
|
-
"@sproutsocial/seeds-react-form-field": "^1.0.0",
|
|
43
|
-
"@types/react-modal": "^3.16.0",
|
|
44
|
-
"@types/styled-system": "^5.1.15"
|
|
63
|
+
"tsup": "^8.3.4",
|
|
64
|
+
"typescript": "^5.6.2"
|
|
45
65
|
},
|
|
46
66
|
"peerDependencies": {
|
|
47
67
|
"styled-components": "^5.2.3"
|
package/src/Modal.stories.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { Button } from "@sproutsocial/seeds-react-button";
|
|
|
5
5
|
import { FormField } from "@sproutsocial/seeds-react-form-field";
|
|
6
6
|
import { Input } from "@sproutsocial/seeds-react-input";
|
|
7
7
|
import { Text } from "@sproutsocial/seeds-react-text";
|
|
8
|
-
import Modal from "./Modal";
|
|
8
|
+
import Modal from "./v1/Modal";
|
|
9
9
|
|
|
10
10
|
interface StatefulStoryProps<T> {
|
|
11
11
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { COLOR_PURPLE_300 } from "@sproutsocial/seeds-color";
|
|
4
|
+
import {
|
|
5
|
+
render,
|
|
6
|
+
fireEvent,
|
|
7
|
+
cleanup,
|
|
8
|
+
screen,
|
|
9
|
+
} from "@sproutsocial/seeds-react-testing-library";
|
|
10
|
+
import Modal from "../../v1/Modal";
|
|
11
|
+
|
|
12
|
+
afterEach(() => cleanup());
|
|
13
|
+
|
|
14
|
+
describe("Modal", () => {
|
|
15
|
+
it("renders a custom background color", () => {
|
|
16
|
+
// Use baseElement since it renders in a Portal
|
|
17
|
+
render(
|
|
18
|
+
<Modal
|
|
19
|
+
isOpen={true}
|
|
20
|
+
label="Label"
|
|
21
|
+
bg={COLOR_PURPLE_300}
|
|
22
|
+
onClose={() => {}}
|
|
23
|
+
closeButtonLabel="Close this dialog"
|
|
24
|
+
>
|
|
25
|
+
ajdsfljasdlfjlasdjf
|
|
26
|
+
</Modal>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
expect(screen.getByRole("dialog")).toHaveStyleRule(
|
|
30
|
+
"background-color",
|
|
31
|
+
COLOR_PURPLE_300
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should close on overlay click and esc", () => {
|
|
36
|
+
const onClose = jest.fn();
|
|
37
|
+
render(
|
|
38
|
+
<Modal
|
|
39
|
+
isOpen={true}
|
|
40
|
+
label="Label"
|
|
41
|
+
bg={COLOR_PURPLE_300}
|
|
42
|
+
onClose={onClose}
|
|
43
|
+
closeButtonLabel="Close this dialog"
|
|
44
|
+
>
|
|
45
|
+
<Modal.Header>
|
|
46
|
+
<Modal.CloseButton />
|
|
47
|
+
</Modal.Header>
|
|
48
|
+
ajdsfljasdlfjlasdjf
|
|
49
|
+
</Modal>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
fireEvent.click(screen.getByRole("dialog").parentElement as HTMLElement);
|
|
53
|
+
expect(onClose).toHaveBeenCalled();
|
|
54
|
+
|
|
55
|
+
onClose.mockClear();
|
|
56
|
+
fireEvent.keyDown(screen.getByText("ajdsfljasdlfjlasdjf"), {
|
|
57
|
+
key: "Escape",
|
|
58
|
+
keyCode: 27,
|
|
59
|
+
});
|
|
60
|
+
expect(onClose).toHaveBeenCalled();
|
|
61
|
+
|
|
62
|
+
onClose.mockClear();
|
|
63
|
+
fireEvent.click(screen.getByLabelText("Close this dialog"));
|
|
64
|
+
expect(onClose).toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should NOT close on overlay click and esc if onClick is not provided", () => {
|
|
68
|
+
const onClose = jest.fn();
|
|
69
|
+
const { baseElement, getByText, queryByLabelText } = render(
|
|
70
|
+
<Modal
|
|
71
|
+
isOpen={true}
|
|
72
|
+
label="Label"
|
|
73
|
+
bg={COLOR_PURPLE_300}
|
|
74
|
+
closeButtonLabel="Close this dialog"
|
|
75
|
+
>
|
|
76
|
+
ajdsfljasdlfjlasdjf
|
|
77
|
+
</Modal>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
expect(queryByLabelText("Close this dialog")).not.toBeInTheDocument();
|
|
81
|
+
|
|
82
|
+
fireEvent.click(screen.getByRole("dialog").parentElement as HTMLElement);
|
|
83
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
84
|
+
|
|
85
|
+
onClose.mockClear();
|
|
86
|
+
fireEvent.keyDown(screen.getByText("ajdsfljasdlfjlasdjf"), {
|
|
87
|
+
key: "Escape",
|
|
88
|
+
keyCode: 27,
|
|
89
|
+
});
|
|
90
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("Modal.Header", () => {
|
|
94
|
+
it("should have an aria-label on the close button", () => {
|
|
95
|
+
render(
|
|
96
|
+
<Modal
|
|
97
|
+
isOpen={true}
|
|
98
|
+
label="Label"
|
|
99
|
+
bg={COLOR_PURPLE_300}
|
|
100
|
+
onClose={() => {}}
|
|
101
|
+
closeButtonLabel="Close this dialog"
|
|
102
|
+
>
|
|
103
|
+
<Modal.Header>
|
|
104
|
+
<Modal.CloseButton />
|
|
105
|
+
</Modal.Header>
|
|
106
|
+
ajdsfljasdlfjlasdjf
|
|
107
|
+
</Modal>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(screen.getByLabelText("Close this dialog")).toBeInTheDocument();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should accept the onClose handler from ModalContext", () => {
|
|
114
|
+
const onClose = jest.fn();
|
|
115
|
+
render(
|
|
116
|
+
<Modal
|
|
117
|
+
isOpen={true}
|
|
118
|
+
label="Label"
|
|
119
|
+
bg={COLOR_PURPLE_300}
|
|
120
|
+
onClose={onClose}
|
|
121
|
+
closeButtonLabel="Close this dialog"
|
|
122
|
+
>
|
|
123
|
+
<Modal.Header>
|
|
124
|
+
<Modal.CloseButton />
|
|
125
|
+
</Modal.Header>
|
|
126
|
+
ajdsfljasdlfjlasdjf
|
|
127
|
+
</Modal>
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
fireEvent.click(screen.getByLabelText("Close this dialog"));
|
|
131
|
+
expect(onClose).toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Box } from "@sproutsocial/seeds-react-box";
|
|
3
|
+
import { Button } from "@sproutsocial/seeds-react-button";
|
|
4
|
+
import { Input } from "@sproutsocial/seeds-react-input";
|
|
5
|
+
import { Text } from "@sproutsocial/seeds-react-text";
|
|
6
|
+
import Modal from "../../v1/Modal";
|
|
7
|
+
import FormField from "@sproutsocial/seeds-react-form-field";
|
|
8
|
+
|
|
9
|
+
const longContent = `
|
|
10
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
11
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem
|
|
12
|
+
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
13
|
+
tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum
|
|
14
|
+
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
15
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
16
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
17
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
18
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
19
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
20
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
21
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
22
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
23
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
24
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
25
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
26
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
27
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
28
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
29
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
30
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
31
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
32
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
33
|
+
incididunt ut labore et dolore magna aliqua.`;
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
36
|
+
function ModalTypeTest() {
|
|
37
|
+
return (
|
|
38
|
+
<>
|
|
39
|
+
<Modal
|
|
40
|
+
appElementSelector="#root"
|
|
41
|
+
isOpen={true}
|
|
42
|
+
onClose={jest.fn()}
|
|
43
|
+
closeButtonLabel="Close this dialog"
|
|
44
|
+
label="Example Modal"
|
|
45
|
+
>
|
|
46
|
+
<React.Fragment>
|
|
47
|
+
<Modal.Header
|
|
48
|
+
title="Assign Chatbot"
|
|
49
|
+
subtitle="The chatbot will respond to customers from this profile."
|
|
50
|
+
/>
|
|
51
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
52
|
+
<Modal.Footer>
|
|
53
|
+
<Button appearance="primary" width={1}>
|
|
54
|
+
Full-Width Button
|
|
55
|
+
</Button>
|
|
56
|
+
</Modal.Footer>
|
|
57
|
+
</React.Fragment>
|
|
58
|
+
</Modal>
|
|
59
|
+
<Modal
|
|
60
|
+
appElementSelector="#root"
|
|
61
|
+
isOpen={false}
|
|
62
|
+
closeButtonLabel="n/a"
|
|
63
|
+
label="Example Modal"
|
|
64
|
+
>
|
|
65
|
+
<React.Fragment>
|
|
66
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
67
|
+
<Modal.Footer>
|
|
68
|
+
<Button appearance="primary" width={1} onClick={jest.fn()}>
|
|
69
|
+
Must click to close
|
|
70
|
+
</Button>
|
|
71
|
+
</Modal.Footer>
|
|
72
|
+
</React.Fragment>
|
|
73
|
+
</Modal>
|
|
74
|
+
<Modal
|
|
75
|
+
appElementSelector="#root"
|
|
76
|
+
isOpen={true}
|
|
77
|
+
onClose={jest.fn()}
|
|
78
|
+
closeButtonLabel="Close this dialog"
|
|
79
|
+
label="Example Modal"
|
|
80
|
+
>
|
|
81
|
+
<React.Fragment>
|
|
82
|
+
<Modal.Header title="" subtitle="" bordered>
|
|
83
|
+
<Box width="100%" bg="purple.400">
|
|
84
|
+
Custom header
|
|
85
|
+
</Box>
|
|
86
|
+
</Modal.Header>
|
|
87
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
88
|
+
<Modal.Footer>
|
|
89
|
+
<Button appearance="primary" width={1}>
|
|
90
|
+
Full-Width Button
|
|
91
|
+
</Button>
|
|
92
|
+
</Modal.Footer>
|
|
93
|
+
</React.Fragment>
|
|
94
|
+
</Modal>
|
|
95
|
+
<Modal
|
|
96
|
+
appElementSelector="#root"
|
|
97
|
+
isOpen={false}
|
|
98
|
+
onClose={jest.fn()}
|
|
99
|
+
closeButtonLabel="Close this dialog"
|
|
100
|
+
label="Example Modal"
|
|
101
|
+
>
|
|
102
|
+
<React.Fragment>
|
|
103
|
+
<Modal.Header bordered>
|
|
104
|
+
<Box>
|
|
105
|
+
<Text as="h1" fontSize={400} fontWeight="semibold">
|
|
106
|
+
Assign Chatbot
|
|
107
|
+
</Text>
|
|
108
|
+
<Text as="div" fontSize={200}>
|
|
109
|
+
The chatbot will respond to customers from this profile.
|
|
110
|
+
</Text>
|
|
111
|
+
</Box>
|
|
112
|
+
<Box>
|
|
113
|
+
<button>dummy button 1</button>
|
|
114
|
+
<button>dummy button 2</button>
|
|
115
|
+
<Modal.CloseButton />
|
|
116
|
+
</Box>
|
|
117
|
+
</Modal.Header>
|
|
118
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
119
|
+
</React.Fragment>
|
|
120
|
+
</Modal>
|
|
121
|
+
<Modal
|
|
122
|
+
appElementSelector="#root"
|
|
123
|
+
isOpen={true}
|
|
124
|
+
onClose={jest.fn()}
|
|
125
|
+
closeButtonLabel="Close this dialog"
|
|
126
|
+
label="Example Modal"
|
|
127
|
+
>
|
|
128
|
+
<React.Fragment>
|
|
129
|
+
<Modal.Header />
|
|
130
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
131
|
+
<Modal.Footer>
|
|
132
|
+
<Button appearance="primary" width={1}>
|
|
133
|
+
Full-Width Button
|
|
134
|
+
</Button>
|
|
135
|
+
</Modal.Footer>
|
|
136
|
+
</React.Fragment>
|
|
137
|
+
</Modal>
|
|
138
|
+
<Modal
|
|
139
|
+
width="500px"
|
|
140
|
+
appElementSelector="#root"
|
|
141
|
+
isOpen={true}
|
|
142
|
+
onClose={jest.fn()}
|
|
143
|
+
closeButtonLabel="Close this dialog"
|
|
144
|
+
label="Example Modal"
|
|
145
|
+
>
|
|
146
|
+
<React.Fragment>
|
|
147
|
+
<Modal.Header
|
|
148
|
+
title="Create Share Link"
|
|
149
|
+
subtitle="Anyone with this link will be able to view its contents."
|
|
150
|
+
/>
|
|
151
|
+
<Modal.Content>
|
|
152
|
+
<FormField
|
|
153
|
+
label="Label"
|
|
154
|
+
helperText="This is some helpful helper text"
|
|
155
|
+
>
|
|
156
|
+
{
|
|
157
|
+
// is there a reason that the props are not passed to the input?
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
159
|
+
(props) => (
|
|
160
|
+
<Input
|
|
161
|
+
placeholder="Type the things..."
|
|
162
|
+
name="title"
|
|
163
|
+
id="title"
|
|
164
|
+
/>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
</FormField>
|
|
168
|
+
</Modal.Content>
|
|
169
|
+
<Modal.Footer>
|
|
170
|
+
<Box display="flex" justifyContent="flex-end">
|
|
171
|
+
<Button appearance="primary">Create Link</Button>
|
|
172
|
+
</Box>
|
|
173
|
+
</Modal.Footer>
|
|
174
|
+
</React.Fragment>
|
|
175
|
+
</Modal>
|
|
176
|
+
<Modal
|
|
177
|
+
bg="container.background.decorative.purple"
|
|
178
|
+
width="500px"
|
|
179
|
+
appElementSelector="#root"
|
|
180
|
+
isOpen={true}
|
|
181
|
+
onClose={jest.fn()}
|
|
182
|
+
closeButtonLabel="Close this dialog"
|
|
183
|
+
label="Example Modal"
|
|
184
|
+
>
|
|
185
|
+
<React.Fragment>
|
|
186
|
+
<Modal.Header
|
|
187
|
+
title="Create Share Link"
|
|
188
|
+
subtitle="Anyone with this link will be able to view its contents."
|
|
189
|
+
/>
|
|
190
|
+
<Modal.Content>
|
|
191
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
192
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem
|
|
193
|
+
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
194
|
+
tempor incididunt ut labore et dolore magna aliqua.
|
|
195
|
+
</Modal.Content>
|
|
196
|
+
<Modal.Footer>
|
|
197
|
+
<Box display="flex" justifyContent="flex-end">
|
|
198
|
+
<Button appearance="primary">Create Link</Button>
|
|
199
|
+
</Box>
|
|
200
|
+
</Modal.Footer>
|
|
201
|
+
</React.Fragment>
|
|
202
|
+
</Modal>
|
|
203
|
+
{/* @ts-expect-error - test that missing required props is rejected */}
|
|
204
|
+
<Modal />
|
|
205
|
+
</>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export default ModalTypeTest;
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Main export - V1 Modal for backwards compatibility
|
|
2
|
+
import Modal from "./v1";
|
|
3
3
|
export default Modal;
|
|
4
4
|
export { Modal };
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
// Explicit type exports from V1 for tree shaking
|
|
7
|
+
export type {
|
|
8
|
+
TypeModalProps,
|
|
9
|
+
TypeModalHeaderProps,
|
|
10
|
+
TypeModalFooterProps,
|
|
11
|
+
TypeModalContentProps,
|
|
12
|
+
TypeModalCloseButtonProps,
|
|
13
|
+
} from "./v1";
|
|
14
|
+
|
|
15
|
+
// V2 Modal exports
|
|
16
|
+
export {
|
|
17
|
+
Modal as ModalV2,
|
|
18
|
+
ModalTrigger,
|
|
19
|
+
ModalDescription,
|
|
20
|
+
ModalHeader,
|
|
21
|
+
ModalFooter,
|
|
22
|
+
ModalContent,
|
|
23
|
+
ModalCloseButton,
|
|
24
|
+
ModalClose,
|
|
25
|
+
ModalRail,
|
|
26
|
+
ModalAction,
|
|
27
|
+
} from "./v2";
|
|
28
|
+
export type {
|
|
29
|
+
TypeModalV2Props,
|
|
30
|
+
TypeModalV2TriggerProps,
|
|
31
|
+
TypeModalV2CloseButtonProps,
|
|
32
|
+
TypeModalV2HeaderProps,
|
|
33
|
+
TypeModalV2FooterProps,
|
|
34
|
+
TypeModalV2ContentProps,
|
|
35
|
+
TypeModalV2DescriptionProps,
|
|
36
|
+
TypeModalRailProps,
|
|
37
|
+
TypeModalActionProps,
|
|
38
|
+
} from "./v2";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Shared constants for both Modal versions
|
|
2
|
+
|
|
3
|
+
// Default z-index values
|
|
4
|
+
export const DEFAULT_MODAL_Z_INDEX = 6;
|
|
5
|
+
export const DEFAULT_OVERLAY_Z_INDEX_OFFSET = -1;
|
|
6
|
+
|
|
7
|
+
// Default styling values
|
|
8
|
+
export const DEFAULT_MODAL_WIDTH = "600px";
|
|
9
|
+
export const DEFAULT_MODAL_BG = "container.background.base";
|
|
10
|
+
export const DEFAULT_CLOSE_BUTTON_LABEL = "Close dialog";
|
|
11
|
+
|
|
12
|
+
// Max space allowed between the modal and the edge of the browser
|
|
13
|
+
export const BODY_PADDING = "64px";
|
|
14
|
+
|
|
15
|
+
// Size presets for simplified API
|
|
16
|
+
export const MODAL_SIZE_PRESETS = {
|
|
17
|
+
small: "400px",
|
|
18
|
+
medium: "600px",
|
|
19
|
+
large: "800px",
|
|
20
|
+
full: "90vw",
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
// Priority level z-index mappings
|
|
24
|
+
export const MODAL_PRIORITY_Z_INDEX = {
|
|
25
|
+
low: 100,
|
|
26
|
+
medium: 1000,
|
|
27
|
+
high: 2000,
|
|
28
|
+
} as const;
|