@xsolla/xui-gdpr-banner 0.206.2 → 0.207.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.
@@ -161,12 +161,15 @@ interface PrivacySettingsProps extends ThemeOverrideProps {
161
161
  * ## Layout
162
162
  *
163
163
  * - Desktop, collapsed - a card pinned to the bottom of the viewport with a
164
- * 20px inset, at either bottom corner (`anchor`).
164
+ * 20px inset, at either bottom corner (`anchor`). Its top corners use the
165
+ * modal radius token and its bottom corners the toast radius token.
165
166
  * - Desktop, expanded - a wider panel hosting the two-column Privacy settings.
166
- * - Mobile - always bottom-anchored and full width; actions stack.
167
+ * It sits flush with the bottom edge, so its bottom corners are square.
168
+ * - Mobile - always bottom-anchored, full width and flush against the bottom
169
+ * edge: `offset` is not applied and the bottom corners are square.
167
170
  *
168
171
  * `Customize` and `Close` are borderless brand-tone text actions, matching the
169
- * Figma `Flex Button` with `Background=False`.
172
+ * Figma `Button` with `Type=Tertiary` / `Tone=Brand`.
170
173
  *
171
174
  * ## Accessibility
172
175
  *
package/native/index.d.ts CHANGED
@@ -161,12 +161,15 @@ interface PrivacySettingsProps extends ThemeOverrideProps {
161
161
  * ## Layout
162
162
  *
163
163
  * - Desktop, collapsed - a card pinned to the bottom of the viewport with a
164
- * 20px inset, at either bottom corner (`anchor`).
164
+ * 20px inset, at either bottom corner (`anchor`). Its top corners use the
165
+ * modal radius token and its bottom corners the toast radius token.
165
166
  * - Desktop, expanded - a wider panel hosting the two-column Privacy settings.
166
- * - Mobile - always bottom-anchored and full width; actions stack.
167
+ * It sits flush with the bottom edge, so its bottom corners are square.
168
+ * - Mobile - always bottom-anchored, full width and flush against the bottom
169
+ * edge: `offset` is not applied and the bottom corners are square.
167
170
  *
168
171
  * `Customize` and `Close` are borderless brand-tone text actions, matching the
169
- * Figma `Flex Button` with `Background=False`.
172
+ * Figma `Button` with `Type=Tertiary` / `Tone=Brand`.
170
173
  *
171
174
  * ## Accessibility
172
175
  *
package/native/index.js CHANGED
@@ -569,6 +569,7 @@ var DEFAULT_LABELS = {
569
569
  };
570
570
  var CARD_WIDTH = 400;
571
571
  var EDGE_OFFSET = 20;
572
+ var ACTION_BUTTON_SIZE = "md";
572
573
  var CONTENT_GAP = 8;
573
574
 
574
575
  // src/GdprBanner.tsx
@@ -706,14 +707,13 @@ var GdprBanner = ({
706
707
  const handleConfirmSelection = (0, import_react.useCallback)(() => {
707
708
  onConfirmSelection?.(selection);
708
709
  }, [onConfirmSelection, selection]);
709
- const sizing = theme.sizing.modal();
710
710
  const titleToken = theme.typographyTokens.basic["body-lg"];
711
711
  const bodyToken = theme.typographyTokens.basic["body-sm"];
712
712
  const solidButton = (key, label, onPress, fullWidth) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
713
713
  import_xui_button.Button,
714
714
  {
715
715
  variant: "secondary",
716
- size: "md",
716
+ size: ACTION_BUTTON_SIZE,
717
717
  fullWidth,
718
718
  onPress,
719
719
  testID: `${testID}__${key}`,
@@ -724,10 +724,11 @@ var GdprBanner = ({
724
724
  key
725
725
  );
726
726
  const textButton = (key, label, onPress) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
727
- import_xui_button.FlexButton,
727
+ import_xui_button.Button,
728
728
  {
729
- variant: "brand",
730
- size: "lg",
729
+ variant: "tertiary",
730
+ tone: "brand",
731
+ size: ACTION_BUTTON_SIZE,
731
732
  onPress,
732
733
  testID: `${testID}__${key}`,
733
734
  themeMode,
@@ -807,9 +808,18 @@ var GdprBanner = ({
807
808
  }
808
809
  );
809
810
  };
810
- const edge = isExpanded ? 0 : offset;
811
+ const isFlushWithEdges = isExpanded || isMobile;
812
+ const edge = isFlushWithEdges ? 0 : offset;
811
813
  const isFixed = position === "fixed";
812
814
  const spansFullWidth = isExpanded || isMobile;
815
+ const topCornerRadius = theme.shape.modal.borderRadius;
816
+ const bottomCornerRadius = isFlushWithEdges ? 0 : theme.shape.toast.borderRadius;
817
+ const cornerRadiusStyle = {
818
+ borderTopLeftRadius: topCornerRadius,
819
+ borderTopRightRadius: topCornerRadius,
820
+ borderBottomLeftRadius: bottomCornerRadius,
821
+ borderBottomRightRadius: bottomCornerRadius
822
+ };
813
823
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
814
824
  Box,
815
825
  {
@@ -828,8 +838,8 @@ var GdprBanner = ({
828
838
  zIndex: isFixed ? 1e3 : void 0,
829
839
  width: spansFullWidth ? "100%" : CARD_WIDTH,
830
840
  maxWidth: "100%",
831
- backgroundColor: theme.colors.background.primary,
832
- borderRadius: isExpanded ? 0 : sizing.borderRadius,
841
+ backgroundColor: theme.colors.layer.float,
842
+ style: cornerRadiusStyle,
833
843
  padding: isMobile ? 16 : 20,
834
844
  gap: CONTENT_GAP,
835
845
  children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.tsx","../../src/GdprBanner.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../src/PrivacySettings.tsx","../../src/defaults.ts"],"sourcesContent":["export { GdprBanner } from \"./GdprBanner\";\nexport { PrivacySettings } from \"./PrivacySettings\";\nexport { DEFAULT_CATEGORIES, DEFAULT_LABELS } from \"./defaults\";\nexport type {\n GdprBannerProps,\n GdprBannerType,\n GdprBannerViewport,\n GdprBannerButtonsRow,\n GdprBannerAnchor,\n GdprBannerLabels,\n GdprCookieCategory,\n PrivacySettingsProps,\n} from \"./types\";\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId } from \"@xsolla/xui-core\";\nimport { Button, FlexButton } from \"@xsolla/xui-button\";\nimport { Remove } from \"@xsolla/xui-icons-base\";\nimport { PrivacySettings } from \"./PrivacySettings\";\nimport {\n CARD_WIDTH,\n CONTENT_GAP,\n DEFAULT_CATEGORIES,\n DEFAULT_LABELS,\n EDGE_OFFSET,\n} from \"./defaults\";\nimport type { GdprBannerProps } from \"./types\";\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 = (element: HTMLElement): boolean => {\n if (typeof window === \"undefined\") return true;\n const style = window.getComputedStyle(element);\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\n/**\n * GdprBanner - the Xsolla cookie-consent banner.\n *\n * Implements the Figma `GDPR-banner` component set. The four Figma variant\n * axes map to props: `Type` -> {@link GdprBannerProps.type}, `Fold` ->\n * {@link GdprBannerProps.expanded} (inverted - Figma's `Fold=On` is the\n * collapsed card), `Buttons row` -> {@link GdprBannerProps.buttonsRow},\n * `Viewport` -> {@link GdprBannerProps.viewport}.\n *\n * ## Layout\n *\n * - Desktop, collapsed - a card pinned to the bottom of the viewport with a\n * 20px inset, at either bottom corner (`anchor`).\n * - Desktop, expanded - a wider panel hosting the two-column Privacy settings.\n * - Mobile - always bottom-anchored and full width; actions stack.\n *\n * `Customize` and `Close` are borderless brand-tone text actions, matching the\n * Figma `Flex Button` with `Background=False`.\n *\n * ## Accessibility\n *\n * - `role=\"dialog\"` labelled by the visible heading.\n * - Focus moves into the banner when it mounts and when the panel expands.\n * - Tab and Shift+Tab cycle within the banner; Escape fires `onClose`.\n * - The close control carries an explicit `aria-label`.\n */\nexport const GdprBanner: React.FC<GdprBannerProps> = ({\n type = \"complex\",\n viewport = \"desktop\",\n buttonsRow = \"single\",\n anchor = \"bottom-left\",\n expanded,\n defaultExpanded = false,\n onExpandedChange,\n categories = DEFAULT_CATEGORIES,\n selectedCategoryIds,\n defaultSelectedCategoryIds,\n onSelectionChange,\n labels,\n cookiePolicyUrl,\n privacyPolicyUrl,\n onAcceptAll,\n onRejectAll,\n onCustomize,\n onConfirmSelection,\n onDismiss,\n onClose,\n showCloseButton = true,\n position = \"fixed\",\n offset = EDGE_OFFSET,\n testID = \"gdpr-banner\",\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const containerRef = useRef<HTMLDivElement>(null);\n\n const rawId = useId();\n const titleId = `gdpr-banner-title-${rawId.replace(/:/g, \"\")}`;\n\n const t = useMemo(() => ({ ...DEFAULT_LABELS, ...labels }), [labels]);\n\n const isMobile = viewport === \"mobile\";\n const isSimple = type === \"simple\";\n\n const allIds = useMemo(\n () => categories.map((category) => category.id),\n [categories]\n );\n const lockedIds = useMemo(\n () => categories.filter((category) => category.locked).map((c) => c.id),\n [categories]\n );\n\n const isExpandedControlled = expanded !== undefined;\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n // `simple` has no Privacy settings panel, so it can never be expanded.\n const isExpanded =\n !isSimple && (isExpandedControlled ? expanded : internalExpanded);\n\n const isSelectionControlled = selectedCategoryIds !== undefined;\n const [internalSelection, setInternalSelection] = useState<string[]>(\n defaultSelectedCategoryIds ?? allIds\n );\n const selection = isSelectionControlled\n ? selectedCategoryIds\n : internalSelection;\n\n const [activeCategoryId, setActiveCategoryId] = useState<string | null>(null);\n\n const setExpanded = useCallback(\n (next: boolean) => {\n if (!isExpandedControlled) setInternalExpanded(next);\n onExpandedChange?.(next);\n },\n [isExpandedControlled, onExpandedChange]\n );\n\n const setSelection = useCallback(\n (next: string[]) => {\n if (!isSelectionControlled) setInternalSelection(next);\n onSelectionChange?.(next);\n },\n [isSelectionControlled, onSelectionChange]\n );\n\n // Escape dismisses the banner outright, matching the close (X) control.\n useEffect(() => {\n if (!onClose || typeof document === \"undefined\") 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 // Pull focus in on mount and whenever the panel expands or collapses, so the\n // newly revealed controls are reachable without hunting for them.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const [first] = getFocusableElements(container);\n first?.focus();\n }, [isExpanded]);\n\n const handleTabKey = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !containerRef.current) return;\n const focusable = getFocusableElements(containerRef.current);\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (!first) {\n event.preventDefault();\n return;\n }\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }, []);\n\n const handleToggleCategory = useCallback(\n (id: string) => {\n const category = categories.find((item) => item.id === id);\n if (!category || category.locked) return;\n const next = selection.includes(id)\n ? selection.filter((item) => item !== id)\n : [...selection, id];\n setSelection(next);\n },\n [categories, selection, setSelection]\n );\n\n const handleAcceptAll = useCallback(() => {\n setSelection(allIds);\n onAcceptAll?.();\n }, [allIds, onAcceptAll, setSelection]);\n\n const handleRejectAll = useCallback(() => {\n // Locked categories stay consented - they cannot be switched off.\n setSelection(lockedIds);\n onRejectAll?.();\n }, [lockedIds, onRejectAll, setSelection]);\n\n const handleCustomize = useCallback(() => {\n setExpanded(true);\n onCustomize?.();\n }, [onCustomize, setExpanded]);\n\n const handleCollapse = useCallback(() => {\n setExpanded(false);\n }, [setExpanded]);\n\n const handleConfirmSelection = useCallback(() => {\n onConfirmSelection?.(selection);\n }, [onConfirmSelection, selection]);\n\n const sizing = theme.sizing.modal();\n const titleToken = theme.typographyTokens.basic[\"body-lg\"];\n const bodyToken = theme.typographyTokens.basic[\"body-sm\"];\n\n /** Filled action (Reject All / Accept All / Confirm Selection / Dismiss). */\n const solidButton = (\n key: string,\n label: string,\n onPress: () => void,\n fullWidth: boolean\n ) => (\n <Button\n key={key}\n variant=\"secondary\"\n size=\"md\"\n fullWidth={fullWidth}\n onPress={onPress}\n testID={`${testID}__${key}`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n {label}\n </Button>\n );\n\n /**\n * Borderless text action (Customize / Close).\n *\n * `Button variant=\"ghost\"` cannot be used here: its border token is not\n * transparent in the light theme, so it renders a visible outline that the\n * Figma design does not have. `FlexButton` with the default\n * `background={false}` is the design-system's text-action primitive and is\n * what the Figma file instantiates (`Flex Button`, `Background=False`).\n */\n const textButton = (key: string, label: string, onPress: () => void) => (\n <FlexButton\n key={key}\n variant=\"brand\"\n size=\"lg\"\n onPress={onPress}\n testID={`${testID}__${key}`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n {label}\n </FlexButton>\n );\n\n const renderActions = () => {\n if (isSimple) {\n return (\n <Box\n width=\"100%\"\n flexDirection=\"row\"\n justifyContent={isMobile ? \"center\" : \"flex-end\"}\n >\n {solidButton(\"dismiss\", t.dismiss, () => onDismiss?.(), isMobile)}\n </Box>\n );\n }\n\n if (isExpanded) {\n const close = textButton(\"close\", t.close, handleCollapse);\n const reject = solidButton(\n \"reject-all\",\n t.rejectAll,\n handleRejectAll,\n isMobile\n );\n const confirm = solidButton(\n \"confirm-selection\",\n t.confirmSelection,\n handleConfirmSelection,\n isMobile\n );\n\n return isMobile ? (\n <Box width=\"100%\" gap={CONTENT_GAP} alignItems=\"center\">\n {[confirm, reject, close]}\n </Box>\n ) : (\n <Box\n width=\"100%\"\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"flex-end\"\n gap={CONTENT_GAP}\n >\n {[close, reject, confirm]}\n </Box>\n );\n }\n\n const customize = textButton(\"customize\", t.customize, handleCustomize);\n\n if (isMobile) {\n return (\n <Box width=\"100%\" gap={CONTENT_GAP} alignItems=\"center\">\n {solidButton(\"accept-all\", t.acceptAll, handleAcceptAll, true)}\n {solidButton(\"reject-all\", t.rejectAll, handleRejectAll, true)}\n {customize}\n </Box>\n );\n }\n\n if (buttonsRow === \"double\") {\n // Figma node 21855:20776 - Customize centred on its own row, then two\n // equal-width buttons filling the 250px content column with an 8px gap.\n return (\n <Box width=\"100%\" gap={CONTENT_GAP}>\n <Box flexDirection=\"row\" justifyContent=\"center\" width=\"100%\">\n {customize}\n </Box>\n <Box flexDirection=\"row\" gap={CONTENT_GAP} width=\"100%\">\n <Box flex={1}>\n {solidButton(\"reject-all\", t.rejectAll, handleRejectAll, true)}\n </Box>\n <Box flex={1}>\n {solidButton(\"accept-all\", t.acceptAll, handleAcceptAll, true)}\n </Box>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box\n width=\"100%\"\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"flex-end\"\n gap={CONTENT_GAP}\n >\n {customize}\n {solidButton(\"reject-all\", t.rejectAll, handleRejectAll, false)}\n {solidButton(\"accept-all\", t.acceptAll, handleAcceptAll, false)}\n </Box>\n );\n };\n\n const edge = isExpanded ? 0 : offset;\n const isFixed = position === \"fixed\";\n const spansFullWidth = isExpanded || isMobile;\n\n return (\n <Box\n ref={containerRef}\n testID={testID}\n role=\"dialog\"\n aria-labelledby={titleId}\n onKeyDown={handleTabKey}\n data-gdpr-banner-type={type}\n data-gdpr-banner-viewport={viewport}\n data-gdpr-banner-expanded={isExpanded ? \"true\" : \"false\"}\n position={isFixed ? \"fixed\" : \"relative\"}\n bottom={isFixed ? edge : undefined}\n left={isFixed && (spansFullWidth || anchor === \"bottom-left\") ? edge : undefined}\n right={\n isFixed && (spansFullWidth || anchor === \"bottom-right\") ? edge : undefined\n }\n zIndex={isFixed ? 1000 : undefined}\n width={spansFullWidth ? \"100%\" : CARD_WIDTH}\n maxWidth=\"100%\"\n backgroundColor={theme.colors.background.primary}\n borderRadius={isExpanded ? 0 : sizing.borderRadius}\n padding={isMobile ? 16 : 20}\n gap={CONTENT_GAP}\n >\n <Box\n flexDirection=\"row\"\n alignItems=\"flex-start\"\n justifyContent=\"space-between\"\n gap={12}\n width=\"100%\"\n >\n <Text\n id={titleId}\n color={theme.colors.content.primary}\n fontSize={titleToken.fontSize}\n lineHeight={titleToken.lineHeight}\n fontWeight={titleToken.accent?.fontWeight ?? 500}\n fontFamily={theme.fonts.body}\n >\n {isExpanded ? t.privacySettingsTitle : t.title}\n </Text>\n\n {showCloseButton && onClose && (\n <FlexButton\n variant=\"tertiary\"\n size=\"xs\"\n onPress={onClose}\n aria-label={t.closeButtonAriaLabel}\n testID={`${testID}__close-icon`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n <Remove variant=\"line\" />\n </FlexButton>\n )}\n </Box>\n\n {isExpanded ? (\n <PrivacySettings\n categories={categories}\n selectedCategoryIds={selection}\n onToggleCategory={handleToggleCategory}\n activeCategoryId={activeCategoryId}\n onActiveCategoryChange={setActiveCategoryId}\n viewport={viewport}\n labels={{\n generalInformation: t.generalInformation,\n generalInformationDescription: t.generalInformationDescription,\n cookiePolicy: t.cookiePolicy,\n privacyPolicy: t.privacyPolicy,\n }}\n cookiePolicyUrl={cookiePolicyUrl}\n privacyPolicyUrl={privacyPolicyUrl}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n testID={`${testID}__privacy-settings`}\n />\n ) : (\n <Text\n color={theme.colors.content.secondary}\n fontSize={bodyToken.fontSize}\n lineHeight={bodyToken.lineHeight}\n fontFamily={theme.fonts.body}\n testID={`${testID}__description`}\n >\n {isSimple ? t.simpleDescription : t.description}\n </Text>\n )}\n\n {renderActions()}\n </Box>\n );\n};\n\nGdprBanner.displayName = \"GdprBanner\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n AccessibilityRole,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleToAccessibilityRole: Record<string, AccessibilityRole> = {\n button: \"button\",\n link: \"link\",\n img: \"image\",\n image: \"image\",\n summary: \"summary\",\n switch: \"switch\",\n checkbox: \"checkbox\",\n radio: \"radio\",\n heading: \"header\",\n text: \"text\",\n search: \"search\",\n alert: \"alert\",\n none: \"none\",\n presentation: \"none\",\n progressbar: \"progressbar\",\n scrollbar: \"scrollbar\",\n adjustable: \"adjustable\",\n tab: \"tab\",\n menu: \"menu\",\n menuitem: \"menuitem\",\n list: \"list\",\n timer: \"timer\",\n};\n\n/** RN ViewStyle.gap is typed as number (Yoga gap), not DimensionValue. */\nconst toGapValue = (gap: number | string | undefined): number | undefined => {\n if (gap === undefined) return undefined;\n if (typeof gap === \"number\") return gap;\n const pxMatch = /^(\\d+(?:\\.\\d+)?)px$/.exec(gap);\n if (pxMatch) return Number(pxMatch[1]);\n const asNumber = Number(gap);\n return Number.isFinite(asNumber) ? asNumber : undefined;\n};\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 flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n flexShrink,\n gap,\n overflow,\n opacity,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n disabled,\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 opacity: opacity ?? (disabled ? 0.5 : undefined),\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 flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\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 flexShrink,\n gap: toGapValue(gap),\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Map web a11y props; drop the rest of the web-only attributes before\n // spreading onto RN hosts (unknown props warn at runtime).\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 \"aria-busy\": ariaBusy,\n className,\n \"data-testid\": _dataTestId,\n cursor: _cursor,\n type: _type,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n const accessibilityRole =\n (typeof role === \"string\" && roleToAccessibilityRole[role]) ||\n (as === \"button\" ? \"button\" : undefined);\n const isDisabled = Boolean(disabled || ariaDisabled);\n const accessibilityState = {\n disabled: isDisabled || undefined,\n busy: Boolean(ariaBusy) || undefined,\n };\n const accessibilityLiveRegion =\n ariaLive === \"polite\" || ariaLive === \"assertive\" ? ariaLive : undefined;\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 accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : alt}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n // Prefer Pressable whenever the node is interactive or explicitly a button,\n // so disabled / aria-disabled controls stay in the a11y tree as buttons.\n if (onPress || as === \"button\") {\n return (\n <Pressable\n onPress={!isDisabled && onPress ? onPress : undefined}\n disabled={isDisabled}\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 accessibilityRole={accessibilityRole}\n accessibilityLabel={\n typeof ariaLabel === \"string\" ? ariaLabel : undefined\n }\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\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 accessibilityRole={accessibilityRole}\n accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : undefined}\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n testID,\n \"data-testid\": dataTestId,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={dataTestId || testID || id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport { Checkbox } from \"@xsolla/xui-checkbox\";\nimport { Link } from \"@xsolla/xui-link\";\nimport { InfoCr } from \"@xsolla/xui-icons-base\";\nimport type { PrivacySettingsProps } from \"./types\";\n\nconst PANE_RADIUS = 8;\nconst LIST_WIDTH = 280;\n\n/**\n * The expanded half of the GDPR banner: a category list on the left and the\n * selected category's explanation on the right (stacked on mobile, where the\n * explanation renders directly beneath the row it belongs to).\n *\n * Rendered by `GdprBanner` when the Privacy settings panel is open; exported\n * so consumers can embed the same panel inside their own settings screen.\n */\nexport const PrivacySettings: React.FC<PrivacySettingsProps> = ({\n categories,\n selectedCategoryIds,\n onToggleCategory,\n activeCategoryId,\n onActiveCategoryChange,\n viewport,\n labels,\n cookiePolicyUrl,\n privacyPolicyUrl,\n testID = \"gdpr-privacy-settings\",\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const isMobile = viewport === \"mobile\";\n const body = theme.typographyTokens.basic[\"body-sm\"];\n\n const activeDescription =\n activeCategoryId === null\n ? labels.generalInformationDescription\n : (categories.find((category) => category.id === activeCategoryId)\n ?.description ?? \"\");\n\n const descriptionPane = (\n <Box\n testID={`${testID}__description`}\n backgroundColor={theme.colors.control.faint.bg}\n borderRadius={PANE_RADIUS}\n padding={16}\n flex={isMobile ? undefined : 1}\n width={isMobile ? \"100%\" : undefined}\n aria-live=\"polite\"\n >\n <Text\n color={theme.colors.content.secondary}\n fontSize={body.fontSize}\n lineHeight={body.lineHeight}\n fontFamily={theme.fonts.body}\n >\n {activeDescription}\n </Text>\n </Box>\n );\n\n const focusStyle = {\n outlineColor: theme.colors.border.brand,\n outlineWidth: 2,\n outlineOffset: 2,\n outlineStyle: \"solid\",\n };\n\n const list = (\n <Box\n gap={12}\n width={isMobile ? \"100%\" : LIST_WIDTH}\n flexShrink={0}\n testID={`${testID}__categories`}\n >\n <Box gap={8}>\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n gap={8}\n role=\"button\"\n tabIndex={0}\n cursor=\"pointer\"\n aria-pressed={activeCategoryId === null}\n onPress={() => onActiveCategoryChange(null)}\n onKeyDown={(event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onActiveCategoryChange(null);\n }\n }}\n focusStyle={focusStyle}\n testID={`${testID}__general-information`}\n >\n <InfoCr\n variant=\"solid\"\n size={16}\n color={theme.colors.control.link.primary}\n />\n <Text\n color={theme.colors.content.primary}\n fontSize={body.fontSize}\n lineHeight={body.lineHeight}\n fontFamily={theme.fonts.body}\n >\n {labels.generalInformation}\n </Text>\n </Box>\n {isMobile && activeCategoryId === null && descriptionPane}\n </Box>\n\n {categories.map((category) => (\n <Box key={category.id} gap={8}>\n <Box onPress={() => onActiveCategoryChange(category.id)}>\n <Checkbox\n size=\"md\"\n checked={selectedCategoryIds.includes(category.id)}\n disabled={category.locked}\n onChange={() => onToggleCategory(category.id)}\n testID={`${testID}__category-${category.id}`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n {category.label}\n </Checkbox>\n </Box>\n {isMobile && activeCategoryId === category.id && descriptionPane}\n </Box>\n ))}\n </Box>\n );\n\n return (\n <Box testID={testID} gap={16} width=\"100%\">\n <Box\n flexDirection={isMobile ? \"column\" : \"row\"}\n gap={isMobile ? 12 : 24}\n alignItems=\"flex-start\"\n width=\"100%\"\n >\n {list}\n {!isMobile && descriptionPane}\n </Box>\n\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n gap={8}\n testID={`${testID}__policies`}\n >\n <Link\n size=\"sm\"\n href={cookiePolicyUrl}\n target=\"_blank\"\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n testID={`${testID}__cookie-policy`}\n >\n {labels.cookiePolicy}\n </Link>\n <Text\n color={theme.colors.content.tertiary}\n fontSize={body.fontSize}\n lineHeight={body.lineHeight}\n fontFamily={theme.fonts.body}\n aria-hidden={true}\n >\n {\"•\"}\n </Text>\n <Link\n size=\"sm\"\n href={privacyPolicyUrl}\n target=\"_blank\"\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n testID={`${testID}__privacy-policy`}\n >\n {labels.privacyPolicy}\n </Link>\n </Box>\n </Box>\n );\n};\n\nPrivacySettings.displayName = \"PrivacySettings\";\n","import type { GdprBannerLabels, GdprCookieCategory } from \"./types\";\n\n/**\n * The five categories shown in the Figma Privacy settings panel.\n *\n * `essential` is `locked`: it renders checked + disabled and is always part of\n * the reported selection, including after `Reject All`.\n */\nexport const DEFAULT_CATEGORIES: GdprCookieCategory[] = [\n {\n id: \"essential\",\n label: \"Essential cookies\",\n locked: true,\n description:\n \"These cookies are required for the Xsolla Ecosystem to function and cannot be disabled in our systems. They are often only set in response to activities taken by you that constitute a request for services, such as changing your privacy settings, logging in, contacting customer support, or filling out forms. You can set your browser to block or inform you about these cookies, but some aspects of the Xsolla Ecosystem will not function properly. These cookies do not contain personally identifying information.\",\n },\n {\n id: \"analytical\",\n label: \"Analytical and performance cookies\",\n description:\n \"These cookies let us count visits and traffic sources so we can measure and improve the performance of the Xsolla Ecosystem. They help us understand which pages are the most and least popular and see how visitors move around the service. All information these cookies collect is aggregated.\",\n },\n {\n id: \"functional\",\n label: \"Functional cookies\",\n description:\n \"These cookies enable the Xsolla Ecosystem to provide enhanced functionality and personalization, such as remembering your preferences and the region you are in. If you do not allow these cookies, some or all of these services may not function properly.\",\n },\n {\n id: \"targeting\",\n label: \"Targeting cookies\",\n description:\n \"These cookies may be set through the Xsolla Ecosystem by our advertising partners to build a profile of your interests and show you relevant offers on other sites. They do not store directly personal information but are based on uniquely identifying your browser and device.\",\n },\n];\n\nexport const DEFAULT_LABELS: Required<GdprBannerLabels> = {\n title: \"How we use cookies\",\n description:\n \"We use cookies to personalize your experience. If you reject the use of cookies, your experience will not be tailored to your preferences.\",\n simpleDescription:\n \"We only use essential cookies that allow us to run this service. Read our cookie policy to learn more.\",\n privacySettingsTitle: \"Privacy settings\",\n generalInformation: \"General information\",\n generalInformationDescription:\n \"We use cookies to personalize your experience, to run and secure the Xsolla Ecosystem, and to measure how it is used. Choose which categories you want to allow below. You can change your choice at any time.\",\n customize: \"Customize\",\n rejectAll: \"Reject All\",\n acceptAll: \"Accept All\",\n confirmSelection: \"Confirm Selection\",\n dismiss: \"Dismiss\",\n close: \"Close\",\n cookiePolicy: \"Cookie Policy\",\n privacyPolicy: \"Privacy Policy\",\n closeButtonAriaLabel: \"Close cookie banner\",\n};\n\n/** Collapsed desktop card width, from the Figma frame. */\nexport const CARD_WIDTH = 400;\n\n/** Default bottom / left / right inset of the collapsed banner, from Figma. */\nexport const EDGE_OFFSET = 20;\n\n/**\n * Vertical and horizontal gap between stacked content blocks and between\n * adjacent action buttons.\n *\n * 8px, measured on the Figma content column (`itemSpacing: 8` on the auto-\n * layout frame inside node 21855:20776).\n */\nexport const CONTENT_GAP = 8;\n"],"mappings":"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","names":["import_react_native","import_jsx_runtime","RNText","import_xui_core","import_xui_icons_base","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../../src/index.tsx","../../src/GdprBanner.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../src/PrivacySettings.tsx","../../src/defaults.ts"],"sourcesContent":["export { GdprBanner } from \"./GdprBanner\";\nexport { PrivacySettings } from \"./PrivacySettings\";\nexport { DEFAULT_CATEGORIES, DEFAULT_LABELS } from \"./defaults\";\nexport type {\n GdprBannerProps,\n GdprBannerType,\n GdprBannerViewport,\n GdprBannerButtonsRow,\n GdprBannerAnchor,\n GdprBannerLabels,\n GdprCookieCategory,\n PrivacySettingsProps,\n} from \"./types\";\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId } from \"@xsolla/xui-core\";\nimport { Button, FlexButton } from \"@xsolla/xui-button\";\nimport { Remove } from \"@xsolla/xui-icons-base\";\nimport { PrivacySettings } from \"./PrivacySettings\";\nimport {\n ACTION_BUTTON_SIZE,\n CARD_WIDTH,\n CONTENT_GAP,\n DEFAULT_CATEGORIES,\n DEFAULT_LABELS,\n EDGE_OFFSET,\n} from \"./defaults\";\nimport type { GdprBannerProps } from \"./types\";\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 = (element: HTMLElement): boolean => {\n if (typeof window === \"undefined\") return true;\n const style = window.getComputedStyle(element);\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\n/**\n * GdprBanner - the Xsolla cookie-consent banner.\n *\n * Implements the Figma `GDPR-banner` component set. The four Figma variant\n * axes map to props: `Type` -> {@link GdprBannerProps.type}, `Fold` ->\n * {@link GdprBannerProps.expanded} (inverted - Figma's `Fold=On` is the\n * collapsed card), `Buttons row` -> {@link GdprBannerProps.buttonsRow},\n * `Viewport` -> {@link GdprBannerProps.viewport}.\n *\n * ## Layout\n *\n * - Desktop, collapsed - a card pinned to the bottom of the viewport with a\n * 20px inset, at either bottom corner (`anchor`). Its top corners use the\n * modal radius token and its bottom corners the toast radius token.\n * - Desktop, expanded - a wider panel hosting the two-column Privacy settings.\n * It sits flush with the bottom edge, so its bottom corners are square.\n * - Mobile - always bottom-anchored, full width and flush against the bottom\n * edge: `offset` is not applied and the bottom corners are square.\n *\n * `Customize` and `Close` are borderless brand-tone text actions, matching the\n * Figma `Button` with `Type=Tertiary` / `Tone=Brand`.\n *\n * ## Accessibility\n *\n * - `role=\"dialog\"` labelled by the visible heading.\n * - Focus moves into the banner when it mounts and when the panel expands.\n * - Tab and Shift+Tab cycle within the banner; Escape fires `onClose`.\n * - The close control carries an explicit `aria-label`.\n */\nexport const GdprBanner: React.FC<GdprBannerProps> = ({\n type = \"complex\",\n viewport = \"desktop\",\n buttonsRow = \"single\",\n anchor = \"bottom-left\",\n expanded,\n defaultExpanded = false,\n onExpandedChange,\n categories = DEFAULT_CATEGORIES,\n selectedCategoryIds,\n defaultSelectedCategoryIds,\n onSelectionChange,\n labels,\n cookiePolicyUrl,\n privacyPolicyUrl,\n onAcceptAll,\n onRejectAll,\n onCustomize,\n onConfirmSelection,\n onDismiss,\n onClose,\n showCloseButton = true,\n position = \"fixed\",\n offset = EDGE_OFFSET,\n testID = \"gdpr-banner\",\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const containerRef = useRef<HTMLDivElement>(null);\n\n const rawId = useId();\n const titleId = `gdpr-banner-title-${rawId.replace(/:/g, \"\")}`;\n\n const t = useMemo(() => ({ ...DEFAULT_LABELS, ...labels }), [labels]);\n\n const isMobile = viewport === \"mobile\";\n const isSimple = type === \"simple\";\n\n const allIds = useMemo(\n () => categories.map((category) => category.id),\n [categories]\n );\n const lockedIds = useMemo(\n () => categories.filter((category) => category.locked).map((c) => c.id),\n [categories]\n );\n\n const isExpandedControlled = expanded !== undefined;\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n // `simple` has no Privacy settings panel, so it can never be expanded.\n const isExpanded =\n !isSimple && (isExpandedControlled ? expanded : internalExpanded);\n\n const isSelectionControlled = selectedCategoryIds !== undefined;\n const [internalSelection, setInternalSelection] = useState<string[]>(\n defaultSelectedCategoryIds ?? allIds\n );\n const selection = isSelectionControlled\n ? selectedCategoryIds\n : internalSelection;\n\n const [activeCategoryId, setActiveCategoryId] = useState<string | null>(null);\n\n const setExpanded = useCallback(\n (next: boolean) => {\n if (!isExpandedControlled) setInternalExpanded(next);\n onExpandedChange?.(next);\n },\n [isExpandedControlled, onExpandedChange]\n );\n\n const setSelection = useCallback(\n (next: string[]) => {\n if (!isSelectionControlled) setInternalSelection(next);\n onSelectionChange?.(next);\n },\n [isSelectionControlled, onSelectionChange]\n );\n\n // Escape dismisses the banner outright, matching the close (X) control.\n useEffect(() => {\n if (!onClose || typeof document === \"undefined\") 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 // Pull focus in on mount and whenever the panel expands or collapses, so the\n // newly revealed controls are reachable without hunting for them.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const [first] = getFocusableElements(container);\n first?.focus();\n }, [isExpanded]);\n\n const handleTabKey = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !containerRef.current) return;\n const focusable = getFocusableElements(containerRef.current);\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (!first) {\n event.preventDefault();\n return;\n }\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }, []);\n\n const handleToggleCategory = useCallback(\n (id: string) => {\n const category = categories.find((item) => item.id === id);\n if (!category || category.locked) return;\n const next = selection.includes(id)\n ? selection.filter((item) => item !== id)\n : [...selection, id];\n setSelection(next);\n },\n [categories, selection, setSelection]\n );\n\n const handleAcceptAll = useCallback(() => {\n setSelection(allIds);\n onAcceptAll?.();\n }, [allIds, onAcceptAll, setSelection]);\n\n const handleRejectAll = useCallback(() => {\n // Locked categories stay consented - they cannot be switched off.\n setSelection(lockedIds);\n onRejectAll?.();\n }, [lockedIds, onRejectAll, setSelection]);\n\n const handleCustomize = useCallback(() => {\n setExpanded(true);\n onCustomize?.();\n }, [onCustomize, setExpanded]);\n\n const handleCollapse = useCallback(() => {\n setExpanded(false);\n }, [setExpanded]);\n\n const handleConfirmSelection = useCallback(() => {\n onConfirmSelection?.(selection);\n }, [onConfirmSelection, selection]);\n\n const titleToken = theme.typographyTokens.basic[\"body-lg\"];\n const bodyToken = theme.typographyTokens.basic[\"body-sm\"];\n\n /** Filled action (Reject All / Accept All / Confirm Selection / Dismiss). */\n const solidButton = (\n key: string,\n label: string,\n onPress: () => void,\n fullWidth: boolean\n ) => (\n <Button\n key={key}\n variant=\"secondary\"\n size={ACTION_BUTTON_SIZE}\n fullWidth={fullWidth}\n onPress={onPress}\n testID={`${testID}__${key}`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n {label}\n </Button>\n );\n\n /**\n * Borderless text action (Customize / Close).\n *\n * Figma builds these from the same `Button` component as the filled actions\n * beside them, switching only the `Type` axis to `Tertiary` (`Tone=Brand`) -\n * see nodes 21858:22234 (`Customize`) and 21858:22512 (`Close`). Rendering\n * them as a `FlexButton` instead made them a different control with its own\n * height, padding and type scale, so the action row read as mismatched.\n *\n * `Button variant=\"ghost\"` is still not an option: its border token is not\n * transparent, so it draws a visible outline the design does not have.\n * `tertiary` is - `control.brand.tertiary` resolves `bg` and `border` to a\n * fully transparent colour in both `light.json` and `dark.json`, and the\n * label picks up `control.brand.text.tertiary`, the brand tone the design\n * uses.\n */\n const textButton = (key: string, label: string, onPress: () => void) => (\n <Button\n key={key}\n variant=\"tertiary\"\n tone=\"brand\"\n size={ACTION_BUTTON_SIZE}\n onPress={onPress}\n testID={`${testID}__${key}`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n {label}\n </Button>\n );\n\n const renderActions = () => {\n if (isSimple) {\n return (\n <Box\n width=\"100%\"\n flexDirection=\"row\"\n justifyContent={isMobile ? \"center\" : \"flex-end\"}\n >\n {solidButton(\"dismiss\", t.dismiss, () => onDismiss?.(), isMobile)}\n </Box>\n );\n }\n\n if (isExpanded) {\n const close = textButton(\"close\", t.close, handleCollapse);\n const reject = solidButton(\n \"reject-all\",\n t.rejectAll,\n handleRejectAll,\n isMobile\n );\n const confirm = solidButton(\n \"confirm-selection\",\n t.confirmSelection,\n handleConfirmSelection,\n isMobile\n );\n\n return isMobile ? (\n <Box width=\"100%\" gap={CONTENT_GAP} alignItems=\"center\">\n {[confirm, reject, close]}\n </Box>\n ) : (\n <Box\n width=\"100%\"\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"flex-end\"\n gap={CONTENT_GAP}\n >\n {[close, reject, confirm]}\n </Box>\n );\n }\n\n const customize = textButton(\"customize\", t.customize, handleCustomize);\n\n if (isMobile) {\n return (\n <Box width=\"100%\" gap={CONTENT_GAP} alignItems=\"center\">\n {solidButton(\"accept-all\", t.acceptAll, handleAcceptAll, true)}\n {solidButton(\"reject-all\", t.rejectAll, handleRejectAll, true)}\n {customize}\n </Box>\n );\n }\n\n if (buttonsRow === \"double\") {\n // Figma node 21855:20776 - Customize centred on its own row, then two\n // equal-width buttons filling the 250px content column with an 8px gap.\n return (\n <Box width=\"100%\" gap={CONTENT_GAP}>\n <Box flexDirection=\"row\" justifyContent=\"center\" width=\"100%\">\n {customize}\n </Box>\n <Box flexDirection=\"row\" gap={CONTENT_GAP} width=\"100%\">\n <Box flex={1}>\n {solidButton(\"reject-all\", t.rejectAll, handleRejectAll, true)}\n </Box>\n <Box flex={1}>\n {solidButton(\"accept-all\", t.acceptAll, handleAcceptAll, true)}\n </Box>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box\n width=\"100%\"\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"flex-end\"\n gap={CONTENT_GAP}\n >\n {customize}\n {solidButton(\"reject-all\", t.rejectAll, handleRejectAll, false)}\n {solidButton(\"accept-all\", t.acceptAll, handleAcceptAll, false)}\n </Box>\n );\n };\n\n // Mobile is a bottom sheet and the expanded desktop panel is a full-bleed\n // bar, so both sit flush against the viewport edges; only the collapsed\n // desktop card is inset.\n const isFlushWithEdges = isExpanded || isMobile;\n const edge = isFlushWithEdges ? 0 : offset;\n const isFixed = position === \"fixed\";\n const spansFullWidth = isExpanded || isMobile;\n\n /**\n * Figma binds the banner's four corners to two different radius tokens: the\n * modal frame radius on top, and - on the collapsed desktop card only - the\n * toast frame radius on the bottom (node 21855:20787). Anything flush with\n * the bottom edge keeps square bottom corners (nodes 21855:20743 mobile /\n * expanded).\n *\n * Written as the four longhand properties rather than a `border-radius`\n * shorthand string: the native `Box` forwards `borderRadius` straight into a\n * React Native `ViewStyle`, which only accepts a number, so a shorthand\n * would silently drop on native.\n */\n const topCornerRadius = theme.shape.modal.borderRadius;\n const bottomCornerRadius = isFlushWithEdges\n ? 0\n : theme.shape.toast.borderRadius;\n const cornerRadiusStyle = {\n borderTopLeftRadius: topCornerRadius,\n borderTopRightRadius: topCornerRadius,\n borderBottomLeftRadius: bottomCornerRadius,\n borderBottomRightRadius: bottomCornerRadius,\n };\n\n return (\n <Box\n ref={containerRef}\n testID={testID}\n role=\"dialog\"\n aria-labelledby={titleId}\n onKeyDown={handleTabKey}\n data-gdpr-banner-type={type}\n data-gdpr-banner-viewport={viewport}\n data-gdpr-banner-expanded={isExpanded ? \"true\" : \"false\"}\n position={isFixed ? \"fixed\" : \"relative\"}\n bottom={isFixed ? edge : undefined}\n left={isFixed && (spansFullWidth || anchor === \"bottom-left\") ? edge : undefined}\n right={\n isFixed && (spansFullWidth || anchor === \"bottom-right\") ? edge : undefined\n }\n zIndex={isFixed ? 1000 : undefined}\n width={spansFullWidth ? \"100%\" : CARD_WIDTH}\n maxWidth=\"100%\"\n backgroundColor={theme.colors.layer.float}\n style={cornerRadiusStyle}\n padding={isMobile ? 16 : 20}\n gap={CONTENT_GAP}\n >\n <Box\n flexDirection=\"row\"\n alignItems=\"flex-start\"\n justifyContent=\"space-between\"\n gap={12}\n width=\"100%\"\n >\n <Text\n id={titleId}\n color={theme.colors.content.primary}\n fontSize={titleToken.fontSize}\n lineHeight={titleToken.lineHeight}\n fontWeight={titleToken.accent?.fontWeight ?? 500}\n fontFamily={theme.fonts.body}\n >\n {isExpanded ? t.privacySettingsTitle : t.title}\n </Text>\n\n {showCloseButton && onClose && (\n <FlexButton\n variant=\"tertiary\"\n size=\"xs\"\n onPress={onClose}\n aria-label={t.closeButtonAriaLabel}\n testID={`${testID}__close-icon`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n <Remove variant=\"line\" />\n </FlexButton>\n )}\n </Box>\n\n {isExpanded ? (\n <PrivacySettings\n categories={categories}\n selectedCategoryIds={selection}\n onToggleCategory={handleToggleCategory}\n activeCategoryId={activeCategoryId}\n onActiveCategoryChange={setActiveCategoryId}\n viewport={viewport}\n labels={{\n generalInformation: t.generalInformation,\n generalInformationDescription: t.generalInformationDescription,\n cookiePolicy: t.cookiePolicy,\n privacyPolicy: t.privacyPolicy,\n }}\n cookiePolicyUrl={cookiePolicyUrl}\n privacyPolicyUrl={privacyPolicyUrl}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n testID={`${testID}__privacy-settings`}\n />\n ) : (\n <Text\n color={theme.colors.content.secondary}\n fontSize={bodyToken.fontSize}\n lineHeight={bodyToken.lineHeight}\n fontFamily={theme.fonts.body}\n testID={`${testID}__description`}\n >\n {isSimple ? t.simpleDescription : t.description}\n </Text>\n )}\n\n {renderActions()}\n </Box>\n );\n};\n\nGdprBanner.displayName = \"GdprBanner\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n AccessibilityRole,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleToAccessibilityRole: Record<string, AccessibilityRole> = {\n button: \"button\",\n link: \"link\",\n img: \"image\",\n image: \"image\",\n summary: \"summary\",\n switch: \"switch\",\n checkbox: \"checkbox\",\n radio: \"radio\",\n heading: \"header\",\n text: \"text\",\n search: \"search\",\n alert: \"alert\",\n none: \"none\",\n presentation: \"none\",\n progressbar: \"progressbar\",\n scrollbar: \"scrollbar\",\n adjustable: \"adjustable\",\n tab: \"tab\",\n menu: \"menu\",\n menuitem: \"menuitem\",\n list: \"list\",\n timer: \"timer\",\n};\n\n/** RN ViewStyle.gap is typed as number (Yoga gap), not DimensionValue. */\nconst toGapValue = (gap: number | string | undefined): number | undefined => {\n if (gap === undefined) return undefined;\n if (typeof gap === \"number\") return gap;\n const pxMatch = /^(\\d+(?:\\.\\d+)?)px$/.exec(gap);\n if (pxMatch) return Number(pxMatch[1]);\n const asNumber = Number(gap);\n return Number.isFinite(asNumber) ? asNumber : undefined;\n};\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 flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n flexShrink,\n gap,\n overflow,\n opacity,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n disabled,\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 opacity: opacity ?? (disabled ? 0.5 : undefined),\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 flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\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 flexShrink,\n gap: toGapValue(gap),\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Map web a11y props; drop the rest of the web-only attributes before\n // spreading onto RN hosts (unknown props warn at runtime).\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 \"aria-busy\": ariaBusy,\n className,\n \"data-testid\": _dataTestId,\n cursor: _cursor,\n type: _type,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n const accessibilityRole =\n (typeof role === \"string\" && roleToAccessibilityRole[role]) ||\n (as === \"button\" ? \"button\" : undefined);\n const isDisabled = Boolean(disabled || ariaDisabled);\n const accessibilityState = {\n disabled: isDisabled || undefined,\n busy: Boolean(ariaBusy) || undefined,\n };\n const accessibilityLiveRegion =\n ariaLive === \"polite\" || ariaLive === \"assertive\" ? ariaLive : undefined;\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 accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : alt}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n // Prefer Pressable whenever the node is interactive or explicitly a button,\n // so disabled / aria-disabled controls stay in the a11y tree as buttons.\n if (onPress || as === \"button\") {\n return (\n <Pressable\n onPress={!isDisabled && onPress ? onPress : undefined}\n disabled={isDisabled}\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 accessibilityRole={accessibilityRole}\n accessibilityLabel={\n typeof ariaLabel === \"string\" ? ariaLabel : undefined\n }\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\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 accessibilityRole={accessibilityRole}\n accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : undefined}\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n testID,\n \"data-testid\": dataTestId,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={dataTestId || testID || id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport { Checkbox } from \"@xsolla/xui-checkbox\";\nimport { Link } from \"@xsolla/xui-link\";\nimport { InfoCr } from \"@xsolla/xui-icons-base\";\nimport type { PrivacySettingsProps } from \"./types\";\n\nconst PANE_RADIUS = 8;\nconst LIST_WIDTH = 280;\n\n/**\n * The expanded half of the GDPR banner: a category list on the left and the\n * selected category's explanation on the right (stacked on mobile, where the\n * explanation renders directly beneath the row it belongs to).\n *\n * Rendered by `GdprBanner` when the Privacy settings panel is open; exported\n * so consumers can embed the same panel inside their own settings screen.\n */\nexport const PrivacySettings: React.FC<PrivacySettingsProps> = ({\n categories,\n selectedCategoryIds,\n onToggleCategory,\n activeCategoryId,\n onActiveCategoryChange,\n viewport,\n labels,\n cookiePolicyUrl,\n privacyPolicyUrl,\n testID = \"gdpr-privacy-settings\",\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const isMobile = viewport === \"mobile\";\n const body = theme.typographyTokens.basic[\"body-sm\"];\n\n const activeDescription =\n activeCategoryId === null\n ? labels.generalInformationDescription\n : (categories.find((category) => category.id === activeCategoryId)\n ?.description ?? \"\");\n\n const descriptionPane = (\n <Box\n testID={`${testID}__description`}\n backgroundColor={theme.colors.control.faint.bg}\n borderRadius={PANE_RADIUS}\n padding={16}\n flex={isMobile ? undefined : 1}\n width={isMobile ? \"100%\" : undefined}\n aria-live=\"polite\"\n >\n <Text\n color={theme.colors.content.secondary}\n fontSize={body.fontSize}\n lineHeight={body.lineHeight}\n fontFamily={theme.fonts.body}\n >\n {activeDescription}\n </Text>\n </Box>\n );\n\n const focusStyle = {\n outlineColor: theme.colors.border.brand,\n outlineWidth: 2,\n outlineOffset: 2,\n outlineStyle: \"solid\",\n };\n\n const list = (\n <Box\n gap={12}\n width={isMobile ? \"100%\" : LIST_WIDTH}\n flexShrink={0}\n testID={`${testID}__categories`}\n >\n <Box gap={8}>\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n gap={8}\n role=\"button\"\n tabIndex={0}\n cursor=\"pointer\"\n aria-pressed={activeCategoryId === null}\n onPress={() => onActiveCategoryChange(null)}\n onKeyDown={(event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onActiveCategoryChange(null);\n }\n }}\n focusStyle={focusStyle}\n testID={`${testID}__general-information`}\n >\n <InfoCr\n variant=\"solid\"\n size={16}\n color={theme.colors.control.link.primary}\n />\n <Text\n color={theme.colors.content.primary}\n fontSize={body.fontSize}\n lineHeight={body.lineHeight}\n fontFamily={theme.fonts.body}\n >\n {labels.generalInformation}\n </Text>\n </Box>\n {isMobile && activeCategoryId === null && descriptionPane}\n </Box>\n\n {categories.map((category) => (\n <Box key={category.id} gap={8}>\n <Box onPress={() => onActiveCategoryChange(category.id)}>\n <Checkbox\n size=\"md\"\n checked={selectedCategoryIds.includes(category.id)}\n disabled={category.locked}\n onChange={() => onToggleCategory(category.id)}\n testID={`${testID}__category-${category.id}`}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n >\n {category.label}\n </Checkbox>\n </Box>\n {isMobile && activeCategoryId === category.id && descriptionPane}\n </Box>\n ))}\n </Box>\n );\n\n return (\n <Box testID={testID} gap={16} width=\"100%\">\n <Box\n flexDirection={isMobile ? \"column\" : \"row\"}\n gap={isMobile ? 12 : 24}\n alignItems=\"flex-start\"\n width=\"100%\"\n >\n {list}\n {!isMobile && descriptionPane}\n </Box>\n\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n gap={8}\n testID={`${testID}__policies`}\n >\n <Link\n size=\"sm\"\n href={cookiePolicyUrl}\n target=\"_blank\"\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n testID={`${testID}__cookie-policy`}\n >\n {labels.cookiePolicy}\n </Link>\n <Text\n color={theme.colors.content.tertiary}\n fontSize={body.fontSize}\n lineHeight={body.lineHeight}\n fontFamily={theme.fonts.body}\n aria-hidden={true}\n >\n {\"•\"}\n </Text>\n <Link\n size=\"sm\"\n href={privacyPolicyUrl}\n target=\"_blank\"\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n testID={`${testID}__privacy-policy`}\n >\n {labels.privacyPolicy}\n </Link>\n </Box>\n </Box>\n );\n};\n\nPrivacySettings.displayName = \"PrivacySettings\";\n","import type { GdprBannerLabels, GdprCookieCategory } from \"./types\";\n\n/**\n * The five categories shown in the Figma Privacy settings panel.\n *\n * `essential` is `locked`: it renders checked + disabled and is always part of\n * the reported selection, including after `Reject All`.\n */\nexport const DEFAULT_CATEGORIES: GdprCookieCategory[] = [\n {\n id: \"essential\",\n label: \"Essential cookies\",\n locked: true,\n description:\n \"These cookies are required for the Xsolla Ecosystem to function and cannot be disabled in our systems. They are often only set in response to activities taken by you that constitute a request for services, such as changing your privacy settings, logging in, contacting customer support, or filling out forms. You can set your browser to block or inform you about these cookies, but some aspects of the Xsolla Ecosystem will not function properly. These cookies do not contain personally identifying information.\",\n },\n {\n id: \"analytical\",\n label: \"Analytical and performance cookies\",\n description:\n \"These cookies let us count visits and traffic sources so we can measure and improve the performance of the Xsolla Ecosystem. They help us understand which pages are the most and least popular and see how visitors move around the service. All information these cookies collect is aggregated.\",\n },\n {\n id: \"functional\",\n label: \"Functional cookies\",\n description:\n \"These cookies enable the Xsolla Ecosystem to provide enhanced functionality and personalization, such as remembering your preferences and the region you are in. If you do not allow these cookies, some or all of these services may not function properly.\",\n },\n {\n id: \"targeting\",\n label: \"Targeting cookies\",\n description:\n \"These cookies may be set through the Xsolla Ecosystem by our advertising partners to build a profile of your interests and show you relevant offers on other sites. They do not store directly personal information but are based on uniquely identifying your browser and device.\",\n },\n];\n\nexport const DEFAULT_LABELS: Required<GdprBannerLabels> = {\n title: \"How we use cookies\",\n description:\n \"We use cookies to personalize your experience. If you reject the use of cookies, your experience will not be tailored to your preferences.\",\n simpleDescription:\n \"We only use essential cookies that allow us to run this service. Read our cookie policy to learn more.\",\n privacySettingsTitle: \"Privacy settings\",\n generalInformation: \"General information\",\n generalInformationDescription:\n \"We use cookies to personalize your experience, to run and secure the Xsolla Ecosystem, and to measure how it is used. Choose which categories you want to allow below. You can change your choice at any time.\",\n customize: \"Customize\",\n rejectAll: \"Reject All\",\n acceptAll: \"Accept All\",\n confirmSelection: \"Confirm Selection\",\n dismiss: \"Dismiss\",\n close: \"Close\",\n cookiePolicy: \"Cookie Policy\",\n privacyPolicy: \"Privacy Policy\",\n closeButtonAriaLabel: \"Close cookie banner\",\n};\n\n/** Collapsed desktop card width, from the Figma frame. */\nexport const CARD_WIDTH = 400;\n\n/** Default bottom / left / right inset of the collapsed banner, from Figma. */\nexport const EDGE_OFFSET = 20;\n\n/**\n * Size shared by every action button in the banner.\n *\n * Figma builds `Customize`, `Close`, `Reject All`, `Accept All`,\n * `Confirm Selection` and `Dismiss` from one `Button` component at a single\n * size, varying only the `Type` axis. Driving them all from one constant keeps\n * the borderless text actions from drifting out of step with the filled ones.\n */\nexport const ACTION_BUTTON_SIZE = \"md\" as const;\n\n/**\n * Vertical and horizontal gap between stacked content blocks and between\n * adjacent action buttons.\n *\n * 8px, measured on the Figma content column (`itemSpacing: 8` on the auto-\n * layout frame inside node 21855:20776).\n */\nexport const CONTENT_GAP = 8;\n"],"mappings":"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","names":["import_react_native","import_jsx_runtime","RNText","import_xui_core","import_xui_icons_base","import_jsx_runtime","import_jsx_runtime"]}
package/native/index.mjs CHANGED
@@ -547,6 +547,7 @@ var DEFAULT_LABELS = {
547
547
  };
548
548
  var CARD_WIDTH = 400;
549
549
  var EDGE_OFFSET = 20;
550
+ var ACTION_BUTTON_SIZE = "md";
550
551
  var CONTENT_GAP = 8;
551
552
 
552
553
  // src/GdprBanner.tsx
@@ -684,14 +685,13 @@ var GdprBanner = ({
684
685
  const handleConfirmSelection = useCallback(() => {
685
686
  onConfirmSelection?.(selection);
686
687
  }, [onConfirmSelection, selection]);
687
- const sizing = theme.sizing.modal();
688
688
  const titleToken = theme.typographyTokens.basic["body-lg"];
689
689
  const bodyToken = theme.typographyTokens.basic["body-sm"];
690
690
  const solidButton = (key, label, onPress, fullWidth) => /* @__PURE__ */ jsx4(
691
691
  Button,
692
692
  {
693
693
  variant: "secondary",
694
- size: "md",
694
+ size: ACTION_BUTTON_SIZE,
695
695
  fullWidth,
696
696
  onPress,
697
697
  testID: `${testID}__${key}`,
@@ -702,10 +702,11 @@ var GdprBanner = ({
702
702
  key
703
703
  );
704
704
  const textButton = (key, label, onPress) => /* @__PURE__ */ jsx4(
705
- FlexButton,
705
+ Button,
706
706
  {
707
- variant: "brand",
708
- size: "lg",
707
+ variant: "tertiary",
708
+ tone: "brand",
709
+ size: ACTION_BUTTON_SIZE,
709
710
  onPress,
710
711
  testID: `${testID}__${key}`,
711
712
  themeMode,
@@ -785,9 +786,18 @@ var GdprBanner = ({
785
786
  }
786
787
  );
787
788
  };
788
- const edge = isExpanded ? 0 : offset;
789
+ const isFlushWithEdges = isExpanded || isMobile;
790
+ const edge = isFlushWithEdges ? 0 : offset;
789
791
  const isFixed = position === "fixed";
790
792
  const spansFullWidth = isExpanded || isMobile;
793
+ const topCornerRadius = theme.shape.modal.borderRadius;
794
+ const bottomCornerRadius = isFlushWithEdges ? 0 : theme.shape.toast.borderRadius;
795
+ const cornerRadiusStyle = {
796
+ borderTopLeftRadius: topCornerRadius,
797
+ borderTopRightRadius: topCornerRadius,
798
+ borderBottomLeftRadius: bottomCornerRadius,
799
+ borderBottomRightRadius: bottomCornerRadius
800
+ };
791
801
  return /* @__PURE__ */ jsxs2(
792
802
  Box,
793
803
  {
@@ -806,8 +816,8 @@ var GdprBanner = ({
806
816
  zIndex: isFixed ? 1e3 : void 0,
807
817
  width: spansFullWidth ? "100%" : CARD_WIDTH,
808
818
  maxWidth: "100%",
809
- backgroundColor: theme.colors.background.primary,
810
- borderRadius: isExpanded ? 0 : sizing.borderRadius,
819
+ backgroundColor: theme.colors.layer.float,
820
+ style: cornerRadiusStyle,
811
821
  padding: isMobile ? 16 : 20,
812
822
  gap: CONTENT_GAP,
813
823
  children: [