@xsolla/xui-tooltip 0.216.0 → 0.217.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.mjs CHANGED
@@ -326,6 +326,41 @@ var Portal = ({ children }) => {
326
326
  return /* @__PURE__ */ jsx3(Fragment, { children });
327
327
  };
328
328
 
329
+ // src/TooltipContentContext.tsx
330
+ import { createContext, useContext } from "react";
331
+ var TooltipContentContext = createContext(
332
+ null
333
+ );
334
+ var useTooltipContentStyles = () => useContext(TooltipContentContext);
335
+
336
+ // src/contentTypography.ts
337
+ var getTooltipTypoStyles = (size) => {
338
+ switch (size) {
339
+ case "sm":
340
+ return { fontSize: 14, lineHeight: "16px" };
341
+ case "md":
342
+ return { fontSize: 16, lineHeight: "18px" };
343
+ case "lg":
344
+ return { fontSize: 18, lineHeight: "20px" };
345
+ case "xl":
346
+ return { fontSize: 20, lineHeight: "22px" };
347
+ default:
348
+ return { fontSize: 16, lineHeight: "18px" };
349
+ }
350
+ };
351
+ var TOOLTIP_BODY_VARIANT = {
352
+ sm: "body-sm",
353
+ md: "body-md",
354
+ lg: "body-lg",
355
+ xl: "body-lg"
356
+ };
357
+ var DEFAULT_BODY_FONT_WEIGHT = 400;
358
+ var DEFAULT_ACCENT_FONT_WEIGHT = 500;
359
+ var getTooltipAccentFontWeight = (typographyTokens, size) => {
360
+ const variant = TOOLTIP_BODY_VARIANT[size] ?? TOOLTIP_BODY_VARIANT.md;
361
+ return typographyTokens?.basic?.[variant]?.accent?.fontWeight ?? DEFAULT_ACCENT_FONT_WEIGHT;
362
+ };
363
+
329
364
  // src/Tooltip.tsx
330
365
  import { jsx as jsx4, jsxs } from "react/jsx-runtime";
331
366
  var TOOLTIP_OPEN_EVENT = "xui-tooltip-open";
@@ -396,20 +431,6 @@ var getPositionStyles = (triggerRect, placement, offset, isVisible) => {
396
431
  };
397
432
  }
398
433
  };
399
- var getTypoStyles = (size) => {
400
- switch (size) {
401
- case "sm":
402
- return { fontSize: 14, lineHeight: "16px" };
403
- case "md":
404
- return { fontSize: 16, lineHeight: "18px" };
405
- case "lg":
406
- return { fontSize: 18, lineHeight: "20px" };
407
- case "xl":
408
- return { fontSize: 20, lineHeight: "22px" };
409
- default:
410
- return { fontSize: 16, lineHeight: "18px" };
411
- }
412
- };
413
434
  var getArrowStyles = (placement) => {
414
435
  const base = {
415
436
  width: ARROW_SIZE,
@@ -484,9 +505,24 @@ var Tooltip = forwardRef(
484
505
  () => triggerRect ? getPositionStyles(triggerRect, placement, offset, isVisible) : { top: 0, left: 0 },
485
506
  [triggerRect, placement, offset, isVisible]
486
507
  );
487
- const typoStyles = useMemo(() => getTypoStyles(size), [size]);
508
+ const typoStyles = useMemo(() => getTooltipTypoStyles(size), [size]);
488
509
  const borderRadius = (theme.shape.tooltip[size] ?? theme.shape.tooltip.md).borderRadius;
489
510
  const arrowStyles = useMemo(() => getArrowStyles(placement), [placement]);
511
+ const contentStyles = useMemo(
512
+ () => ({
513
+ size,
514
+ fontSize: typoStyles.fontSize,
515
+ lineHeight: typoStyles.lineHeight,
516
+ color: theme.colors.content.primary,
517
+ linkColor: theme.colors.content.brand.primary
518
+ }),
519
+ [
520
+ size,
521
+ typoStyles,
522
+ theme.colors.content.primary,
523
+ theme.colors.content.brand.primary
524
+ ]
525
+ );
490
526
  useEffect(() => {
491
527
  if (!isVisible || isNative) return;
492
528
  const updatePosition = () => {
@@ -641,21 +677,28 @@ var Tooltip = forwardRef(
641
677
  }
642
678
  }
643
679
  ),
644
- /* @__PURE__ */ jsx4(
680
+ /* @__PURE__ */ jsx4(TooltipContentContext.Provider, { value: contentStyles, children: /* @__PURE__ */ jsx4(
645
681
  Box,
646
682
  {
647
683
  style: {
648
684
  wordWrap: "break-word",
649
685
  overflowWrap: "break-word",
650
686
  maxWidth: "100%",
651
- whiteSpace: "normal"
687
+ whiteSpace: "normal",
688
+ // Custom `content` inherits the tooltip's own type scale,
689
+ // so plain markup (`<strong>`, `<a>`, bare strings) reads
690
+ // at the right size without re-deriving it per call site.
691
+ fontSize: typoStyles.fontSize,
692
+ lineHeight: typoStyles.lineHeight,
693
+ fontWeight: DEFAULT_BODY_FONT_WEIGHT,
694
+ color: theme.colors.content.primary
652
695
  },
653
696
  children: typeof content === "string" || typeof content === "number" ? /* @__PURE__ */ jsx4(
654
697
  Text,
655
698
  {
656
699
  color: theme.colors.content.primary,
657
700
  fontSize: typoStyles.fontSize,
658
- fontWeight: "400",
701
+ fontWeight: String(DEFAULT_BODY_FONT_WEIGHT),
659
702
  style: {
660
703
  lineHeight: typoStyles.lineHeight,
661
704
  whiteSpace: "pre-line"
@@ -664,7 +707,7 @@ var Tooltip = forwardRef(
664
707
  }
665
708
  ) : content
666
709
  }
667
- )
710
+ ) })
668
711
  ]
669
712
  }
670
713
  ) })
@@ -674,7 +717,135 @@ var Tooltip = forwardRef(
674
717
  }
675
718
  );
676
719
  Tooltip.displayName = "Tooltip";
