@xsolla/xui-modal 0.158.0 → 0.160.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.tsx","../../src/Modal.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/WorkArea.tsx","../../src/ModalProvider.tsx","../../src/ModalContext.ts","../../src/ModalRoot.native.tsx","../../src/useModal.ts"],"sourcesContent":["export * from \"./Modal\";\nexport * from \"./ModalProvider\";\nexport * from \"./useModal\";\nexport * from \"./types\";\nexport * from \"./WorkArea\";\nexport { useModalId } from \"@xsolla/xui-core\";\n","import { forwardRef, useEffect, useRef, useCallback } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId, ModalIdContext } from \"@xsolla/xui-core\";\nimport { FlexButton } from \"@xsolla/xui-button\";\nimport { ChevronLeft, Remove } from \"@xsolla/xui-icons-base\";\nimport type { ModalProps } from \"./types\";\nimport { WorkArea } from \"./WorkArea\";\n\nconst FOCUSABLE_SELECTORS =\n 'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst isElementVisible = (el: HTMLElement): boolean => {\n if (el.offsetParent === null && getComputedStyle(el).position !== \"fixed\")\n return false;\n const style = getComputedStyle(el);\n return style.visibility !== \"hidden\" && style.display !== \"none\";\n};\n\nconst getFocusableElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS)\n ).filter(isElementVisible);\n\nexport const Modal = forwardRef<any, ModalProps>(\n (\n {\n children,\n type = \"popup\",\n openContent = false,\n closeOutside = true,\n onClose,\n onBack,\n align,\n header,\n footer,\n styled: styledProps,\n maxWidth,\n minHeight,\n title,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n initialFocusRef,\n themeMode,\n themeProductContext,\n ...rest\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const modalRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n const titleId = useId();\n\n useEffect(() => {\n previousActiveElement.current = document.activeElement as HTMLElement;\n\n const focusTarget =\n initialFocusRef?.current ||\n closeButtonRef.current ||\n (modalRef.current && getFocusableElements(modalRef.current)[0]);\n\n if (focusTarget) {\n focusTarget.focus();\n } else {\n modalRef.current?.focus();\n }\n\n return () => {\n previousActiveElement.current?.focus();\n };\n }, [initialFocusRef]);\n\n useEffect(() => {\n if (!onClose) return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n useEffect(() => {\n if (!closeOutside || !onClose) return;\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target;\n if (!target || !(target instanceof Node)) return;\n if (modalRef.current && !modalRef.current.contains(target)) {\n const portalContent = (target as Element).closest?.(\n `[data-modal-id=\"${titleId}\"]`\n );\n if (!portalContent) {\n onClose();\n }\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [closeOutside, onClose, titleId]);\n\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !modalRef.current) return;\n\n const focusableElements = getFocusableElements(modalRef.current);\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (!firstElement) {\n event.preventDefault();\n return;\n }\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }, []);\n\n const maxWidthValue =\n type === \"full-screen\" || type === \"bottom-sheet\"\n ? \"100%\"\n : (maxWidth ?? sizing.maxWidth);\n const hasDefaultHeader = !header && (onBack || onClose);\n const hasHeader = !!header || hasDefaultHeader;\n\n const typeStyles: React.CSSProperties =\n type === \"full-screen\"\n ? {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : type === \"bottom-sheet\"\n ? {\n position: \"fixed\",\n bottom: 0,\n left: 0,\n right: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : {};\n\n return (\n <Box\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={!title ? ariaLabel : undefined}\n aria-describedby={ariaDescribedBy}\n data-modal-id={titleId}\n data-modal-type={type}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n flexGrow={1}\n position=\"relative\"\n width=\"100%\"\n style={{\n maxWidth:\n typeof maxWidthValue === \"number\"\n ? `${maxWidthValue}px`\n : maxWidthValue,\n minHeight:\n typeof minHeight === \"number\" ? `${minHeight}px` : minHeight,\n outline: \"none\",\n ...typeStyles,\n ...styledProps,\n }}\n {...rest}\n >\n {title && (\n <Box\n id={titleId}\n position=\"absolute\"\n style={{\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: 1,\n width: 1,\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n }}\n >\n {title}\n </Box>\n )}\n <ModalIdContext.Provider value={titleId}>\n <WorkArea\n ref={ref}\n stretched\n openContent={openContent}\n type={type}\n align={align}\n >\n {hasHeader && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n width=\"100%\"\n padding={sizing.headerPadding}\n style={{ flexShrink: 0 }}\n >\n {header ?? (\n <>\n <Box style={{ minWidth: 36 }}>\n {onBack && (\n <FlexButton\n variant=\"secondary\"\n size={sizing.headerButtonSize}\n background\n onPress={onBack}\n aria-label=\"Go back\"\n >\n <ChevronLeft />\n </FlexButton>\n )}\n </Box>\n <Box\n ref={closeButtonRef}\n style={{ minWidth: 36 }}\n alignItems=\"flex-end\"\n >\n {onClose && (\n <FlexButton\n variant=\"secondary\"\n size={sizing.headerButtonSize}\n background\n onPress={onClose}\n aria-label=\"Close modal\"\n >\n <Remove />\n </FlexButton>\n )}\n </Box>\n </>\n )}\n </Box>\n )}\n <Box\n flexGrow={1}\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{ paddingTop: hasHeader ? 0 : undefined }}\n >\n {children}\n </Box>\n {footer && (\n <Box\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{ paddingTop: 0, flexShrink: 0 }}\n >\n {footer}\n </Box>\n )}\n </WorkArea>\n </ModalIdContext.Provider>\n </Box>\n );\n }\n);\n\nModal.displayName = \"Modal\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import { forwardRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport type { WorkAreaProps } from \"./types\";\n\nconst getBorderRadius = (\n type: WorkAreaProps[\"type\"],\n baseRadius: number\n): string | number => {\n switch (type) {\n case \"full-screen\":\n return 0;\n case \"bottom-sheet\":\n return `${baseRadius}px ${baseRadius}px 0 0`;\n default:\n return baseRadius;\n }\n};\n\nexport const WorkArea = forwardRef<any, WorkAreaProps>(\n (\n {\n children,\n openContent = false,\n stretched = false,\n fetching = false,\n type = \"popup\",\n align,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const showShadow = type !== \"full-screen\";\n\n return (\n <Box\n ref={ref}\n backgroundColor={theme.colors.background.primary}\n width=\"100%\"\n height={stretched ? \"100%\" : \"auto\"}\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{\n borderRadius: getBorderRadius(type, sizing.borderRadius),\n boxShadow: showShadow ? sizing.shadow : \"none\",\n overflow: \"hidden\",\n color: theme.colors.content.primary,\n }}\n >\n <Box\n width=\"100%\"\n height=\"100%\"\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{ textAlign: align === \"center\" ? \"center\" : \"left\" }}\n >\n {fetching ? (\n <Box\n alignItems=\"center\"\n justifyContent=\"center\"\n width=\"100%\"\n height=\"100%\"\n >\n <div>Loading...</div>\n </Box>\n ) : (\n children\n )}\n </Box>\n </Box>\n );\n }\n);\n\nWorkArea.displayName = \"WorkArea\";\n","import { useCallback, useMemo, useState } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalRoot } from \"./ModalRoot\";\nimport type { ModalProviderProps, ModalType } from \"./types\";\n\nexport const ModalProvider = ({ children }: ModalProviderProps) => {\n const [modals, setModals] = useState<Record<string, ModalType>>({});\n\n const onOpenModal = useCallback(\n (key: string, modal: ModalType) =>\n setModals((m) => ({ ...m, [key]: modal })),\n []\n );\n\n const onCloseModal = useCallback(\n (key: string) =>\n setModals((m) => {\n if (!m[key]) return m;\n const newModals = { ...m };\n delete newModals[key];\n return newModals;\n }),\n []\n );\n\n const contextValue = useMemo(\n () => ({ onOpenModal, onCloseModal }),\n [onOpenModal, onCloseModal]\n );\n\n return (\n <ModalContext.Provider value={contextValue}>\n {children}\n <ModalRoot modals={modals} />\n </ModalContext.Provider>\n );\n};\n","import { createContext } from \"react\";\nimport type { ModalContextType } from \"./types\";\n\nconst invariantViolation = () => {\n throw new Error(\n \"Attempted to call useModal outside of modal context. Make sure your app is rendered inside ModalProvider.\"\n );\n};\n\nexport const ModalContext = createContext<ModalContextType>({\n onOpenModal: invariantViolation,\n onCloseModal: invariantViolation,\n});\n","import React, { memo } from \"react\";\nimport type { ModalRootProps } from \"./types\";\n\n// Web portal not available on React Native\n// Native modal implementation would use RN-specific approach\nexport const ModalRoot = memo(({ modals }: ModalRootProps) => {\n return null;\n});\n\nModalRoot.displayName = \"ModalRoot\";\n","import { useContext, useEffect, useMemo, useRef, useCallback } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalType } from \"./types\";\n\nexport const useModal = (modal: ModalType): [() => void, () => void] => {\n const { onOpenModal, onCloseModal } = useContext(ModalContext);\n const key = useMemo(() => Math.random().toString(36).substr(2, 9), []);\n const modalRef = useRef(modal);\n\n useEffect(() => {\n modalRef.current = modal;\n }, [modal]);\n\n const open = useCallback(() => {\n onOpenModal(key, modalRef.current);\n }, [key, onOpenModal]);\n\n const close = useCallback(() => {\n onCloseModal(key);\n }, [key, onCloseModal]);\n\n return [open, close];\n};\n"],"mappings":"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","names":["import_react","import_xui_core","import_jsx_runtime","import_jsx_runtime","handleKeyDown","import_react","import_react","import_react","import_jsx_runtime","import_react","import_xui_core"]}
1
+ {"version":3,"sources":["../../src/index.tsx","../../src/Modal.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/WorkArea.tsx","../../src/ModalProvider.tsx","../../src/ModalContext.ts","../../src/ModalRoot.native.tsx","../../src/useModal.ts"],"sourcesContent":["export * from \"./Modal\";\nexport * from \"./ModalProvider\";\nexport * from \"./useModal\";\nexport * from \"./types\";\nexport * from \"./WorkArea\";\nexport { useModalId } from \"@xsolla/xui-core\";\n","import { forwardRef, useEffect, useRef, useCallback } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId, ModalIdContext } from \"@xsolla/xui-core\";\nimport { IconButton } from \"@xsolla/xui-button\";\nimport { ChevronLeft, Remove } from \"@xsolla/xui-icons-base\";\nimport type { ModalProps } from \"./types\";\nimport { WorkArea } from \"./WorkArea\";\n\nconst FOCUSABLE_SELECTORS =\n 'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst isElementVisible = (el: HTMLElement): boolean => {\n if (el.offsetParent === null && getComputedStyle(el).position !== \"fixed\")\n return false;\n const style = getComputedStyle(el);\n return style.visibility !== \"hidden\" && style.display !== \"none\";\n};\n\nconst getFocusableElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS)\n ).filter(isElementVisible);\n\nexport const Modal = forwardRef<any, ModalProps>(\n (\n {\n children,\n type = \"popup\",\n openContent = false,\n closeOutside = true,\n onClose,\n onBack,\n align,\n header,\n footer,\n styled: styledProps,\n maxWidth,\n minHeight,\n title,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n initialFocusRef,\n testID,\n themeMode,\n themeProductContext,\n ...rest\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const modalRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n const titleId = useId();\n\n useEffect(() => {\n previousActiveElement.current = document.activeElement as HTMLElement;\n\n const focusTarget =\n initialFocusRef?.current ||\n closeButtonRef.current ||\n (modalRef.current && getFocusableElements(modalRef.current)[0]);\n\n if (focusTarget) {\n focusTarget.focus();\n } else {\n modalRef.current?.focus();\n }\n\n return () => {\n previousActiveElement.current?.focus();\n };\n }, [initialFocusRef]);\n\n useEffect(() => {\n if (!onClose) return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n useEffect(() => {\n if (!closeOutside || !onClose) return;\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target;\n if (!target || !(target instanceof Node)) return;\n if (modalRef.current && !modalRef.current.contains(target)) {\n const portalContent = (target as Element).closest?.(\n `[data-modal-id=\"${titleId}\"]`\n );\n if (!portalContent) {\n onClose();\n }\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [closeOutside, onClose, titleId]);\n\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !modalRef.current) return;\n\n const focusableElements = getFocusableElements(modalRef.current);\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (!firstElement) {\n event.preventDefault();\n return;\n }\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }, []);\n\n const maxWidthValue =\n type === \"full-screen\" || type === \"bottom-sheet\"\n ? \"100%\"\n : (maxWidth ?? sizing.maxWidth);\n const hasDefaultHeader = !header && (onBack || onClose);\n const hasHeader = !!header || hasDefaultHeader;\n\n const typeStyles: React.CSSProperties =\n type === \"full-screen\"\n ? {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : type === \"bottom-sheet\"\n ? {\n position: \"fixed\",\n bottom: 0,\n left: 0,\n right: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : {};\n\n return (\n <Box\n testID={testID}\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={!title ? ariaLabel : undefined}\n aria-describedby={ariaDescribedBy}\n data-modal-id={titleId}\n data-modal-type={type}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n flexGrow={1}\n position=\"relative\"\n width=\"100%\"\n style={{\n maxWidth:\n typeof maxWidthValue === \"number\"\n ? `${maxWidthValue}px`\n : maxWidthValue,\n minHeight:\n typeof minHeight === \"number\" ? `${minHeight}px` : minHeight,\n outline: \"none\",\n ...typeStyles,\n ...styledProps,\n }}\n {...rest}\n >\n {title && (\n <Box\n id={titleId}\n position=\"absolute\"\n style={{\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: 1,\n width: 1,\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n }}\n >\n {title}\n </Box>\n )}\n <ModalIdContext.Provider value={titleId}>\n <WorkArea\n ref={ref}\n stretched\n openContent={openContent}\n type={type}\n align={align}\n >\n {hasHeader && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n width=\"100%\"\n padding={sizing.headerPadding}\n style={{ flexShrink: 0 }}\n >\n {header ?? (\n <>\n <Box style={{ minWidth: 36 }}>\n {onBack && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size={sizing.headerButtonSize}\n icon={<ChevronLeft />}\n onPress={onBack}\n aria-label=\"Go back\"\n />\n )}\n </Box>\n <Box\n ref={closeButtonRef}\n style={{ minWidth: 36 }}\n alignItems=\"flex-end\"\n >\n {onClose && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size={sizing.headerButtonSize}\n icon={<Remove />}\n onPress={onClose}\n aria-label=\"Close modal\"\n />\n )}\n </Box>\n </>\n )}\n </Box>\n )}\n <Box\n flexGrow={1}\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{\n paddingTop:\n hasHeader && !openContent ? sizing.headerGap : undefined,\n }}\n >\n {children}\n </Box>\n {footer && (\n <Box\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{ paddingTop: 0, flexShrink: 0 }}\n >\n {footer}\n </Box>\n )}\n </WorkArea>\n </ModalIdContext.Provider>\n </Box>\n );\n }\n);\n\nModal.displayName = \"Modal\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import { forwardRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport type { WorkAreaProps } from \"./types\";\n\nconst getBorderRadius = (\n type: WorkAreaProps[\"type\"],\n baseRadius: number\n): string | number => {\n switch (type) {\n case \"full-screen\":\n return 0;\n case \"bottom-sheet\":\n return `${baseRadius}px ${baseRadius}px 0 0`;\n default:\n return baseRadius;\n }\n};\n\nexport const WorkArea = forwardRef<any, WorkAreaProps>(\n (\n {\n children,\n openContent = false,\n stretched = false,\n fetching = false,\n type = \"popup\",\n align,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const showShadow = type !== \"full-screen\";\n\n return (\n <Box\n testID={testID}\n ref={ref}\n backgroundColor={theme.colors.background.primary}\n width=\"100%\"\n height={stretched ? \"100%\" : \"auto\"}\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{\n borderRadius: getBorderRadius(type, sizing.borderRadius),\n boxShadow: showShadow ? sizing.shadow : \"none\",\n overflow: \"hidden\",\n color: theme.colors.content.primary,\n }}\n >\n <Box\n width=\"100%\"\n height=\"100%\"\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{ textAlign: align === \"center\" ? \"center\" : \"left\" }}\n >\n {fetching ? (\n <Box\n alignItems=\"center\"\n justifyContent=\"center\"\n width=\"100%\"\n height=\"100%\"\n >\n <div>Loading...</div>\n </Box>\n ) : (\n children\n )}\n </Box>\n </Box>\n );\n }\n);\n\nWorkArea.displayName = \"WorkArea\";\n","import { useCallback, useMemo, useState } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalRoot } from \"./ModalRoot\";\nimport type { ModalProviderProps, ModalType } from \"./types\";\n\nexport const ModalProvider = ({ children, testID }: ModalProviderProps) => {\n const [modals, setModals] = useState<Record<string, ModalType>>({});\n\n const onOpenModal = useCallback(\n (key: string, modal: ModalType) =>\n setModals((m) => ({ ...m, [key]: modal })),\n []\n );\n\n const onCloseModal = useCallback(\n (key: string) =>\n setModals((m) => {\n if (!m[key]) return m;\n const newModals = { ...m };\n delete newModals[key];\n return newModals;\n }),\n []\n );\n\n const contextValue = useMemo(\n () => ({ onOpenModal, onCloseModal }),\n [onOpenModal, onCloseModal]\n );\n\n return (\n <ModalContext.Provider value={contextValue}>\n {children}\n <ModalRoot modals={modals} testID={testID} />\n </ModalContext.Provider>\n );\n};\n","import { createContext } from \"react\";\nimport type { ModalContextType } from \"./types\";\n\nconst invariantViolation = () => {\n throw new Error(\n \"Attempted to call useModal outside of modal context. Make sure your app is rendered inside ModalProvider.\"\n );\n};\n\nexport const ModalContext = createContext<ModalContextType>({\n onOpenModal: invariantViolation,\n onCloseModal: invariantViolation,\n});\n","import React, { memo } from \"react\";\nimport type { ModalRootProps } from \"./types\";\n\n// Web portal not available on React Native\n// Native modal implementation would use RN-specific approach\nexport const ModalRoot = memo(\n ({ modals: _modals, testID: _testID }: ModalRootProps) => {\n return null;\n }\n);\n\nModalRoot.displayName = \"ModalRoot\";\n","import { useContext, useEffect, useMemo, useRef, useCallback } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalType } from \"./types\";\n\nexport const useModal = (modal: ModalType): [() => void, () => void] => {\n const { onOpenModal, onCloseModal } = useContext(ModalContext);\n const key = useMemo(() => Math.random().toString(36).substr(2, 9), []);\n const modalRef = useRef(modal);\n\n useEffect(() => {\n modalRef.current = modal;\n }, [modal]);\n\n const open = useCallback(() => {\n onOpenModal(key, modalRef.current);\n }, [key, onOpenModal]);\n\n const close = useCallback(() => {\n onCloseModal(key);\n }, [key, onCloseModal]);\n\n return [open, close];\n};\n"],"mappings":"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","names":["import_react","import_xui_core","import_jsx_runtime","import_jsx_runtime","handleKeyDown","import_react","import_react","import_react","import_jsx_runtime","import_react","import_xui_core"]}
package/native/index.mjs CHANGED
@@ -181,7 +181,7 @@ var Box = ({
181
181
 
182
182
  // src/Modal.tsx
183
183
  import { useResolvedTheme as useResolvedTheme2, useId, ModalIdContext } from "@xsolla/xui-core";
184
- import { FlexButton } from "@xsolla/xui-button";
184
+ import { IconButton } from "@xsolla/xui-button";
185
185
  import { ChevronLeft, Remove } from "@xsolla/xui-icons-base";
186
186
 
187
187
  // src/WorkArea.tsx
@@ -206,6 +206,7 @@ var WorkArea = forwardRef(
206
206
  fetching = false,
207
207
  type = "popup",
208
208
  align,
209
+ testID,
209
210
  themeMode,
210
211
  themeProductContext
211
212
  }, ref) => {
@@ -215,6 +216,7 @@ var WorkArea = forwardRef(
215
216
  return /* @__PURE__ */ jsx2(
216
217
  Box,
217
218
  {
219
+ testID,
218
220
  ref,
219
221
  backgroundColor: theme.colors.background.primary,
220
222
  width: "100%",
@@ -283,6 +285,7 @@ var Modal = forwardRef2(
283
285
  "aria-label": ariaLabel,
284
286
  "aria-describedby": ariaDescribedBy,
285
287
  initialFocusRef,
288
+ testID,
286
289
  themeMode,
287
290
  themeProductContext,
288
291
  ...rest
@@ -369,6 +372,7 @@ var Modal = forwardRef2(
369
372
  return /* @__PURE__ */ jsxs(
370
373
  Box,
371
374
  {
375
+ testID,
372
376
  ref: modalRef,
373
377
  role: "dialog",
374
378
  "aria-modal": "true",
@@ -427,14 +431,14 @@ var Modal = forwardRef2(
427
431
  style: { flexShrink: 0 },
428
432
  children: header ?? /* @__PURE__ */ jsxs(Fragment, { children: [
429
433
  /* @__PURE__ */ jsx3(Box, { style: { minWidth: 36 }, children: onBack && /* @__PURE__ */ jsx3(
430
- FlexButton,
434
+ IconButton,
431
435
  {
432
436
  variant: "secondary",
437
+ tone: "mono",
433
438
  size: sizing.headerButtonSize,
434
- background: true,
439
+ icon: /* @__PURE__ */ jsx3(ChevronLeft, {}),
435
440
  onPress: onBack,
436
- "aria-label": "Go back",
437
- children: /* @__PURE__ */ jsx3(ChevronLeft, {})
441
+ "aria-label": "Go back"
438
442
  }
439
443
  ) }),
440
444
  /* @__PURE__ */ jsx3(
@@ -444,14 +448,14 @@ var Modal = forwardRef2(
444
448
  style: { minWidth: 36 },
445
449
  alignItems: "flex-end",
446
450
  children: onClose && /* @__PURE__ */ jsx3(
447
- FlexButton,
451
+ IconButton,
448
452
  {
449
453
  variant: "secondary",
454
+ tone: "mono",
450
455
  size: sizing.headerButtonSize,
451
- background: true,
456
+ icon: /* @__PURE__ */ jsx3(Remove, {}),
452
457
  onPress: onClose,
453
- "aria-label": "Close modal",
454
- children: /* @__PURE__ */ jsx3(Remove, {})
458
+ "aria-label": "Close modal"
455
459
  }
456
460
  )
457
461
  }
@@ -465,7 +469,9 @@ var Modal = forwardRef2(
465
469
  flexGrow: 1,
466
470
  width: "100%",
467
471
  padding: openContent ? 0 : sizing.contentPadding,
468
- style: { paddingTop: hasHeader ? 0 : void 0 },
472
+ style: {
473
+ paddingTop: hasHeader && !openContent ? sizing.headerGap : void 0
474
+ },
469
475
  children
470
476
  }
471
477
  ),
@@ -505,14 +511,16 @@ var ModalContext = createContext({
505
511
 
506
512
  // src/ModalRoot.native.tsx
507
513
  import { memo } from "react";
508
- var ModalRoot = memo(({ modals }) => {
509
- return null;
510
- });
514
+ var ModalRoot = memo(
515
+ ({ modals: _modals, testID: _testID }) => {
516
+ return null;
517
+ }
518
+ );
511
519
  ModalRoot.displayName = "ModalRoot";
512
520
 
513
521
  // src/ModalProvider.tsx
514
522
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
515
- var ModalProvider = ({ children }) => {
523
+ var ModalProvider = ({ children, testID }) => {
516
524
  const [modals, setModals] = useState({});
517
525
  const onOpenModal = useCallback2(
518
526
  (key, modal) => setModals((m) => ({ ...m, [key]: modal })),
@@ -533,7 +541,7 @@ var ModalProvider = ({ children }) => {
533
541
  );
534
542
  return /* @__PURE__ */ jsxs2(ModalContext.Provider, { value: contextValue, children: [
535
543
  children,
536
- /* @__PURE__ */ jsx4(ModalRoot, { modals })
544
+ /* @__PURE__ */ jsx4(ModalRoot, { modals, testID })
537
545
  ] });
538
546
  };
539
547
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Modal.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/WorkArea.tsx","../../src/ModalProvider.tsx","../../src/ModalContext.ts","../../src/ModalRoot.native.tsx","../../src/useModal.ts","../../src/index.tsx"],"sourcesContent":["import { forwardRef, useEffect, useRef, useCallback } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId, ModalIdContext } from \"@xsolla/xui-core\";\nimport { FlexButton } from \"@xsolla/xui-button\";\nimport { ChevronLeft, Remove } from \"@xsolla/xui-icons-base\";\nimport type { ModalProps } from \"./types\";\nimport { WorkArea } from \"./WorkArea\";\n\nconst FOCUSABLE_SELECTORS =\n 'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst isElementVisible = (el: HTMLElement): boolean => {\n if (el.offsetParent === null && getComputedStyle(el).position !== \"fixed\")\n return false;\n const style = getComputedStyle(el);\n return style.visibility !== \"hidden\" && style.display !== \"none\";\n};\n\nconst getFocusableElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS)\n ).filter(isElementVisible);\n\nexport const Modal = forwardRef<any, ModalProps>(\n (\n {\n children,\n type = \"popup\",\n openContent = false,\n closeOutside = true,\n onClose,\n onBack,\n align,\n header,\n footer,\n styled: styledProps,\n maxWidth,\n minHeight,\n title,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n initialFocusRef,\n themeMode,\n themeProductContext,\n ...rest\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const modalRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n const titleId = useId();\n\n useEffect(() => {\n previousActiveElement.current = document.activeElement as HTMLElement;\n\n const focusTarget =\n initialFocusRef?.current ||\n closeButtonRef.current ||\n (modalRef.current && getFocusableElements(modalRef.current)[0]);\n\n if (focusTarget) {\n focusTarget.focus();\n } else {\n modalRef.current?.focus();\n }\n\n return () => {\n previousActiveElement.current?.focus();\n };\n }, [initialFocusRef]);\n\n useEffect(() => {\n if (!onClose) return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n useEffect(() => {\n if (!closeOutside || !onClose) return;\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target;\n if (!target || !(target instanceof Node)) return;\n if (modalRef.current && !modalRef.current.contains(target)) {\n const portalContent = (target as Element).closest?.(\n `[data-modal-id=\"${titleId}\"]`\n );\n if (!portalContent) {\n onClose();\n }\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [closeOutside, onClose, titleId]);\n\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !modalRef.current) return;\n\n const focusableElements = getFocusableElements(modalRef.current);\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (!firstElement) {\n event.preventDefault();\n return;\n }\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }, []);\n\n const maxWidthValue =\n type === \"full-screen\" || type === \"bottom-sheet\"\n ? \"100%\"\n : (maxWidth ?? sizing.maxWidth);\n const hasDefaultHeader = !header && (onBack || onClose);\n const hasHeader = !!header || hasDefaultHeader;\n\n const typeStyles: React.CSSProperties =\n type === \"full-screen\"\n ? {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : type === \"bottom-sheet\"\n ? {\n position: \"fixed\",\n bottom: 0,\n left: 0,\n right: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : {};\n\n return (\n <Box\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={!title ? ariaLabel : undefined}\n aria-describedby={ariaDescribedBy}\n data-modal-id={titleId}\n data-modal-type={type}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n flexGrow={1}\n position=\"relative\"\n width=\"100%\"\n style={{\n maxWidth:\n typeof maxWidthValue === \"number\"\n ? `${maxWidthValue}px`\n : maxWidthValue,\n minHeight:\n typeof minHeight === \"number\" ? `${minHeight}px` : minHeight,\n outline: \"none\",\n ...typeStyles,\n ...styledProps,\n }}\n {...rest}\n >\n {title && (\n <Box\n id={titleId}\n position=\"absolute\"\n style={{\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: 1,\n width: 1,\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n }}\n >\n {title}\n </Box>\n )}\n <ModalIdContext.Provider value={titleId}>\n <WorkArea\n ref={ref}\n stretched\n openContent={openContent}\n type={type}\n align={align}\n >\n {hasHeader && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n width=\"100%\"\n padding={sizing.headerPadding}\n style={{ flexShrink: 0 }}\n >\n {header ?? (\n <>\n <Box style={{ minWidth: 36 }}>\n {onBack && (\n <FlexButton\n variant=\"secondary\"\n size={sizing.headerButtonSize}\n background\n onPress={onBack}\n aria-label=\"Go back\"\n >\n <ChevronLeft />\n </FlexButton>\n )}\n </Box>\n <Box\n ref={closeButtonRef}\n style={{ minWidth: 36 }}\n alignItems=\"flex-end\"\n >\n {onClose && (\n <FlexButton\n variant=\"secondary\"\n size={sizing.headerButtonSize}\n background\n onPress={onClose}\n aria-label=\"Close modal\"\n >\n <Remove />\n </FlexButton>\n )}\n </Box>\n </>\n )}\n </Box>\n )}\n <Box\n flexGrow={1}\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{ paddingTop: hasHeader ? 0 : undefined }}\n >\n {children}\n </Box>\n {footer && (\n <Box\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{ paddingTop: 0, flexShrink: 0 }}\n >\n {footer}\n </Box>\n )}\n </WorkArea>\n </ModalIdContext.Provider>\n </Box>\n );\n }\n);\n\nModal.displayName = \"Modal\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import { forwardRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport type { WorkAreaProps } from \"./types\";\n\nconst getBorderRadius = (\n type: WorkAreaProps[\"type\"],\n baseRadius: number\n): string | number => {\n switch (type) {\n case \"full-screen\":\n return 0;\n case \"bottom-sheet\":\n return `${baseRadius}px ${baseRadius}px 0 0`;\n default:\n return baseRadius;\n }\n};\n\nexport const WorkArea = forwardRef<any, WorkAreaProps>(\n (\n {\n children,\n openContent = false,\n stretched = false,\n fetching = false,\n type = \"popup\",\n align,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const showShadow = type !== \"full-screen\";\n\n return (\n <Box\n ref={ref}\n backgroundColor={theme.colors.background.primary}\n width=\"100%\"\n height={stretched ? \"100%\" : \"auto\"}\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{\n borderRadius: getBorderRadius(type, sizing.borderRadius),\n boxShadow: showShadow ? sizing.shadow : \"none\",\n overflow: \"hidden\",\n color: theme.colors.content.primary,\n }}\n >\n <Box\n width=\"100%\"\n height=\"100%\"\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{ textAlign: align === \"center\" ? \"center\" : \"left\" }}\n >\n {fetching ? (\n <Box\n alignItems=\"center\"\n justifyContent=\"center\"\n width=\"100%\"\n height=\"100%\"\n >\n <div>Loading...</div>\n </Box>\n ) : (\n children\n )}\n </Box>\n </Box>\n );\n }\n);\n\nWorkArea.displayName = \"WorkArea\";\n","import { useCallback, useMemo, useState } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalRoot } from \"./ModalRoot\";\nimport type { ModalProviderProps, ModalType } from \"./types\";\n\nexport const ModalProvider = ({ children }: ModalProviderProps) => {\n const [modals, setModals] = useState<Record<string, ModalType>>({});\n\n const onOpenModal = useCallback(\n (key: string, modal: ModalType) =>\n setModals((m) => ({ ...m, [key]: modal })),\n []\n );\n\n const onCloseModal = useCallback(\n (key: string) =>\n setModals((m) => {\n if (!m[key]) return m;\n const newModals = { ...m };\n delete newModals[key];\n return newModals;\n }),\n []\n );\n\n const contextValue = useMemo(\n () => ({ onOpenModal, onCloseModal }),\n [onOpenModal, onCloseModal]\n );\n\n return (\n <ModalContext.Provider value={contextValue}>\n {children}\n <ModalRoot modals={modals} />\n </ModalContext.Provider>\n );\n};\n","import { createContext } from \"react\";\nimport type { ModalContextType } from \"./types\";\n\nconst invariantViolation = () => {\n throw new Error(\n \"Attempted to call useModal outside of modal context. Make sure your app is rendered inside ModalProvider.\"\n );\n};\n\nexport const ModalContext = createContext<ModalContextType>({\n onOpenModal: invariantViolation,\n onCloseModal: invariantViolation,\n});\n","import React, { memo } from \"react\";\nimport type { ModalRootProps } from \"./types\";\n\n// Web portal not available on React Native\n// Native modal implementation would use RN-specific approach\nexport const ModalRoot = memo(({ modals }: ModalRootProps) => {\n return null;\n});\n\nModalRoot.displayName = \"ModalRoot\";\n","import { useContext, useEffect, useMemo, useRef, useCallback } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalType } from \"./types\";\n\nexport const useModal = (modal: ModalType): [() => void, () => void] => {\n const { onOpenModal, onCloseModal } = useContext(ModalContext);\n const key = useMemo(() => Math.random().toString(36).substr(2, 9), []);\n const modalRef = useRef(modal);\n\n useEffect(() => {\n modalRef.current = modal;\n }, [modal]);\n\n const open = useCallback(() => {\n onOpenModal(key, modalRef.current);\n }, [key, onOpenModal]);\n\n const close = useCallback(() => {\n onCloseModal(key);\n }, [key, onCloseModal]);\n\n return [open, close];\n};\n","export * from \"./Modal\";\nexport * from \"./ModalProvider\";\nexport * from \"./useModal\";\nexport * from \"./types\";\nexport * from \"./WorkArea\";\nexport { useModalId } from \"@xsolla/xui-core\";\n"],"mappings":"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","names":["forwardRef","useResolvedTheme","jsx","jsx","forwardRef","useResolvedTheme","handleKeyDown","useCallback","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useCallback","useMemo","useRef","useEffect","useCallback"]}
1
+ {"version":3,"sources":["../../src/Modal.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/WorkArea.tsx","../../src/ModalProvider.tsx","../../src/ModalContext.ts","../../src/ModalRoot.native.tsx","../../src/useModal.ts","../../src/index.tsx"],"sourcesContent":["import { forwardRef, useEffect, useRef, useCallback } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId, ModalIdContext } from \"@xsolla/xui-core\";\nimport { IconButton } from \"@xsolla/xui-button\";\nimport { ChevronLeft, Remove } from \"@xsolla/xui-icons-base\";\nimport type { ModalProps } from \"./types\";\nimport { WorkArea } from \"./WorkArea\";\n\nconst FOCUSABLE_SELECTORS =\n 'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst isElementVisible = (el: HTMLElement): boolean => {\n if (el.offsetParent === null && getComputedStyle(el).position !== \"fixed\")\n return false;\n const style = getComputedStyle(el);\n return style.visibility !== \"hidden\" && style.display !== \"none\";\n};\n\nconst getFocusableElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS)\n ).filter(isElementVisible);\n\nexport const Modal = forwardRef<any, ModalProps>(\n (\n {\n children,\n type = \"popup\",\n openContent = false,\n closeOutside = true,\n onClose,\n onBack,\n align,\n header,\n footer,\n styled: styledProps,\n maxWidth,\n minHeight,\n title,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n initialFocusRef,\n testID,\n themeMode,\n themeProductContext,\n ...rest\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const modalRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n const titleId = useId();\n\n useEffect(() => {\n previousActiveElement.current = document.activeElement as HTMLElement;\n\n const focusTarget =\n initialFocusRef?.current ||\n closeButtonRef.current ||\n (modalRef.current && getFocusableElements(modalRef.current)[0]);\n\n if (focusTarget) {\n focusTarget.focus();\n } else {\n modalRef.current?.focus();\n }\n\n return () => {\n previousActiveElement.current?.focus();\n };\n }, [initialFocusRef]);\n\n useEffect(() => {\n if (!onClose) return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n useEffect(() => {\n if (!closeOutside || !onClose) return;\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target;\n if (!target || !(target instanceof Node)) return;\n if (modalRef.current && !modalRef.current.contains(target)) {\n const portalContent = (target as Element).closest?.(\n `[data-modal-id=\"${titleId}\"]`\n );\n if (!portalContent) {\n onClose();\n }\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [closeOutside, onClose, titleId]);\n\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !modalRef.current) return;\n\n const focusableElements = getFocusableElements(modalRef.current);\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (!firstElement) {\n event.preventDefault();\n return;\n }\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }, []);\n\n const maxWidthValue =\n type === \"full-screen\" || type === \"bottom-sheet\"\n ? \"100%\"\n : (maxWidth ?? sizing.maxWidth);\n const hasDefaultHeader = !header && (onBack || onClose);\n const hasHeader = !!header || hasDefaultHeader;\n\n const typeStyles: React.CSSProperties =\n type === \"full-screen\"\n ? {\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : type === \"bottom-sheet\"\n ? {\n position: \"fixed\",\n bottom: 0,\n left: 0,\n right: 0,\n zIndex: 1,\n maxWidth: \"100%\",\n }\n : {};\n\n return (\n <Box\n testID={testID}\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={!title ? ariaLabel : undefined}\n aria-describedby={ariaDescribedBy}\n data-modal-id={titleId}\n data-modal-type={type}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n flexGrow={1}\n position=\"relative\"\n width=\"100%\"\n style={{\n maxWidth:\n typeof maxWidthValue === \"number\"\n ? `${maxWidthValue}px`\n : maxWidthValue,\n minHeight:\n typeof minHeight === \"number\" ? `${minHeight}px` : minHeight,\n outline: \"none\",\n ...typeStyles,\n ...styledProps,\n }}\n {...rest}\n >\n {title && (\n <Box\n id={titleId}\n position=\"absolute\"\n style={{\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: 1,\n width: 1,\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n }}\n >\n {title}\n </Box>\n )}\n <ModalIdContext.Provider value={titleId}>\n <WorkArea\n ref={ref}\n stretched\n openContent={openContent}\n type={type}\n align={align}\n >\n {hasHeader && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n width=\"100%\"\n padding={sizing.headerPadding}\n style={{ flexShrink: 0 }}\n >\n {header ?? (\n <>\n <Box style={{ minWidth: 36 }}>\n {onBack && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size={sizing.headerButtonSize}\n icon={<ChevronLeft />}\n onPress={onBack}\n aria-label=\"Go back\"\n />\n )}\n </Box>\n <Box\n ref={closeButtonRef}\n style={{ minWidth: 36 }}\n alignItems=\"flex-end\"\n >\n {onClose && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size={sizing.headerButtonSize}\n icon={<Remove />}\n onPress={onClose}\n aria-label=\"Close modal\"\n />\n )}\n </Box>\n </>\n )}\n </Box>\n )}\n <Box\n flexGrow={1}\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{\n paddingTop:\n hasHeader && !openContent ? sizing.headerGap : undefined,\n }}\n >\n {children}\n </Box>\n {footer && (\n <Box\n width=\"100%\"\n padding={openContent ? 0 : sizing.contentPadding}\n style={{ paddingTop: 0, flexShrink: 0 }}\n >\n {footer}\n </Box>\n )}\n </WorkArea>\n </ModalIdContext.Provider>\n </Box>\n );\n }\n);\n\nModal.displayName = \"Modal\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import { forwardRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport type { WorkAreaProps } from \"./types\";\n\nconst getBorderRadius = (\n type: WorkAreaProps[\"type\"],\n baseRadius: number\n): string | number => {\n switch (type) {\n case \"full-screen\":\n return 0;\n case \"bottom-sheet\":\n return `${baseRadius}px ${baseRadius}px 0 0`;\n default:\n return baseRadius;\n }\n};\n\nexport const WorkArea = forwardRef<any, WorkAreaProps>(\n (\n {\n children,\n openContent = false,\n stretched = false,\n fetching = false,\n type = \"popup\",\n align,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.modal();\n const showShadow = type !== \"full-screen\";\n\n return (\n <Box\n testID={testID}\n ref={ref}\n backgroundColor={theme.colors.background.primary}\n width=\"100%\"\n height={stretched ? \"100%\" : \"auto\"}\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{\n borderRadius: getBorderRadius(type, sizing.borderRadius),\n boxShadow: showShadow ? sizing.shadow : \"none\",\n overflow: \"hidden\",\n color: theme.colors.content.primary,\n }}\n >\n <Box\n width=\"100%\"\n height=\"100%\"\n flexDirection=\"column\"\n alignItems={align === \"center\" ? \"center\" : \"stretch\"}\n style={{ textAlign: align === \"center\" ? \"center\" : \"left\" }}\n >\n {fetching ? (\n <Box\n alignItems=\"center\"\n justifyContent=\"center\"\n width=\"100%\"\n height=\"100%\"\n >\n <div>Loading...</div>\n </Box>\n ) : (\n children\n )}\n </Box>\n </Box>\n );\n }\n);\n\nWorkArea.displayName = \"WorkArea\";\n","import { useCallback, useMemo, useState } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalRoot } from \"./ModalRoot\";\nimport type { ModalProviderProps, ModalType } from \"./types\";\n\nexport const ModalProvider = ({ children, testID }: ModalProviderProps) => {\n const [modals, setModals] = useState<Record<string, ModalType>>({});\n\n const onOpenModal = useCallback(\n (key: string, modal: ModalType) =>\n setModals((m) => ({ ...m, [key]: modal })),\n []\n );\n\n const onCloseModal = useCallback(\n (key: string) =>\n setModals((m) => {\n if (!m[key]) return m;\n const newModals = { ...m };\n delete newModals[key];\n return newModals;\n }),\n []\n );\n\n const contextValue = useMemo(\n () => ({ onOpenModal, onCloseModal }),\n [onOpenModal, onCloseModal]\n );\n\n return (\n <ModalContext.Provider value={contextValue}>\n {children}\n <ModalRoot modals={modals} testID={testID} />\n </ModalContext.Provider>\n );\n};\n","import { createContext } from \"react\";\nimport type { ModalContextType } from \"./types\";\n\nconst invariantViolation = () => {\n throw new Error(\n \"Attempted to call useModal outside of modal context. Make sure your app is rendered inside ModalProvider.\"\n );\n};\n\nexport const ModalContext = createContext<ModalContextType>({\n onOpenModal: invariantViolation,\n onCloseModal: invariantViolation,\n});\n","import React, { memo } from \"react\";\nimport type { ModalRootProps } from \"./types\";\n\n// Web portal not available on React Native\n// Native modal implementation would use RN-specific approach\nexport const ModalRoot = memo(\n ({ modals: _modals, testID: _testID }: ModalRootProps) => {\n return null;\n }\n);\n\nModalRoot.displayName = \"ModalRoot\";\n","import { useContext, useEffect, useMemo, useRef, useCallback } from \"react\";\nimport { ModalContext } from \"./ModalContext\";\nimport { ModalType } from \"./types\";\n\nexport const useModal = (modal: ModalType): [() => void, () => void] => {\n const { onOpenModal, onCloseModal } = useContext(ModalContext);\n const key = useMemo(() => Math.random().toString(36).substr(2, 9), []);\n const modalRef = useRef(modal);\n\n useEffect(() => {\n modalRef.current = modal;\n }, [modal]);\n\n const open = useCallback(() => {\n onOpenModal(key, modalRef.current);\n }, [key, onOpenModal]);\n\n const close = useCallback(() => {\n onCloseModal(key);\n }, [key, onCloseModal]);\n\n return [open, close];\n};\n","export * from \"./Modal\";\nexport * from \"./ModalProvider\";\nexport * from \"./useModal\";\nexport * from \"./types\";\nexport * from \"./WorkArea\";\nexport { useModalId } from \"@xsolla/xui-core\";\n"],"mappings":"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","names":["forwardRef","useResolvedTheme","jsx","jsx","forwardRef","useResolvedTheme","handleKeyDown","useCallback","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useCallback","useMemo","useRef","useEffect","useCallback"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-modal",
3
- "version": "0.158.0",
3
+ "version": "0.160.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -13,10 +13,10 @@
13
13
  "test:coverage": "vitest run --coverage"
14
14
  },
15
15
  "dependencies": {
16
- "@xsolla/xui-button": "0.158.0",
17
- "@xsolla/xui-core": "0.158.0",
18
- "@xsolla/xui-icons-base": "0.158.0",
19
- "@xsolla/xui-primitives-core": "0.158.0"
16
+ "@xsolla/xui-button": "0.160.0",
17
+ "@xsolla/xui-core": "0.160.0",
18
+ "@xsolla/xui-icons-base": "0.160.0",
19
+ "@xsolla/xui-primitives-core": "0.160.0"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "react": ">=16.8.0",
package/web/index.d.mts CHANGED
@@ -33,6 +33,8 @@ interface ModalProps extends ThemeOverrideProps {
33
33
  "aria-describedby"?: string;
34
34
  /** Ref to element that should receive focus when modal opens */
35
35
  initialFocusRef?: RefObject<HTMLElement>;
36
+ /** Test ID for testing frameworks */
37
+ testID?: string;
36
38
  }
37
39
  type ModalType = (props: any) => ReactNode;
38
40
  interface ModalContextType {
@@ -41,9 +43,13 @@ interface ModalContextType {
41
43
  }
42
44
  interface ModalProviderProps {
43
45
  children: ReactNode;
46
+ /** Test ID for testing frameworks */
47
+ testID?: string;
44
48
  }
45
49
  interface ModalRootProps {
46
50
  modals: Record<string, ModalType>;
51
+ /** Test ID for testing frameworks */
52
+ testID?: string;
47
53
  }
48
54
  type WorkAreaSize = "sm" | "md" | "lg";
49
55
  interface WorkAreaProps extends ThemeOverrideProps {
@@ -56,11 +62,13 @@ interface WorkAreaProps extends ThemeOverrideProps {
56
62
  type?: ModalVariant;
57
63
  /** Content alignment */
58
64
  align?: "left" | "center";
65
+ /** Test ID for testing frameworks */
66
+ testID?: string;
59
67
  }
60
68
 
61
69
  declare const Modal: react.ForwardRefExoticComponent<ModalProps & react.RefAttributes<any>>;
62
70
 
63
- declare const ModalProvider: ({ children }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
71
+ declare const ModalProvider: ({ children, testID }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
64
72
 
65
73
  declare const useModal: (modal: ModalType) => [() => void, () => void];
66
74
 
package/web/index.d.ts CHANGED
@@ -33,6 +33,8 @@ interface ModalProps extends ThemeOverrideProps {
33
33
  "aria-describedby"?: string;
34
34
  /** Ref to element that should receive focus when modal opens */
35
35
  initialFocusRef?: RefObject<HTMLElement>;
36
+ /** Test ID for testing frameworks */
37
+ testID?: string;
36
38
  }
37
39
  type ModalType = (props: any) => ReactNode;
38
40
  interface ModalContextType {
@@ -41,9 +43,13 @@ interface ModalContextType {
41
43
  }
42
44
  interface ModalProviderProps {
43
45
  children: ReactNode;
46
+ /** Test ID for testing frameworks */
47
+ testID?: string;
44
48
  }
45
49
  interface ModalRootProps {
46
50
  modals: Record<string, ModalType>;
51
+ /** Test ID for testing frameworks */
52
+ testID?: string;
47
53
  }
48
54
  type WorkAreaSize = "sm" | "md" | "lg";
49
55
  interface WorkAreaProps extends ThemeOverrideProps {
@@ -56,11 +62,13 @@ interface WorkAreaProps extends ThemeOverrideProps {
56
62
  type?: ModalVariant;
57
63
  /** Content alignment */
58
64
  align?: "left" | "center";
65
+ /** Test ID for testing frameworks */
66
+ testID?: string;
59
67
  }
60
68
 
61
69
  declare const Modal: react.ForwardRefExoticComponent<ModalProps & react.RefAttributes<any>>;
62
70
 
63
- declare const ModalProvider: ({ children }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
71
+ declare const ModalProvider: ({ children, testID }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
64
72
 
65
73
  declare const useModal: (modal: ModalType) => [() => void, () => void];
66
74
 
package/web/index.js CHANGED
@@ -319,6 +319,7 @@ var WorkArea = (0, import_react3.forwardRef)(
319
319
  fetching = false,
320
320
  type = "popup",
321
321
  align,
322
+ testID,
322
323
  themeMode,
323
324
  themeProductContext
324
325
  }, ref) => {
@@ -328,6 +329,7 @@ var WorkArea = (0, import_react3.forwardRef)(
328
329
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
329
330
  Box,
330
331
  {
332
+ testID,
331
333
  ref,
332
334
  backgroundColor: theme.colors.background.primary,
333
335
  width: "100%",
@@ -396,6 +398,7 @@ var Modal = (0, import_react4.forwardRef)(
396
398
  "aria-label": ariaLabel,
397
399
  "aria-describedby": ariaDescribedBy,
398
400
  initialFocusRef,
401
+ testID,
399
402
  themeMode,
400
403
  themeProductContext,
401
404
  ...rest
@@ -482,6 +485,7 @@ var Modal = (0, import_react4.forwardRef)(
482
485
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
483
486
  Box,
484
487
  {
488
+ testID,
485
489
  ref: modalRef,
486
490
  role: "dialog",
487
491
  "aria-modal": "true",
@@ -540,14 +544,14 @@ var Modal = (0, import_react4.forwardRef)(
540
544
  style: { flexShrink: 0 },
541
545
  children: header ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
542
546
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box, { style: { minWidth: 36 }, children: onBack && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
543
- import_xui_button.FlexButton,
547
+ import_xui_button.IconButton,
544
548
  {
545
549
  variant: "secondary",
550
+ tone: "mono",
546
551
  size: sizing.headerButtonSize,
547
- background: true,
552
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.ChevronLeft, {}),
548
553
  onPress: onBack,
549
- "aria-label": "Go back",
550
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.ChevronLeft, {})
554
+ "aria-label": "Go back"
551
555
  }
552
556
  ) }),
553
557
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -557,14 +561,14 @@ var Modal = (0, import_react4.forwardRef)(
557
561
  style: { minWidth: 36 },
558
562
  alignItems: "flex-end",
559
563
  children: onClose && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
560
- import_xui_button.FlexButton,
564
+ import_xui_button.IconButton,
561
565
  {
562
566
  variant: "secondary",
567
+ tone: "mono",
563
568
  size: sizing.headerButtonSize,
564
- background: true,
569
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.Remove, {}),
565
570
  onPress: onClose,
566
- "aria-label": "Close modal",
567
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.Remove, {})
571
+ "aria-label": "Close modal"
568
572
  }
569
573
  )
570
574
  }
@@ -578,7 +582,9 @@ var Modal = (0, import_react4.forwardRef)(
578
582
  flexGrow: 1,
579
583
  width: "100%",
580
584
  padding: openContent ? 0 : sizing.contentPadding,
581
- style: { paddingTop: hasHeader ? 0 : void 0 },
585
+ style: {
586
+ paddingTop: hasHeader && !openContent ? sizing.headerGap : void 0
587
+ },
582
588
  children
583
589
  }
584
590
  ),
@@ -620,7 +626,7 @@ var ModalContext = (0, import_react5.createContext)({
620
626
  var import_react6 = __toESM(require("react"));
621
627
  var import_react_dom = __toESM(require("react-dom"));
622
628
  var import_jsx_runtime4 = require("react/jsx-runtime");
623
- var ModalRoot = (0, import_react6.memo)(({ modals }) => {
629
+ var ModalRoot = (0, import_react6.memo)(({ modals, testID }) => {
624
630
  const visibleModalKey = (0, import_react6.useMemo)(
625
631
  () => Object.keys(modals)[Object.keys(modals).length - 1],
626
632
  [modals]
@@ -630,6 +636,7 @@ var ModalRoot = (0, import_react6.memo)(({ modals }) => {
630
636
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
631
637
  Box,
632
638
  {
639
+ testID,
633
640
  position: "fixed",
634
641
  zIndex: 1e3,
635
642
  top: 0,
@@ -679,7 +686,7 @@ ModalRoot.displayName = "ModalRoot";
679
686
 
680
687
  // src/ModalProvider.tsx
681
688
  var import_jsx_runtime5 = require("react/jsx-runtime");
682
- var ModalProvider = ({ children }) => {
689
+ var ModalProvider = ({ children, testID }) => {
683
690
  const [modals, setModals] = (0, import_react7.useState)({});
684
691
  const onOpenModal = (0, import_react7.useCallback)(
685
692
  (key, modal) => setModals((m) => ({ ...m, [key]: modal })),
@@ -700,7 +707,7 @@ var ModalProvider = ({ children }) => {
700
707
  );
701
708
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ModalContext.Provider, { value: contextValue, children: [
702
709
  children,
703
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModalRoot, { modals })
710
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModalRoot, { modals, testID })
704
711
  ] });
705
712
  };
706
713