@xsolla/xui-tooltip 0.216.1 → 0.218.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/README.md CHANGED
@@ -55,7 +55,11 @@ npm install @xsolla/xui-tooltip
55
55
  ```tsx
56
56
  import {
57
57
  Tooltip,
58
+ TooltipText,
59
+ TooltipLink,
58
60
  type TooltipProps,
61
+ type TooltipTextProps,
62
+ type TooltipLinkProps,
59
63
  type TooltipPlacement,
60
64
  type TooltipSize,
61
65
  } from "@xsolla/xui-tooltip";
@@ -83,7 +87,7 @@ export default function Example() {
83
87
 
84
88
  | Prop | Type | Default | Description |
85
89
  | ------------------- | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------- |
86
- | `content` | `ReactNode` | — | **Required.** Tooltip content. Strings/numbers render as themed text; `\n` in a string is preserved as a line break (`white-space: pre-line`) while long lines still wrap normally. |
90
+ | `content` | `ReactNode` | — | **Required.** Tooltip content. Strings/numbers render as themed text; `\n` in a string is preserved as a line break (`white-space: pre-line`) while long lines still wrap normally. Any other node renders as-is and inherits the tooltip's type scale — see [Rich content](#rich-content). |
87
91
  | `children` | `ReactNode` | — | **Required.** Trigger element. |
88
92
  | `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` | Typography size. |
89
93
  | `placement` | `TooltipPlacement` | `"top"` | Position relative to trigger. |
@@ -108,14 +112,47 @@ than 34px cannot fit the arrow's 17px inset from that edge, so the tooltip slide
108
112
  out by the shortfall to keep the arrow on the trigger's centre; icon-sized
109
113
  triggers stay correctly aimed.
110
114
 
115
+ ### `<TooltipText>`
116
+
117
+ Text inside a tooltip's `content`, styled with the surrounding tooltip's size scale.
118
+
119
+ | Prop | Type | Default | Description |
120
+ | ------------- | ------------------------------ | ----------- | --------------------------------------------------------------------------------------------------- |
121
+ | `children` | `ReactNode` | — | Copy to render. |
122
+ | `accent` | `boolean` | `false` | Render with the **accent** (bold) weight of the body token matching the tooltip's size. |
123
+ | `size` | `"sm" \| "md" \| "lg" \| "xl"` | *inherited* | Overrides the size taken from the surrounding tooltip. Falls back to `"md"` when used outside one. |
124
+ | `color` | `string` | *inherited* | Overrides the inherited `content/primary` colour. |
125
+ | `style` | `CSSProperties` | — | Merged into the rendered text's inline styles. |
126
+ | `data-testid` | `string` | — | Test identifier. |
127
+ | `testID` | `string` | — | Test ID for testing frameworks. |
128
+
129
+ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
130
+
131
+ ### `<TooltipLink>`
132
+
133
+ A link inside a tooltip's `content`, using the `content/brand-primary` token. Accepts every `TooltipText` prop plus:
134
+
135
+ | Prop | Type | Default | Description |
136
+ | ----------- | ------------ | ------- | ----------------------------------------------------------------------------- |
137
+ | `href` | `string` | — | Destination. Omit when navigation is driven by `onPress`. |
138
+ | `target` | `string` | — | Anchor target. `"_blank"` automatically adds `noopener noreferrer` to `rel`. |
139
+ | `rel` | `string` | — | Extra `rel` tokens, merged with the `_blank` hardening above. |
140
+ | `onPress` | `() => void` | — | Click handler. When supplied, the anchor's default navigation is prevented. |
141
+ | `underline` | `boolean` | `false` | Underline the link text. |
142
+
111
143
  ### Size typography
112
144
 
113
- | Size | Font size | Line height |
114
- | ---- | --------- | ----------- |
115
- | `sm` | 14px | 16px |
116
- | `md` | 16px | 18px |
117
- | `lg` | 18px | 20px |
118
- | `xl` | 20px | 22px |
145
+ | Size | Font size | Line height | Body token for `accent` |
146
+ | ---- | --------- | ----------- | ----------------------- |
147
+ | `sm` | 14px | 16px | `body-sm` |
148
+ | `md` | 16px | 18px | `body-md` |
149
+ | `lg` | 18px | 20px | `body-lg` |
150
+ | `xl` | 20px | 22px | `body-lg` |
151
+
152
+ `accent` resolves its weight from the body token in the right-hand column, so
153
+ bold tooltip copy follows the active product context (500 for b2b/b2c, 600 for
154
+ corpsite) instead of a fixed weight. `xl` reuses `body-lg` because the body
155
+ scale tops out at 18px.
119
156
 
120
157
  ## Examples
121
158
 
@@ -237,9 +274,43 @@ export default function Multiline() {
237
274
 
238
275
  ### Rich content
239
276
 
277
+ `content` is not restricted to a string — pass any node. The tooltip publishes
278
+ its resolved type scale and colour tokens to whatever it renders, so
279
+ `TooltipText` and `TooltipLink` pick up the tooltip's `size` without repeating
280
+ it, and bare markup inherits the same font size, line height and colour.
281
+
240
282
  ```tsx