720
+
721
+ // src/TooltipText.tsx
722
+ import { useResolvedTheme as useResolvedTheme2 } from "@xsolla/xui-core";
723
+ import { jsx as jsx5 } from "react/jsx-runtime";
724
+ var TooltipText = ({
725
+ children,
726
+ accent = false,
727
+ size,
728
+ color,
729
+ style,
730
+ testID,
731
+ "data-testid": dataTestId,
732
+ themeMode,
733
+ themeProductContext
734
+ }) => {
735
+ const inherited = useTooltipContentStyles();
736
+ const { theme } = useResolvedTheme2({ themeMode, themeProductContext });
737
+ const resolvedSize = size ?? inherited?.size ?? "md";
738
+ const typo = getTooltipTypoStyles(resolvedSize);
739
+ const resolvedColor = color ?? inherited?.color ?? theme.colors.content.primary;
740
+ const fontWeight = accent ? getTooltipAccentFontWeight(
741
+ theme.typographyTokens,
742
+ resolvedSize
743
+ ) : DEFAULT_BODY_FONT_WEIGHT;
744
+ return /* @__PURE__ */ jsx5(
745
+ Text,
746
+ {
747
+ testID,
748
+ "data-testid": dataTestId,
749
+ color: resolvedColor,
750
+ fontSize: typo.fontSize,
751
+ fontWeight: String(fontWeight),
752
+ style: {
753
+ lineHeight: typo.lineHeight,
754
+ whiteSpace: "pre-line",
755
+ ...style
756
+ },
757
+ children
758
+ }
759
+ );
760
+ };
761
+ TooltipText.displayName = "TooltipText";
762
+
763
+ // src/TooltipLink.tsx
764
+ import { useResolvedTheme as useResolvedTheme3 } from "@xsolla/xui-core";
765
+ import { jsx as jsx6 } from "react/jsx-runtime";
766
+ var TooltipLink = ({
767
+ children,
768
+ href,
769
+ target,
770
+ rel,
771
+ onPress,
772
+ accent = false,
773
+ underline = false,
774
+ size,
775
+ color,
776
+ style,
777
+ testID,
778
+ "data-testid": dataTestId,
779
+ themeMode,
780
+ themeProductContext
781
+ }) => {
782
+ const inherited = useTooltipContentStyles();
783
+ const { theme } = useResolvedTheme3({ themeMode, themeProductContext });
784
+ const resolvedSize = size ?? inherited?.size ?? "md";
785
+ const typo = getTooltipTypoStyles(resolvedSize);
786
+ const resolvedColor = color ?? inherited?.linkColor ?? theme.colors.content.brand.primary;
787
+ const fontWeight = accent ? getTooltipAccentFontWeight(
788
+ theme.typographyTokens,
789
+ resolvedSize
790
+ ) : DEFAULT_BODY_FONT_WEIGHT;
791
+ const resolvedRel = target === "_blank" ? Array.from(
792
+ /* @__PURE__ */ new Set([
793
+ ...rel ? rel.split(/\s+/).filter(Boolean) : [],
794
+ "noopener",
795
+ "noreferrer"
796
+ ])
797
+ ).join(" ") : rel;
798
+ const handlePress = (event) => {
799
+ if (!onPress) return;
800
+ event?.preventDefault?.();
801
+ onPress();
802
+ };
803
+ return /* @__PURE__ */ jsx6(
804
+ Box,
805
+ {
806
+ as: "a",
807
+ href,
808
+ target,
809
+ rel: resolvedRel,
810
+ onPress: handlePress,
811
+ onClick: handlePress,
812
+ role: "link",
813
+ cursor: "pointer",
814
+ display: "inline-flex",
815
+ alignItems: "center",
816
+ testID,
817
+ "data-testid": dataTestId,
818
+ hoverStyle: { opacity: 0.8 },
819
+ focusStyle: {
820
+ outlineColor: theme.colors.border.brand,
821
+ outlineWidth: 2,
822
+ outlineStyle: "solid",
823
+ outlineOffset: 2
824
+ },
825
+ children: /* @__PURE__ */ jsx6(
826
+ Text,
827
+ {
828
+ color: resolvedColor,
829
+ fontSize: typo.fontSize,
830
+ fontWeight: String(fontWeight),
831
+ textDecoration: underline ? "underline" : "none",
832
+ style: { lineHeight: typo.lineHeight, ...style },
833
+ children
834
+ }
835
+ )
836
+ }
837
+ );
838
+ };
839
+ TooltipLink.displayName = "TooltipLink";
677
840
  export {
678
- Tooltip
841
+ DEFAULT_ACCENT_FONT_WEIGHT,
842
+ DEFAULT_BODY_FONT_WEIGHT,
843
+ Tooltip,
844
+ TooltipContentContext,
845
+ TooltipLink,
846
+ TooltipText,
847
+ getTooltipAccentFontWeight,
848
+ getTooltipTypoStyles,
849
+ useTooltipContentStyles
679
850
  };
