@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.
- package/native/index.d.mts +6 -3
- package/native/index.d.ts +6 -3
- package/native/index.js +18 -8
- package/native/index.js.map +1 -1
- package/native/index.mjs +18 -8
- package/native/index.mjs.map +1 -1
- package/package.json +7 -7
- package/web/index.d.mts +6 -3
- package/web/index.d.ts +6 -3
- package/web/index.js +18 -8
- package/web/index.js.map +1 -1
- package/web/index.mjs +18 -8
- package/web/index.mjs.map +1 -1
package/native/index.d.mts
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
|
-
*
|
|
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 `
|
|
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
|
-
*
|
|
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 `
|
|
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:
|
|
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.
|
|
727
|
+
import_xui_button.Button,
|
|
728
728
|
{
|
|
729
|
-
variant: "
|
|
730
|
-
|
|
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
|
|
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.
|
|
832
|
-
|
|
841
|
+
backgroundColor: theme.colors.layer.float,
|
|
842
|
+
style: cornerRadiusStyle,
|
|
833
843
|
padding: isMobile ? 16 : 20,
|
|
834
844
|
gap: CONTENT_GAP,
|
|
835
845
|
children: [
|
package/native/index.js.map
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
705
|
+
Button,
|
|
706
706
|
{
|
|
707
|
-
variant: "
|
|
708
|
-
|
|
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
|
|
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.
|
|
810
|
-
|
|
819
|
+
backgroundColor: theme.colors.layer.float,
|
|
820
|
+
style: cornerRadiusStyle,
|
|
811
821
|
padding: isMobile ? 16 : 20,
|
|
812
822
|
gap: CONTENT_GAP,
|
|
813
823
|
children: [
|