241
283
  import * as React from "react";
242
- import { Tooltip } from "@xsolla/xui-tooltip";
284
+ import { Tooltip, TooltipText, TooltipLink } from "@xsolla/xui-tooltip";
285
+ import { Button } from "@xsolla/xui-button";
286
+
287
+ export default function RichContent() {
288
+ return (
289
+ <Tooltip
290
+ size="md"
291
+ maxWidth={280}
292
+ content={
293
+ <>
294
+ <TooltipText accent>Payout schedule</TooltipText>
295
+ <TooltipText>{" is set per project. "}</TooltipText>
296
+ <TooltipLink href="https://developers.xsolla.com" target="_blank">
297
+ Read the docs
298
+ </TooltipLink>
299
+ </>
300
+ }
301
+ >
302
+ <Button variant="secondary">Hover me</Button>
303
+ </Tooltip>
304
+ );
305
+ }
306
+ ```
307
+
308
+ Any component composes the same way — the tooltip is a wrapper around its
309
+ content, not a text-only surface:
310
+
311
+ ```tsx
312
+ import * as React from "react";
313
+ import { Tooltip, TooltipText } from "@xsolla/xui-tooltip";
243
314
  import { Avatar } from "@xsolla/xui-avatar";
244
315
 
245
316
  export default function Rich() {
@@ -247,9 +318,9 @@ export default function Rich() {
247
318
  <Tooltip
248
319
  content={
249
320
  <div style={{ textAlign: "center" }}>
250
- <strong>John Doe</strong>
321
+ <TooltipText accent>John Doe</TooltipText>
251
322
  <br />
252
- <span style={{ opacity: 0.7 }}>Senior Developer</span>
323
+ <TooltipText style={{ opacity: 0.7 }}>Senior Developer</TooltipText>
253
324
  </div>
254
325
  }
255
326
  >
@@ -329,18 +400,21 @@ export default function DisabledTrigger() {
329
400
 
330
401
  - **Hover bridge.** Moving the cursor from the trigger onto the tooltip keeps it visible — the tooltip surface is hoverable and a short `delayLeave` grace period (default 100ms) bridges the gap between trigger and tooltip, so the tooltip no longer flickers or disappears when the cursor moves toward it. The tooltip hides once the cursor leaves *both* the trigger and the tooltip.
331
402
  - **Multiline content.** String/number `content` renders with `white-space: pre-line`, so `\n` characters are preserved as line breaks while long lines continue to wrap.
403
+ - **Content inheritance.** Non-string `content` is rendered inside a wrapper carrying the tooltip's font size, line height and `content/primary` colour, so nested markup does not have to restate them.
332
404
 
333
405
  ## Theme
334
406
 
335
407
  - The tooltip is a floating surface: both the panel and its arrow use the `layer/float` colour token (`theme.colors.layer.float`), not a page-level `background/*` token, so the tooltip stays visibly lifted off the page in light and dark mode.
336
408
  - Label colour comes from `theme.colors.content.primary`; corner radius comes from `theme.shape.tooltip[size]`.
409
+ - `TooltipLink` uses `theme.colors.content.brand.primary`, and its focus ring uses `theme.colors.border.brand`.
410
+ - `TooltipText accent` resolves its weight from `theme.typographyTokens.basic[<body token>].accent.fontWeight` — see [Size typography](#size-typography).
337
411
 
338
412
  ## Accessibility
339
413
 
340
414
  - Tooltip surface uses `role="tooltip"` and `aria-hidden` reflects visibility.
341
415
  - Trigger receives `aria-describedby` while the tooltip is visible.
342
416
  - Press Escape to dismiss.
343
- - Tooltip content is non-interactive — for interactive content (links, buttons), prefer [Toggletip](./toggletip.md). The tooltip surface is hoverable only so the pointer can rest on it without flicker.
417
+ - **`TooltipLink` is pointer-reachable only.** The tooltip surface is hoverable, so a link inside it can be clicked with a mouse — but tabbing away from the trigger blurs it and dismisses the tooltip, so the link cannot be reached by keyboard. Use [Toggletip](./toggletip.md) whenever the link is essential or must be keyboard-operable; reserve `TooltipLink` for supplementary "read more" affordances that are also available elsewhere in the UI.
344
418
 
345
419
  ## Related
346
420
 
@@ -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 };
package/native/index.d.ts 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 };