680
851
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Tooltip.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../src/Portal.native.tsx"],"sourcesContent":["import React, { forwardRef, useState, useMemo, useEffect, useRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text } from \"@xsolla/xui-primitives\";\nimport {\n useResolvedTheme,\n useId,\n isNative,\n useModalId,\n useOverlayLayer,\n LAYER_OFFSET,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport type { TooltipPlacement, TooltipProps, TooltipSize } from \"./types\";\nimport { Portal } from \"./Portal\";\n\nconst TOOLTIP_OPEN_EVENT = \"xui-tooltip-open\";\ntype TooltipTheme = {\n colors: {\n layer: {\n float: string;\n };\n content: {\n primary: string;\n };\n };\n shape: {\n tooltip: Record<TooltipSize, { borderRadius: number | string }>;\n };\n};\n\nconst ARROW_SIZE = 10;\nconst ARROW_HALF = ARROW_SIZE / 2;\n// Keeps the arrow clear of the panel's corner radius (8px for `md`).\nconst ARROW_EDGE_OFFSET = 12;\nconst ARROW_CENTER_INSET = ARROW_EDGE_OFFSET + ARROW_HALF;\n\n// Re-centres the arrow on triggers too narrow for the flush inset (FEP-889).\nconst getArrowAlignmentShift = (triggerWidth: number) =>\n Math.max(0, ARROW_CENTER_INSET - triggerWidth / 2);\n\nconst getPositionStyles = (\n triggerRect: DOMRect,\n placement: TooltipPlacement,\n offset: number,\n isVisible: boolean\n) => {\n const slideDistance = 8;\n const scale = isVisible ? \"scale(1)\" : \"scale(0.95)\";\n const slideOffset = isVisible ? 0 : -slideDistance;\n const arrowShift = getArrowAlignmentShift(triggerRect.width);\n\n switch (placement) {\n case \"top\":\n return {\n top: triggerRect.top - offset,\n left: triggerRect.left + triggerRect.width / 2,\n transform: `translateX(-50%) translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n case \"top-left\":\n return {\n top: triggerRect.top - offset,\n left: triggerRect.right + arrowShift,\n transform: `translateX(-100%) translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n case \"top-right\":\n return {\n top: triggerRect.top - offset,\n left: triggerRect.left - arrowShift,\n transform: `translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n case \"bottom\":\n return {\n top: triggerRect.bottom + offset,\n left: triggerRect.left + triggerRect.width / 2,\n transform: `translateX(-50%) translateY(${slideOffset}px) ${scale}`,\n };\n case \"bottom-left\":\n return {\n top: triggerRect.bottom + offset,\n left: triggerRect.right + arrowShift,\n transform: `translateX(-100%) translateY(${slideOffset}px) ${scale}`,\n };\n case \"bottom-right\":\n return {\n top: triggerRect.bottom + offset,\n left: triggerRect.left - arrowShift,\n transform: `translateY(${slideOffset}px) ${scale}`,\n };\n case \"left\":\n return {\n top: triggerRect.top + triggerRect.height / 2,\n left: triggerRect.left - offset,\n transform: `translateX(calc(-100% - ${slideOffset}px)) translateY(-50%) ${scale}`,\n };\n case \"right\":\n return {\n top: triggerRect.top + triggerRect.height / 2,\n left: triggerRect.right + offset,\n transform: `translateX(${slideOffset}px) translateY(-50%) ${scale}`,\n };\n default:\n return {\n top: triggerRect.top - offset,\n left: triggerRect.left,\n transform: `translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n }\n};\n\nconst getTypoStyles = (size: TooltipSize) => {\n switch (size) {\n case \"sm\":\n return { fontSize: 14, lineHeight: \"16px\" };\n case \"md\":\n return { fontSize: 16, lineHeight: \"18px\" };\n case \"lg\":\n return { fontSize: 18, lineHeight: \"20px\" };\n case \"xl\":\n return { fontSize: 20, lineHeight: \"22px\" };\n default:\n return { fontSize: 16, lineHeight: \"18px\" };\n }\n};\n\nconst getArrowStyles = (placement: TooltipPlacement) => {\n const base: React.CSSProperties = {\n width: ARROW_SIZE,\n height: ARROW_SIZE,\n transform: \"rotate(45deg)\",\n borderRadius: 1,\n };\n\n const placementStyles: Record<TooltipPlacement, React.CSSProperties> = {\n top: { bottom: -ARROW_HALF, left: \"50%\", marginLeft: -ARROW_HALF },\n \"top-left\": { bottom: -ARROW_HALF, right: ARROW_EDGE_OFFSET },\n \"top-right\": { bottom: -ARROW_HALF, left: ARROW_EDGE_OFFSET },\n\n bottom: { top: -ARROW_HALF, left: \"50%\", marginLeft: -ARROW_HALF },\n \"bottom-left\": { top: -ARROW_HALF, right: ARROW_EDGE_OFFSET },\n \"bottom-right\": { top: -ARROW_HALF, left: ARROW_EDGE_OFFSET },\n\n left: { right: -ARROW_HALF, top: \"50%\", marginTop: -ARROW_HALF },\n right: { left: -ARROW_HALF, top: \"50%\", marginTop: -ARROW_HALF },\n };\n\n return { ...base, ...placementStyles[placement] };\n};\n\nexport const Tooltip = forwardRef<\n HTMLDivElement,\n TooltipProps & ThemeOverrideProps\n>(\n (\n {\n content,\n children,\n size = \"md\",\n delayEnter = 0,\n delayLeave = 100,\n offset = 12,\n placement = \"top\",\n maxWidth,\n controlledVisible,\n style,\n \"data-testid\": dataTestId,\n className,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const [isHovered, setIsHovered] = useState(false);\n const [triggerRect, setTriggerRect] = useState<DOMRect | null>(null);\n const { theme: resolvedTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = resolvedTheme as TooltipTheme;\n const enterTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const leaveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const tooltipId = useId();\n const modalId = useModalId();\n const overlayLayer = useOverlayLayer();\n\n const isVisible =\n controlledVisible !== undefined ? controlledVisible : isHovered;\n\n const clearPendingVisibilityUpdates = () => {\n if (enterTimeoutRef.current) {\n clearTimeout(enterTimeoutRef.current);\n enterTimeoutRef.current = null;\n }\n\n if (leaveTimeoutRef.current) {\n clearTimeout(leaveTimeoutRef.current);\n leaveTimeoutRef.current = null;\n }\n\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n };\n\n const forceHideTooltip = () => {\n clearPendingVisibilityUpdates();\n setIsHovered(false);\n };\n\n const positionStyles = useMemo(\n () =>\n triggerRect\n ? getPositionStyles(triggerRect, placement, offset, isVisible)\n : { top: 0, left: 0 },\n [triggerRect, placement, offset, isVisible]\n );\n const typoStyles = useMemo(() => getTypoStyles(size), [size]);\n const borderRadius = (theme.shape.tooltip[size] ?? theme.shape.tooltip.md)\n .borderRadius;\n const arrowStyles = useMemo(() => getArrowStyles(placement), [placement]);\n\n // Update trigger position when tooltip becomes visible and on scroll/resize\n useEffect(() => {\n if (!isVisible || isNative) return;\n\n const updatePosition = () => {\n if (triggerRef.current) {\n setTriggerRect(triggerRef.current.getBoundingClientRect());\n }\n };\n\n updatePosition();\n\n window.addEventListener(\"scroll\", updatePosition, true);\n window.addEventListener(\"resize\", updatePosition);\n\n return () => {\n window.removeEventListener(\"scroll\", updatePosition, true);\n window.removeEventListener(\"resize\", updatePosition);\n };\n }, [isVisible]);\n\n const showTooltip = () => {\n clearPendingVisibilityUpdates();\n\n if (!isNative && typeof document !== \"undefined\") {\n document.dispatchEvent(\n new CustomEvent(TOOLTIP_OPEN_EVENT, { detail: { tooltipId } })\n );\n }\n\n // Update position before showing to prevent pop-in\n if (triggerRef.current) {\n setTriggerRect(triggerRef.current.getBoundingClientRect());\n\n // Double RAF to ensure position is rendered before showing tooltip\n rafRef.current = requestAnimationFrame(() => {\n rafRef.current = requestAnimationFrame(() => {\n if (delayEnter > 0) {\n enterTimeoutRef.current = setTimeout(() => {\n setIsHovered(true);\n }, delayEnter);\n } else {\n setIsHovered(true);\n }\n });\n });\n }\n };\n\n const showTooltipOnFocus = (event: React.FocusEvent<HTMLElement>) => {\n // Only reveal the tooltip on intentional keyboard focus. Focus that the\n // browser restores to the trigger when the tab/window regains focus — as\n // well as focus from a mouse click — must not re-trigger the tooltip\n // (FEP-832). `:focus-visible` encodes exactly this heuristic: it matches\n // for keyboard navigation but not for pointer-driven or restored focus.\n const target = event.target as HTMLElement | null;\n\n if (target && typeof target.matches === \"function\") {\n let isFocusVisible: boolean;\n try {\n isFocusVisible = target.matches(\":focus-visible\");\n } catch {\n // Legacy browsers without :focus-visible support — preserve the\n // previous behaviour of showing on any focus.\n isFocusVisible = true;\n }\n\n if (!isFocusVisible) return;\n }\n\n showTooltip();\n };\n\n const hideTooltip = () => {\n clearPendingVisibilityUpdates();\n\n if (delayLeave > 0) {\n leaveTimeoutRef.current = setTimeout(() => {\n setIsHovered(false);\n }, delayLeave);\n } else {\n setIsHovered(false);\n }\n };\n\n useEffect(() => {\n if (isNative) return;\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && isVisible) {\n forceHideTooltip();\n }\n };\n\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n forceHideTooltip();\n }\n };\n\n const handleTooltipOpen = (event: Event) => {\n const { tooltipId: activeTooltipId } =\n (event as CustomEvent).detail ?? {};\n\n if (activeTooltipId !== tooltipId) {\n forceHideTooltip();\n }\n };\n\n document.addEventListener(\"keydown\", handleEscape);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n document.addEventListener(TOOLTIP_OPEN_EVENT, handleTooltipOpen);\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n document.removeEventListener(\n \"visibilitychange\",\n handleVisibilityChange\n );\n document.removeEventListener(TOOLTIP_OPEN_EVENT, handleTooltipOpen);\n clearPendingVisibilityUpdates();\n };\n }, [isVisible, tooltipId]);\n\n return (\n <Box\n testID={testID}\n ref={triggerRef}\n position=\"relative\"\n display=\"inline-flex\"\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n onFocus={showTooltipOnFocus}\n onBlur={hideTooltip}\n className={className}\n style={{ height: \"fit-content\" }}\n aria-describedby={isVisible ? tooltipId : undefined}\n >\n {children}\n {!isNative && triggerRect && (\n <Portal>\n <Box\n ref={ref}\n data-testid={dataTestId}\n data-modal-id={modalId}\n position=\"fixed\"\n backgroundColor={theme.colors.layer.float}\n borderRadius={borderRadius}\n paddingVertical={8}\n paddingHorizontal={12}\n zIndex={overlayLayer + LAYER_OFFSET.tooltip}\n id={tooltipId}\n role=\"tooltip\"\n aria-hidden={!isVisible}\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n style={{\n ...positionStyles,\n // https://stackoverflow.com/questions/62844007/how-to-apply-tool-tip-arrow-triangle-shadow\n filter:\n \"drop-shadow(0 6px 10px rgba(7, 7, 8, 0.1)) drop-shadow(0 2px 3px rgba(7, 7, 8, 0.2))\",\n WebkitFilter:\n \"drop-shadow(0 6px 10px rgba(7, 7, 8, 0.1)) drop-shadow(0 2px 3px rgba(7, 7, 8, 0.2))\",\n opacity: isVisible ? 1 : 0,\n visibility: isVisible ? \"visible\" : \"hidden\",\n transition:\n \"opacity 150ms cubic-bezier(.4,0,.2,1), transform 150ms cubic-bezier(.4,0,.2,1), visibility 150ms cubic-bezier(.4,0,.2,1)\",\n pointerEvents: isVisible ? \"auto\" : \"none\",\n whiteSpace: \"normal\",\n width: \"max-content\",\n maxWidth: maxWidth ?? \"none\",\n overflow: \"visible\",\n willChange: isVisible ? \"transform, opacity\" : \"auto\", // optimize rendering and ensure more stable positioning\n ...style,\n }}\n >\n <Box\n position=\"absolute\"\n backgroundColor={theme.colors.layer.float}\n style={{\n ...arrowStyles,\n backfaceVisibility: \"hidden\",\n WebkitBackfaceVisibility: \"hidden\",\n }}\n />\n <Box\n style={{\n wordWrap: \"break-word\",\n overflowWrap: \"break-word\",\n maxWidth: \"100%\",\n whiteSpace: \"normal\",\n }}\n >\n {typeof content === \"string\" || typeof content === \"number\" ? (\n <Text\n color={theme.colors.content.primary}\n fontSize={typoStyles.fontSize}\n fontWeight=\"400\"\n style={{\n lineHeight: typoStyles.lineHeight,\n whiteSpace: \"pre-line\",\n }}\n >\n {content}\n </Text>\n ) : (\n content\n )}\n </Box>\n </Box>\n </Portal>\n )}\n </Box>\n );\n }\n);\n\nTooltip.displayName = \"Tooltip\";\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 { ReactNode } from \"react\";\n\ninterface PortalProps {\n children: ReactNode;\n}\n\n// Portal not supported on React Native - tooltip content renders inline\nexport const Portal = ({ children }: PortalProps) => {\n return <>{children}</>;\n};\n"],"mappings":"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","names":["jsx","jsx","jsx"]}
1
+ {"version":3,"sources":["../../src/Tooltip.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../src/Portal.native.tsx","../../src/TooltipContentContext.tsx","../../src/contentTypography.ts","../../src/TooltipText.tsx","../../src/TooltipLink.tsx"],"sourcesContent":["import React, { forwardRef, useState, useMemo, useEffect, useRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text } from \"@xsolla/xui-primitives\";\nimport {\n useResolvedTheme,\n useId,\n isNative,\n useModalId,\n useOverlayLayer,\n LAYER_OFFSET,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport type {\n TooltipContentStyles,\n TooltipPlacement,\n TooltipProps,\n TooltipSize,\n} from \"./types\";\nimport { Portal } from \"./Portal\";\nimport { TooltipContentContext } from \"./TooltipContentContext\";\nimport {\n getTooltipTypoStyles,\n DEFAULT_BODY_FONT_WEIGHT,\n type TooltipTypographyTokens,\n} from \"./contentTypography\";\n\nconst TOOLTIP_OPEN_EVENT = \"xui-tooltip-open\";\ntype TooltipTheme = {\n colors: {\n layer: {\n float: string;\n };\n content: {\n primary: string;\n brand: {\n primary: string;\n };\n };\n };\n shape: {\n tooltip: Record<TooltipSize, { borderRadius: number | string }>;\n };\n typographyTokens?: TooltipTypographyTokens;\n};\n\nconst ARROW_SIZE = 10;\nconst ARROW_HALF = ARROW_SIZE / 2;\n// Keeps the arrow clear of the panel's corner radius (8px for `md`).\nconst ARROW_EDGE_OFFSET = 12;\nconst ARROW_CENTER_INSET = ARROW_EDGE_OFFSET + ARROW_HALF;\n\n// Re-centres the arrow on triggers too narrow for the flush inset (FEP-889).\nconst getArrowAlignmentShift = (triggerWidth: number) =>\n Math.max(0, ARROW_CENTER_INSET - triggerWidth / 2);\n\nconst getPositionStyles = (\n triggerRect: DOMRect,\n placement: TooltipPlacement,\n offset: number,\n isVisible: boolean\n) => {\n const slideDistance = 8;\n const scale = isVisible ? \"scale(1)\" : \"scale(0.95)\";\n const slideOffset = isVisible ? 0 : -slideDistance;\n const arrowShift = getArrowAlignmentShift(triggerRect.width);\n\n switch (placement) {\n case \"top\":\n return {\n top: triggerRect.top - offset,\n left: triggerRect.left + triggerRect.width / 2,\n transform: `translateX(-50%) translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n case \"top-left\":\n return {\n top: triggerRect.top - offset,\n left: triggerRect.right + arrowShift,\n transform: `translateX(-100%) translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n case \"top-right\":\n return {\n top: triggerRect.top - offset,\n left: triggerRect.left - arrowShift,\n transform: `translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n case \"bottom\":\n return {\n top: triggerRect.bottom + offset,\n left: triggerRect.left + triggerRect.width / 2,\n transform: `translateX(-50%) translateY(${slideOffset}px) ${scale}`,\n };\n case \"bottom-left\":\n return {\n top: triggerRect.bottom + offset,\n left: triggerRect.right + arrowShift,\n transform: `translateX(-100%) translateY(${slideOffset}px) ${scale}`,\n };\n case \"bottom-right\":\n return {\n top: triggerRect.bottom + offset,\n left: triggerRect.left - arrowShift,\n transform: `translateY(${slideOffset}px) ${scale}`,\n };\n case \"left\":\n return {\n top: triggerRect.top + triggerRect.height / 2,\n left: triggerRect.left - offset,\n transform: `translateX(calc(-100% - ${slideOffset}px)) translateY(-50%) ${scale}`,\n };\n case \"right\":\n return {\n top: triggerRect.top + triggerRect.height / 2,\n left: triggerRect.right + offset,\n transform: `translateX(${slideOffset}px) translateY(-50%) ${scale}`,\n };\n default:\n return {\n top: triggerRect.top - offset,\n left: triggerRect.left,\n transform: `translateY(calc(-100% - ${slideOffset}px)) ${scale}`,\n };\n }\n};\n\nconst getArrowStyles = (placement: TooltipPlacement) => {\n const base: React.CSSProperties = {\n width: ARROW_SIZE,\n height: ARROW_SIZE,\n transform: \"rotate(45deg)\",\n borderRadius: 1,\n };\n\n const placementStyles: Record<TooltipPlacement, React.CSSProperties> = {\n top: { bottom: -ARROW_HALF, left: \"50%\", marginLeft: -ARROW_HALF },\n \"top-left\": { bottom: -ARROW_HALF, right: ARROW_EDGE_OFFSET },\n \"top-right\": { bottom: -ARROW_HALF, left: ARROW_EDGE_OFFSET },\n\n bottom: { top: -ARROW_HALF, left: \"50%\", marginLeft: -ARROW_HALF },\n \"bottom-left\": { top: -ARROW_HALF, right: ARROW_EDGE_OFFSET },\n \"bottom-right\": { top: -ARROW_HALF, left: ARROW_EDGE_OFFSET },\n\n left: { right: -ARROW_HALF, top: \"50%\", marginTop: -ARROW_HALF },\n right: { left: -ARROW_HALF, top: \"50%\", marginTop: -ARROW_HALF },\n };\n\n return { ...base, ...placementStyles[placement] };\n};\n\nexport const Tooltip = forwardRef<\n HTMLDivElement,\n TooltipProps & ThemeOverrideProps\n>(\n (\n {\n content,\n children,\n size = \"md\",\n delayEnter = 0,\n delayLeave = 100,\n offset = 12,\n placement = \"top\",\n maxWidth,\n controlledVisible,\n style,\n \"data-testid\": dataTestId,\n className,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const [isHovered, setIsHovered] = useState(false);\n const [triggerRect, setTriggerRect] = useState<DOMRect | null>(null);\n const { theme: resolvedTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = resolvedTheme as TooltipTheme;\n const enterTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const leaveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const tooltipId = useId();\n const modalId = useModalId();\n const overlayLayer = useOverlayLayer();\n\n const isVisible =\n controlledVisible !== undefined ? controlledVisible : isHovered;\n\n const clearPendingVisibilityUpdates = () => {\n if (enterTimeoutRef.current) {\n clearTimeout(enterTimeoutRef.current);\n enterTimeoutRef.current = null;\n }\n\n if (leaveTimeoutRef.current) {\n clearTimeout(leaveTimeoutRef.current);\n leaveTimeoutRef.current = null;\n }\n\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n };\n\n const forceHideTooltip = () => {\n clearPendingVisibilityUpdates();\n setIsHovered(false);\n };\n\n const positionStyles = useMemo(\n () =>\n triggerRect\n ? getPositionStyles(triggerRect, placement, offset, isVisible)\n : { top: 0, left: 0 },\n [triggerRect, placement, offset, isVisible]\n );\n const typoStyles = useMemo(() => getTooltipTypoStyles(size), [size]);\n const borderRadius = (theme.shape.tooltip[size] ?? theme.shape.tooltip.md)\n .borderRadius;\n const arrowStyles = useMemo(() => getArrowStyles(placement), [placement]);\n\n // Published to arbitrary `content` so nested helpers (TooltipText,\n // TooltipLink) inherit this tooltip's size scale and colour tokens.\n const contentStyles = useMemo<TooltipContentStyles>(\n () => ({\n size,\n fontSize: typoStyles.fontSize,\n lineHeight: typoStyles.lineHeight,\n color: theme.colors.content.primary,\n linkColor: theme.colors.content.brand.primary,\n }),\n [\n size,\n typoStyles,\n theme.colors.content.primary,\n theme.colors.content.brand.primary,\n ]\n );\n\n // Update trigger position when tooltip becomes visible and on scroll/resize\n useEffect(() => {\n if (!isVisible || isNative) return;\n\n const updatePosition = () => {\n if (triggerRef.current) {\n setTriggerRect(triggerRef.current.getBoundingClientRect());\n }\n };\n\n updatePosition();\n\n window.addEventListener(\"scroll\", updatePosition, true);\n window.addEventListener(\"resize\", updatePosition);\n\n return () => {\n window.removeEventListener(\"scroll\", updatePosition, true);\n window.removeEventListener(\"resize\", updatePosition);\n };\n }, [isVisible]);\n\n const showTooltip = () => {\n clearPendingVisibilityUpdates();\n\n if (!isNative && typeof document !== \"undefined\") {\n document.dispatchEvent(\n new CustomEvent(TOOLTIP_OPEN_EVENT, { detail: { tooltipId } })\n );\n }\n\n // Update position before showing to prevent pop-in\n if (triggerRef.current) {\n setTriggerRect(triggerRef.current.getBoundingClientRect());\n\n // Double RAF to ensure position is rendered before showing tooltip\n rafRef.current = requestAnimationFrame(() => {\n rafRef.current = requestAnimationFrame(() => {\n if (delayEnter > 0) {\n enterTimeoutRef.current = setTimeout(() => {\n setIsHovered(true);\n }, delayEnter);\n } else {\n setIsHovered(true);\n }\n });\n });\n }\n };\n\n const showTooltipOnFocus = (event: React.FocusEvent<HTMLElement>) => {\n // Only reveal the tooltip on intentional keyboard focus. Focus that the\n // browser restores to the trigger when the tab/window regains focus — as\n // well as focus from a mouse click — must not re-trigger the tooltip\n // (FEP-832). `:focus-visible` encodes exactly this heuristic: it matches\n // for keyboard navigation but not for pointer-driven or restored focus.\n const target = event.target as HTMLElement | null;\n\n if (target && typeof target.matches === \"function\") {\n let isFocusVisible: boolean;\n try {\n isFocusVisible = target.matches(\":focus-visible\");\n } catch {\n // Legacy browsers without :focus-visible support — preserve the\n // previous behaviour of showing on any focus.\n isFocusVisible = true;\n }\n\n if (!isFocusVisible) return;\n }\n\n showTooltip();\n };\n\n const hideTooltip = () => {\n clearPendingVisibilityUpdates();\n\n if (delayLeave > 0) {\n leaveTimeoutRef.current = setTimeout(() => {\n setIsHovered(false);\n }, delayLeave);\n } else {\n setIsHovered(false);\n }\n };\n\n useEffect(() => {\n if (isNative) return;\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && isVisible) {\n forceHideTooltip();\n }\n };\n\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n forceHideTooltip();\n }\n };\n\n const handleTooltipOpen = (event: Event) => {\n const { tooltipId: activeTooltipId } =\n (event as CustomEvent).detail ?? {};\n\n if (activeTooltipId !== tooltipId) {\n forceHideTooltip();\n }\n };\n\n document.addEventListener(\"keydown\", handleEscape);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n document.addEventListener(TOOLTIP_OPEN_EVENT, handleTooltipOpen);\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n document.removeEventListener(\n \"visibilitychange\",\n handleVisibilityChange\n );\n document.removeEventListener(TOOLTIP_OPEN_EVENT, handleTooltipOpen);\n clearPendingVisibilityUpdates();\n };\n }, [isVisible, tooltipId]);\n\n return (\n <Box\n testID={testID}\n ref={triggerRef}\n position=\"relative\"\n display=\"inline-flex\"\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n onFocus={showTooltipOnFocus}\n onBlur={hideTooltip}\n className={className}\n style={{ height: \"fit-content\" }}\n aria-describedby={isVisible ? tooltipId : undefined}\n >\n {children}\n {!isNative && triggerRect && (\n <Portal>\n <Box\n ref={ref}\n data-testid={dataTestId}\n data-modal-id={modalId}\n position=\"fixed\"\n backgroundColor={theme.colors.layer.float}\n borderRadius={borderRadius}\n paddingVertical={8}\n paddingHorizontal={12}\n zIndex={overlayLayer + LAYER_OFFSET.tooltip}\n id={tooltipId}\n role=\"tooltip\"\n aria-hidden={!isVisible}\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n style={{\n ...positionStyles,\n // https://stackoverflow.com/questions/62844007/how-to-apply-tool-tip-arrow-triangle-shadow\n filter:\n \"drop-shadow(0 6px 10px rgba(7, 7, 8, 0.1)) drop-shadow(0 2px 3px rgba(7, 7, 8, 0.2))\",\n WebkitFilter:\n \"drop-shadow(0 6px 10px rgba(7, 7, 8, 0.1)) drop-shadow(0 2px 3px rgba(7, 7, 8, 0.2))\",\n opacity: isVisible ? 1 : 0,\n visibility: isVisible ? \"visible\" : \"hidden\",\n transition:\n \"opacity 150ms cubic-bezier(.4,0,.2,1), transform 150ms cubic-bezier(.4,0,.2,1), visibility 150ms cubic-bezier(.4,0,.2,1)\",\n pointerEvents: isVisible ? \"auto\" : \"none\",\n whiteSpace: \"normal\",\n width: \"max-content\",\n maxWidth: maxWidth ?? \"none\",\n overflow: \"visible\",\n willChange: isVisible ? \"transform, opacity\" : \"auto\", // optimize rendering and ensure more stable positioning\n ...style,\n }}\n >\n <Box\n position=\"absolute\"\n backgroundColor={theme.colors.layer.float}\n style={{\n ...arrowStyles,\n backfaceVisibility: \"hidden\",\n WebkitBackfaceVisibility: \"hidden\",\n }}\n />\n <TooltipContentContext.Provider value={contentStyles}>\n <Box\n style={{\n wordWrap: \"break-word\",\n overflowWrap: \"break-word\",\n maxWidth: \"100%\",\n whiteSpace: \"normal\",\n // Custom `content` inherits the tooltip's own type scale,\n // so plain markup (`<strong>`, `<a>`, bare strings) reads\n // at the right size without re-deriving it per call site.\n fontSize: typoStyles.fontSize,\n lineHeight: typoStyles.lineHeight,\n fontWeight: DEFAULT_BODY_FONT_WEIGHT,\n color: theme.colors.content.primary,\n }}\n >\n {typeof content === \"string\" || typeof content === \"number\" ? (\n <Text\n color={theme.colors.content.primary}\n fontSize={typoStyles.fontSize}\n fontWeight={String(DEFAULT_BODY_FONT_WEIGHT)}\n style={{\n lineHeight: typoStyles.lineHeight,\n whiteSpace: \"pre-line\",\n }}\n >\n {content}\n </Text>\n ) : (\n content\n )}\n </Box>\n </TooltipContentContext.Provider>\n </Box>\n </Portal>\n )}\n </Box>\n );\n }\n);\n\nTooltip.displayName = \"Tooltip\";\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 { ReactNode } from \"react\";\n\ninterface PortalProps {\n children: ReactNode;\n}\n\n// Portal not supported on React Native - tooltip content renders inline\nexport const Portal = ({ children }: PortalProps) => {\n return <>{children}</>;\n};\n","import { createContext, useContext } from \"react\";\nimport type { TooltipContentStyles } from \"./types\";\n\n/**\n * Publishes the surrounding tooltip's resolved typography and colour tokens to\n * whatever is rendered inside its `content`, so `TooltipText` / `TooltipLink`\n * inherit the tooltip's size without the caller repeating it.\n *\n * `null` when the consumer is rendered outside a `Tooltip` — the helpers then\n * fall back to their own defaults.\n */\nexport const TooltipContentContext = createContext<TooltipContentStyles | null>(\n null\n);\n\nexport const useTooltipContentStyles = (): TooltipContentStyles | null =>\n useContext(TooltipContentContext);\n","import type { TooltipSize } from \"./types\";\n\n/**\n * Per-size font metrics for tooltip copy. Mirrors the tooltip size matrix in\n * the Figma UI kit (node 5680-32928).\n */\nexport const getTooltipTypoStyles = (size: TooltipSize) => {\n switch (size) {\n case \"sm\":\n return { fontSize: 14, lineHeight: \"16px\" };\n case \"md\":\n return { fontSize: 16, lineHeight: \"18px\" };\n case \"lg\":\n return { fontSize: 18, lineHeight: \"20px\" };\n case \"xl\":\n return { fontSize: 20, lineHeight: \"22px\" };\n default:\n return { fontSize: 16, lineHeight: \"18px\" };\n }\n};\n\n/**\n * Body typography token whose scale matches each tooltip size. Used to resolve\n * the *accent* (bold) font weight for emphasised copy inside a tooltip.\n *\n * `xl` has no body token of its own — the body scale tops out at 18px\n * (`body-lg`) — so it reuses `body-lg`'s accent weight rather than hardcoding\n * a weight the active product context may not use.\n */\nconst TOOLTIP_BODY_VARIANT: Record<TooltipSize, string> = {\n sm: \"body-sm\",\n md: \"body-md\",\n lg: \"body-lg\",\n xl: \"body-lg\",\n};\n\n/** Fallbacks for a resolved theme that predates `typographyTokens`. */\nexport const DEFAULT_BODY_FONT_WEIGHT = 400;\nexport const DEFAULT_ACCENT_FONT_WEIGHT = 500;\n\nexport interface TooltipTypographyTokens {\n basic?: Record<\n string,\n { fontWeight?: number; accent?: { fontWeight?: number } } | undefined\n >;\n}\n\n/** The slice of the resolved theme this module reads. */\nexport interface TooltipThemeTypography {\n typographyTokens?: TooltipTypographyTokens;\n}\n\n/**\n * Resolves the accent font weight for `size` from the theme's body typography\n * scale, so bold tooltip copy follows the active product context (b2b/b2c use\n * 500, corpsite uses 600) instead of a hardcoded weight.\n */\nexport const getTooltipAccentFontWeight = (\n typographyTokens: TooltipTypographyTokens | undefined,\n size: TooltipSize\n): number => {\n const variant = TOOLTIP_BODY_VARIANT[size] ?? TOOLTIP_BODY_VARIANT.md;\n\n return (\n typographyTokens?.basic?.[variant]?.accent?.fontWeight ??\n DEFAULT_ACCENT_FONT_WEIGHT\n );\n};\n","import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Text } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { useTooltipContentStyles } from \"./TooltipContentContext\";\nimport {\n getTooltipTypoStyles,\n getTooltipAccentFontWeight,\n DEFAULT_BODY_FONT_WEIGHT,\n type TooltipThemeTypography,\n} from \"./contentTypography\";\nimport type { TooltipTextProps } from \"./types\";\n\n/**\n * Text inside a `Tooltip`'s `content`, styled with the tooltip's own size\n * scale and `content/primary` colour.\n *\n * Pass `accent` for bold copy — the weight is read from the body accent token\n * matching the tooltip's size, so it tracks the active product context instead\n * of a hardcoded `700`.\n */\nexport const TooltipText: React.FC<TooltipTextProps & ThemeOverrideProps> = ({\n children,\n accent = false,\n size,\n color,\n style,\n testID,\n \"data-testid\": dataTestId,\n themeMode,\n themeProductContext,\n}) => {\n const inherited = useTooltipContentStyles();\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const resolvedSize = size ?? inherited?.size ?? \"md\";\n const typo = getTooltipTypoStyles(resolvedSize);\n const resolvedColor =\n color ?? inherited?.color ?? theme.colors.content.primary;\n const fontWeight = accent\n ? getTooltipAccentFontWeight(\n (theme as unknown as TooltipThemeTypography).typographyTokens,\n resolvedSize\n )\n : DEFAULT_BODY_FONT_WEIGHT;\n\n return (\n <Text\n testID={testID}\n data-testid={dataTestId}\n color={resolvedColor}\n fontSize={typo.fontSize}\n fontWeight={String(fontWeight)}\n style={{\n lineHeight: typo.lineHeight,\n whiteSpace: \"pre-line\",\n ...style,\n }}\n >\n {children}\n </Text>\n );\n};\n\nTooltipText.displayName = \"TooltipText\";\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, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { useTooltipContentStyles } from \"./TooltipContentContext\";\nimport {\n getTooltipTypoStyles,\n getTooltipAccentFontWeight,\n DEFAULT_BODY_FONT_WEIGHT,\n type TooltipThemeTypography,\n} from \"./contentTypography\";\nimport type { TooltipLinkProps } from \"./types\";\n\n/**\n * A link inside a `Tooltip`'s `content`. Uses the `content/brand-primary`\n * token and the tooltip's own size scale, so it sits inline with surrounding\n * `TooltipText` without the caller re-deriving typography.\n *\n * The tooltip surface is hoverable, so the link is reachable with a pointer.\n * It is **not** reachable by keyboard — tabbing away from the trigger blurs it\n * and dismisses the tooltip. When a link must be keyboard-operable, use\n * [Toggletip](../../toggletip) instead.\n */\nexport const TooltipLink: React.FC<TooltipLinkProps & ThemeOverrideProps> = ({\n children,\n href,\n target,\n rel,\n onPress,\n accent = false,\n underline = false,\n size,\n color,\n style,\n testID,\n \"data-testid\": dataTestId,\n themeMode,\n themeProductContext,\n}) => {\n const inherited = useTooltipContentStyles();\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const resolvedSize = size ?? inherited?.size ?? \"md\";\n const typo = getTooltipTypoStyles(resolvedSize);\n const resolvedColor =\n color ?? inherited?.linkColor ?? theme.colors.content.brand.primary;\n const fontWeight = accent\n ? getTooltipAccentFontWeight(\n (theme as unknown as TooltipThemeTypography).typographyTokens,\n resolvedSize\n )\n : DEFAULT_BODY_FONT_WEIGHT;\n\n // Mirrors Link: never open a new tab without the reverse-tabnabbing guard.\n const resolvedRel =\n target === \"_blank\"\n ? Array.from(\n new Set([\n ...(rel ? rel.split(/\\s+/).filter(Boolean) : []),\n \"noopener\",\n \"noreferrer\",\n ])\n ).join(\" \")\n : rel;\n\n const handlePress = (event?: any) => {\n if (!onPress) return;\n event?.preventDefault?.();\n onPress();\n };\n\n return (\n <Box\n as=\"a\"\n href={href}\n target={target}\n rel={resolvedRel}\n onPress={handlePress}\n onClick={handlePress}\n role=\"link\"\n cursor=\"pointer\"\n display=\"inline-flex\"\n alignItems=\"center\"\n testID={testID}\n data-testid={dataTestId}\n hoverStyle={{ opacity: 0.8 }}\n focusStyle={{\n outlineColor: theme.colors.border.brand,\n outlineWidth: 2,\n outlineStyle: \"solid\",\n outlineOffset: 2,\n }}\n >\n <Text\n color={resolvedColor}\n fontSize={typo.fontSize}\n fontWeight={String(fontWeight)}\n textDecoration={underline ? \"underline\" : \"none\"}\n style={{ lineHeight: typo.lineHeight, ...style }}\n >\n {children}\n </Text>\n </Box>\n );\n};\n\nTooltipLink.displayName = \"TooltipLink\";\n"],"mappings":"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","names":["jsx","jsx","jsx","useResolvedTheme","jsx","useResolvedTheme","useResolvedTheme","jsx","useResolvedTheme"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-tooltip",
3
- "version": "0.216.0",
3
+ "version": "0.217.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -13,9 +13,9 @@
13
13
  "test:coverage": "vitest run --coverage"
14
14
  },
15
15
  "dependencies": {
16
- "@xsolla/xui-button": "0.216.0",
17
- "@xsolla/xui-core": "0.216.0",
18
- "@xsolla/xui-primitives-core": "0.216.0"
16
+ "@xsolla/xui-button": "0.217.0",
17
+ "@xsolla/xui-core": "0.217.0",
18
+ "@xsolla/xui-primitives-core": "0.217.0"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "react": ">=16.8.0",
package/web/index.d.mts CHANGED
@@ -1,11 +1,14 @@
1
- import React, { ReactNode } from 'react';
1
+ import * as React from 'react';
2
+ import React__default, { ReactNode } from 'react';
2
3
  import { ThemeOverrideProps } from '@xsolla/xui-core';
3
4
 
4
5
  type TooltipSize = "sm" | "md" | "lg" | "xl";
5
6
  type TooltipPlacement = "top" | "top-left" | "top-right" | "bottom" | "bottom-left" | "bottom-right" | "left" | "right";
6
7
  interface TooltipProps {
7
8
  /**
8
- * The content of the tooltip.
9
+ * The content of the tooltip. Strings and numbers are rendered as themed
10
+ * text; any other node is rendered as-is and inherits the tooltip's
11
+ * typography (see `TooltipText` / `TooltipLink`).
9
12
  */
10
13
  content: ReactNode;
11
14
  /**
@@ -52,7 +55,125 @@ interface TooltipProps {
52
55
  className?: string;
53
56
  testID?: string;
54
57
  }
58
+ /**
59
+ * Typography and colour tokens the tooltip publishes to its content, so nested
60
+ * helpers do not have to re-derive them from the tooltip's `size`.
61
+ */
62
+ interface TooltipContentStyles {
63
+ /** Size of the surrounding tooltip. */
64
+ size: TooltipSize;
65
+ /** Font size for the surrounding tooltip's size, in pixels. */
66
+ fontSize: number;
67
+ /** Line height for the surrounding tooltip's size, as a CSS length. */
68
+ lineHeight: string;
69
+ /** `content/primary` — default colour for tooltip copy. */
70
+ color: string;
71
+ /** `content/brand-primary` — default colour for links inside a tooltip. */
72
+ linkColor: string;
73
+ }
74
+ interface TooltipTextProps {
75
+ children?: ReactNode;
76
+ /**
77
+ * Render with the *accent* (bold) weight of the body token matching the
78
+ * tooltip's size.
79
+ * @default false
80
+ */
81
+ accent?: boolean;
82
+ /**
83
+ * Overrides the size inherited from the surrounding tooltip. Defaults to the
84
+ * tooltip's own `size`, or `"md"` when rendered outside one.
85
+ */
86
+ size?: TooltipSize;
87
+ /** Overrides the inherited text colour. */
88
+ color?: string;
89
+ style?: any;
90
+ "data-testid"?: string;
91
+ testID?: string;
92
+ }
93
+ interface TooltipLinkProps extends TooltipTextProps {
94
+ /** Destination. Omit when driving navigation through `onPress`. */
95
+ href?: string;
96
+ /**
97
+ * Anchor target. `"_blank"` automatically adds `noopener noreferrer` to
98
+ * `rel`.
99
+ */
100
+ target?: string;
101
+ rel?: string;
102
+ /**
103
+ * Click handler. When supplied, the anchor's default navigation is
104
+ * prevented.
105
+ */
106
+ onPress?: () => void;
107
+ /**
108
+ * Underline the link text.
109
+ * @default false
110
+ */
111
+ underline?: boolean;
112
+ }
113
+
114
+ declare const Tooltip: React__default.ForwardRefExoticComponent<TooltipProps & ThemeOverrideProps & React__default.RefAttributes<HTMLDivElement>>;
55
115
 
56
- declare const Tooltip: React.ForwardRefExoticComponent<TooltipProps & ThemeOverrideProps & React.RefAttributes<HTMLDivElement>>;
116
+ /**
117
+ * Text inside a `Tooltip`'s `content`, styled with the tooltip's own size
118
+ * scale and `content/primary` colour.
119
+ *
120
+ * Pass `accent` for bold copy — the weight is read from the body accent token
121
+ * matching the tooltip's size, so it tracks the active product context instead
122
+ * of a hardcoded `700`.
123
+ */
124
+ declare const TooltipText: React__default.FC<TooltipTextProps & ThemeOverrideProps>;
125
+
126
+ /**
127
+ * A link inside a `Tooltip`'s `content`. Uses the `content/brand-primary`
128
+ * token and the tooltip's own size scale, so it sits inline with surrounding
129
+ * `TooltipText` without the caller re-deriving typography.
130
+ *
131
+ * The tooltip surface is hoverable, so the link is reachable with a pointer.
132
+ * It is **not** reachable by keyboard — tabbing away from the trigger blurs it
133
+ * and dismisses the tooltip. When a link must be keyboard-operable, use
134
+ * [Toggletip](../../toggletip) instead.
135
+ */
136
+ declare const TooltipLink: React__default.FC<TooltipLinkProps & ThemeOverrideProps>;
137
+
138
+ /**
139
+ * Publishes the surrounding tooltip's resolved typography and colour tokens to
140
+ * whatever is rendered inside its `content`, so `TooltipText` / `TooltipLink`
141
+ * inherit the tooltip's size without the caller repeating it.
142
+ *
143
+ * `null` when the consumer is rendered outside a `Tooltip` — the helpers then
144
+ * fall back to their own defaults.
145
+ */
146
+ declare const TooltipContentContext: React.Context<TooltipContentStyles | null>;
147
+ declare const useTooltipContentStyles: () => TooltipContentStyles | null;
148
+
149
+ /**
150
+ * Per-size font metrics for tooltip copy. Mirrors the tooltip size matrix in
151
+ * the Figma UI kit (node 5680-32928).
152
+ */
153
+ declare const getTooltipTypoStyles: (size: TooltipSize) => {
154
+ fontSize: number;
155
+ lineHeight: string;
156
+ };
157
+ /** Fallbacks for a resolved theme that predates `typographyTokens`. */
158
+ declare const DEFAULT_BODY_FONT_WEIGHT = 400;
159
+ declare const DEFAULT_ACCENT_FONT_WEIGHT = 500;
160
+ interface TooltipTypographyTokens {
161
+ basic?: Record<string, {
162
+ fontWeight?: number;
163
+ accent?: {
164
+ fontWeight?: number;
165
+ };
166
+ } | undefined>;
167
+ }
168
+ /** The slice of the resolved theme this module reads. */
169
+ interface TooltipThemeTypography {
170
+ typographyTokens?: TooltipTypographyTokens;
171
+ }
172
+ /**
173
+ * Resolves the accent font weight for `size` from the theme's body typography
174
+ * scale, so bold tooltip copy follows the active product context (b2b/b2c use
175
+ * 500, corpsite uses 600) instead of a hardcoded weight.
176
+ */
177
+ declare const getTooltipAccentFontWeight: (typographyTokens: TooltipTypographyTokens | undefined, size: TooltipSize) => number;
57
178
 
58
- export { Tooltip, type TooltipPlacement, type TooltipProps, type TooltipSize };
179
+ export { DEFAULT_ACCENT_FONT_WEIGHT, DEFAULT_BODY_FONT_WEIGHT, Tooltip, TooltipContentContext, type TooltipContentStyles, TooltipLink, type TooltipLinkProps, type TooltipPlacement, type TooltipProps, type TooltipSize, TooltipText, type TooltipTextProps, type TooltipThemeTypography, type TooltipTypographyTokens, getTooltipAccentFontWeight, getTooltipTypoStyles, useTooltipContentStyles };