@xsolla/xui-tag-label 0.218.0 → 0.219.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
@@ -105,23 +105,49 @@ export default function QuickStart() {
105
105
 
106
106
  ### `<TagLabel>`
107
107
 
108
- | Prop | Type | Default | Description |
109
- | --------------- | --------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------- |
110
- | `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
111
- | `entityType` | `"item" \| "product" \| "account"` | — | Primary category. Drives icon and tinted background of the entity segment. |
112
- | `subentityType` | `SubentityType` | — | Detailed sub-category (e.g. `"skin"`, `"game"`, `"sdk"`). Hidden when `compact`. |
113
- | `icon` | `ReactNode` | — | Custom icon override for the entity segment. |
114
- | `series` | `string` | — | ID series prefix (e.g. `"XLA"`). |
115
- | `number` | `string` | — | ID number suffix (e.g. `"-001-001"`). |
116
- | `label` | `string` | — | Item label/name. Hidden when `compact`. |
117
- | `rarity` | `ReactNode` | — | Rarity icon segment. Hidden when `compact`. |
118
- | `status` | `"sale" \| "maintenance" \| "inactive"` | — | Status indicator segment. Hidden when `compact`. |
119
- | `compact` | `boolean` | `false` | Render the icon-only / minimal version. |
120
- | `children` | `ReactNode` | — | Custom trailing-slot content. Hidden when `compact`. |
121
- | `style` | `CSSProperties` | — | Inline style overrides on the root container. |
108
+ | Prop | Type | Default | Description |
109
+ | -------------------- | --------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------- |
110
+ | `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
111
+ | `entityType` | `"item" \| "product" \| "account"` | — | Primary category. Drives icon and tinted background of the entity module. |
112
+ | `showEntityIcon` | `boolean` | `true` | Show the icon of the entity module. |
113
+ | `showEntityLabel` | `boolean` | `!compact` | Show the text label of the entity module. An explicit value wins over `compact`. |
114
+ | `entityIcon` | `ReactNode` | — | Custom icon override for the entity module. |
115
+ | `subentityType` | `SubentityType` | — | Detailed sub-category (e.g. `"skin"`, `"game"`, `"sdk"`). |
116
+ | `showSubentityIcon` | `boolean` | `true` | Show the icon of the subentity module. |
117
+ | `showSubentityLabel` | `boolean` | `!compact` | Show the text label of the subentity module. An explicit value wins over `compact`. |
118
+ | `subentityIcon` | `ReactNode` | — | Custom icon override for the subentity module. |
119
+ | `icon` | `ReactNode` | — | **Deprecated** — alias for `entityIcon`, kept for backwards compatibility. |
120
+ | `series` | `string` | — | ID series prefix (e.g. `"XLA"`). |
121
+ | `number` | `string` | — | ID number suffix (e.g. `"-001-001"`). |
122
+ | `label` | `string` | — | Item label/name. Hidden when `compact`. |
123
+ | `rarity` | `ReactNode` | — | Rarity icon segment. Hidden when `compact`. |
124
+ | `status` | `"sale" \| "maintenance" \| "inactive"` | — | Status indicator segment. Hidden when `compact`. |
125
+ | `compact` | `boolean` | `false` | Render the icon-only / minimal version. Only seeds the defaults of the two `show*Label` flags. |
126
+ | `children` | `ReactNode` | — | Custom trailing-slot content. Hidden when `compact`. |
127
+ | `style` | `CSSProperties` | — | Inline style overrides on the root container. |
122
128
 
123
129
  Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
124
130
 
131
+ ### Module visibility rules
132
+
133
+ The entity and subentity modules mirror the independent `Icon` / `Label` booleans
134
+ on the Figma component sets `.tag-label-entity` and `.tag-label-subentity`, so any
135
+ combination is possible per module:
136
+
137
+ | `show*Icon` | `show*Label` | Rendering |
138
+ | ----------- | ------------ | ---------------------------------------------------------------------------- |
139
+ | `true` | `true` | Full chip: tinted background, icon, text. |
140
+ | `true` | `false` | 24×24 icon-only square (no chip background). |
141
+ | `false` | `true` | Label-only chip: background, padding and typography of the full version. |
142
+ | `false` | `false` | The module is not rendered at all (same as omitting the `*Type` prop). |
143
+
144
+ - `compact` only sets the **defaults** for the two label flags. An explicit
145
+ `showEntityLabel={true}` wins over `compact={true}`.
146
+ - `compact={true}` collapses **both** the entity and the subentity module to
147
+ icon-only. Previously the subentity module was dropped entirely in compact
148
+ view; it now collapses to a 24×24 icon, matching the Figma
149
+ "Compact view = True" variant.
150
+
125
151
  ### Exported types
126
152
 
127
153
  | Type | Members |
@@ -134,8 +160,11 @@ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
134
160
 
135
161
  The tag is composed of optional segments rendered in this order:
136
162
 
137
- 1. **Entity** — coloured background, icon, label.
138
- 2. **Subentity** — secondary categorisation (omitted when `compact`).
163
+ 1. **Entity** — coloured background, icon, label. Icon and label are controlled
164
+ independently via `showEntityIcon` / `showEntityLabel`.
165
+ 2. **Subentity** — secondary categorisation. Icon and label are controlled
166
+ independently via `showSubentityIcon` / `showSubentityLabel`; collapses to an
167
+ icon when `compact`.
139
168
  3. **ID** — series + number.
140
169
  4. **Name** — descriptive text (omitted when `compact`).
141
170
  5. **Rarity** — icon (omitted when `compact`).
@@ -151,7 +180,68 @@ import * as React from "react";
151
180
  import { TagLabel } from "@xsolla/xui-tag-label";
152
181
 
153
182
  export default function CompactTagLabel() {
154
- return <TagLabel entityType="item" series="XLA" number="-001-001" compact />;
183
+ return (
184
+ <TagLabel
185
+ entityType="item"
186
+ subentityType="skin"
187
+ series="XLA"
188
+ number="-001-001"
189
+ compact
190
+ />
191
+ );
192
+ }
193
+ ```
194
+
195
+ ### Per-module icon / label visibility
196
+
197
+ ```tsx
198
+ import * as React from "react";
199
+ import { TagLabel } from "@xsolla/xui-tag-label";
200
+
201
+ export default function ModuleVisibility() {
202
+ return (
203
+ <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
204
+ {/* icon only on both modules */}
205
+ <TagLabel
206
+ entityType="item"
207
+ subentityType="skin"
208
+ showEntityLabel={false}
209
+ showSubentityLabel={false}
210
+ series="XLA"
211
+ number="-001"
212
+ />
213
+
214
+ {/* label only on both modules */}
215
+ <TagLabel
216
+ entityType="item"
217
+ subentityType="skin"
218
+ showEntityIcon={false}
219
+ showSubentityIcon={false}
220
+ series="XLA"
221
+ number="-001"
222
+ />
223
+
224
+ {/* entity module hidden entirely */}
225
+ <TagLabel
226
+ entityType="item"
227
+ showEntityIcon={false}
228
+ showEntityLabel={false}
229
+ subentityType="skin"
230
+ series="XLA"
231
+ number="-001"
232
+ />
233
+
234
+ {/* explicit flag wins over compact */}
235
+ <TagLabel
236
+ entityType="item"
237
+ subentityType="skin"
238
+ compact
239
+ showEntityLabel
240
+ series="XLA"
241
+ number="-001"
242
+ />
243
+ </div>
244
+ );
155
245
  }
156
246
  ```
157
247
 
@@ -191,3 +281,4 @@ export default function TagLabelCustomSlot() {
191
281
 
192
282
  - Provide context around the tag (e.g. a list label or surrounding heading) so screen readers can interpret the categorisation.
193
283
  - The component is decorative; for interactive use, wrap in a button or link with an explicit accessible name.
284
+ - In compact / icon-only configurations the chips carry no text, so the surrounding container must describe the entity — e.g. `aria-label="Item: Skin, ID XLA-001-001"`.
@@ -9,8 +9,43 @@ interface TagLabelProps extends ThemeOverrideProps {
9
9
  entityType?: EntityType;
10
10
  /** Detailed sub-category */
11
11
  subentityType?: SubentityType;
12
- /** Custom icon for entity/subentity if needed */
12
+ /**
13
+ * Custom icon for the entity module.
14
+ *
15
+ * @deprecated Use {@link TagLabelProps.entityIcon} instead. `icon` is kept as
16
+ * an alias for backwards compatibility and will be removed in a future major.
17
+ */
13
18
  icon?: ReactNode;
19
+ /**
20
+ * Show the icon of the entity module.
21
+ *
22
+ * @default true
23
+ */
24
+ showEntityIcon?: boolean;
25
+ /**
26
+ * Show the text label of the entity module. Defaults to `!compact`, so
27
+ * `compact` only seeds the default — an explicit value always wins.
28
+ *
29
+ * @default !compact
30
+ */
31
+ showEntityLabel?: boolean;
32
+ /** Custom icon override for the entity module. Takes precedence over `icon`. */
33
+ entityIcon?: ReactNode;
34
+ /**
35
+ * Show the icon of the subentity module.
36
+ *
37
+ * @default true
38
+ */
39
+ showSubentityIcon?: boolean;
40
+ /**
41
+ * Show the text label of the subentity module. Defaults to `!compact`, so
42
+ * `compact` only seeds the default — an explicit value always wins.
43
+ *
44
+ * @default !compact
45
+ */
46
+ showSubentityLabel?: boolean;
47
+ /** Custom icon override for the subentity module. */
48
+ subentityIcon?: ReactNode;
14
49
  /** ID series (e.g. "XLA") */
15
50
  series?: string;
16
51
  /** ID number (e.g. "-001-001") */
package/native/index.d.ts CHANGED
@@ -9,8 +9,43 @@ interface TagLabelProps extends ThemeOverrideProps {
9
9
  entityType?: EntityType;
10
10
  /** Detailed sub-category */
11
11
  subentityType?: SubentityType;
12
- /** Custom icon for entity/subentity if needed */
12
+ /**
13
+ * Custom icon for the entity module.
14
+ *
15
+ * @deprecated Use {@link TagLabelProps.entityIcon} instead. `icon` is kept as
16
+ * an alias for backwards compatibility and will be removed in a future major.
17
+ */
13
18
  icon?: ReactNode;
19
+ /**
20
+ * Show the icon of the entity module.
21
+ *
22
+ * @default true
23
+ */
24
+ showEntityIcon?: boolean;
25
+ /**
26
+ * Show the text label of the entity module. Defaults to `!compact`, so
27
+ * `compact` only seeds the default — an explicit value always wins.
28
+ *
29
+ * @default !compact
30
+ */
31
+ showEntityLabel?: boolean;
32
+ /** Custom icon override for the entity module. Takes precedence over `icon`. */
33
+ entityIcon?: ReactNode;
34
+ /**
35
+ * Show the icon of the subentity module.
36
+ *
37
+ * @default true
38
+ */
39
+ showSubentityIcon?: boolean;
40
+ /**
41
+ * Show the text label of the subentity module. Defaults to `!compact`, so
42
+ * `compact` only seeds the default — an explicit value always wins.
43
+ *
44
+ * @default !compact
45
+ */
46
+ showSubentityLabel?: boolean;
47
+ /** Custom icon override for the subentity module. */
48
+ subentityIcon?: ReactNode;
14
49
  /** ID series (e.g. "XLA") */
15
50
  series?: string;
16
51
  /** ID number (e.g. "-001-001") */
package/native/index.js CHANGED
@@ -69,6 +69,7 @@ var toGapValue = (gap) => {
69
69
  const asNumber = Number(gap);
70
70
  return Number.isFinite(asNumber) ? asNumber : void 0;
71
71
  };
72
+ var toNativeDisplay = (display) => display === "none" ? "none" : void 0;
72
73
  var Box = ({
73
74
  children,
74
75
  onPress,
@@ -100,6 +101,7 @@ var Box = ({
100
101
  marginBottom,
101
102
  marginLeft,
102
103
  marginRight,
104
+ display,
103
105
  flexDirection,
104
106
  flexWrap,
105
107
  alignItems,
@@ -163,6 +165,7 @@ var Box = ({
163
165
  marginBottom,
164
166
  marginLeft,
165
167
  marginRight,
168
+ display: toNativeDisplay(display),
166
169
  flexDirection,
167
170
  flexWrap,
168
171
  alignItems,
@@ -371,34 +374,9 @@ var import_xui_core = require("@xsolla/xui-core");
371
374
  var import_xui_icons = require("@xsolla/xui-icons");
372
375
  var import_jsx_runtime4 = require("react/jsx-runtime");
373
376
  var SEGMENT_HEIGHT = 24;
374
- var TagLabelEntitySegment = ({ type, compact, icon, theme }) => {
375
- const tagLabel = theme?.colors?.control?.tagLabel;
376
- const colors = tagLabel?.[type];
377
- if (!colors) return null;
378
- const renderIcon = () => {
379
- if (icon) return icon;
380
- switch (type) {
381
- case "item":
382
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
383
- Box,
384
- {
385
- style: { width: 12, height: 12, backgroundColor: colors.text }
386
- }
387
- );
388
- // Cube placeholder
389
- case "product":
390
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
391
- Box,
392
- {
393
- style: { width: 12, height: 12, backgroundColor: colors.text }
394
- }
395
- );
396
- // Chip placeholder
397
- case "account":
398
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_xui_icons.User, { size: "100%" });
399
- }
400
- };
401
- if (compact) {
377
+ var TagLabelModuleChip = ({ showIcon, showLabel, icon, label, colors }) => {
378
+ if (!showIcon && !showLabel) return null;
379
+ if (showIcon && !showLabel) {
402
380
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
403
381
  Box,
404
382
  {
@@ -406,7 +384,7 @@ var TagLabelEntitySegment = ({ type, compact, icon, theme }) => {
406
384
  width: SEGMENT_HEIGHT,
407
385
  alignItems: "center",
408
386
  justifyContent: "center",
409
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { size: 16, color: colors.textCompact || colors.text, children: renderIcon() })
387
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { size: 16, color: colors.textCompact || colors.text, children: icon })
410
388
  }
411
389
  );
412
390
  }
@@ -421,7 +399,7 @@ var TagLabelEntitySegment = ({ type, compact, icon, theme }) => {
421
399
  alignItems: "center",
422
400
  gap: 2,
423
401
  children: [
424
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { size: 20, color: colors.text, children: renderIcon() }),
402
+ showIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { size: 20, color: colors.text, children: icon }),
425
403
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
426
404
  Text,
427
405
  {
@@ -429,18 +407,57 @@ var TagLabelEntitySegment = ({ type, compact, icon, theme }) => {
429
407
  fontSize: 14,
430
408
  fontWeight: "500",
431
409
  whiteSpace: "nowrap",
432
- children: type.charAt(0).toUpperCase() + type.slice(1)
410
+ children: label
433
411
  }
434
412
  )
435
413
  ]
436
414
  }
437
415
  );
438
416
  };
439
- var TagLabelSubentitySegment = ({ type, theme }) => {
417
+ var TagLabelEntitySegment = ({ type, showIcon, showLabel, icon, theme }) => {
418
+ const tagLabel = theme?.colors?.control?.tagLabel;
419
+ const colors = tagLabel?.[type];
420
+ if (!colors) return null;
421
+ const renderIcon = () => {
422
+ if (icon) return icon;
423
+ switch (type) {
424
+ case "item":
425
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
426
+ Box,
427
+ {
428
+ style: { width: 12, height: 12, backgroundColor: colors.text }
429
+ }
430
+ );
431
+ // Cube placeholder
432
+ case "product":
433
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
434
+ Box,
435
+ {
436
+ style: { width: 12, height: 12, backgroundColor: colors.text }
437
+ }
438
+ );
439
+ // Chip placeholder
440
+ case "account":
441
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_xui_icons.User, { size: "100%" });
442
+ }
443
+ };
444
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
445
+ TagLabelModuleChip,
446
+ {
447
+ showIcon,
448
+ showLabel,
449
+ icon: renderIcon(),
450
+ label: type.charAt(0).toUpperCase() + type.slice(1),
451
+ colors
452
+ }
453
+ );
454
+ };
455
+ var TagLabelSubentitySegment = ({ type, showIcon, showLabel, icon, theme }) => {
440
456
  const tagLabel = theme?.colors?.control?.tagLabel;
441
457
  const colors = tagLabel?.subentity;
442
458
  if (!colors || !type || typeof type !== "string") return null;
443
459
  const renderIcon = () => {
460
+ if (icon) return icon;
444
461
  switch (type) {
445
462
  case "skin":
446
463
  case "in-game-item":
@@ -469,29 +486,14 @@ var TagLabelSubentitySegment = ({ type, theme }) => {
469
486
  }
470
487
  };
471
488
  const label = type.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
472
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
473
- Box,
489
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
490
+ TagLabelModuleChip,
474
491
  {
475
- height: SEGMENT_HEIGHT,
476
- backgroundColor: colors.bg,
477
- paddingLeft: 2,
478
- paddingRight: 4,
479
- flexDirection: "row",
480
- alignItems: "center",
481
- gap: 2,
482
- children: [
483
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { size: 20, color: colors.text, children: renderIcon() }),
484
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
485
- Text,
486
- {
487
- color: colors.text,
488
- fontSize: 14,
489
- fontWeight: "500",
490
- whiteSpace: "nowrap",
491
- children: label
492
- }
493
- )
494
- ]
492
+ showIcon,
493
+ showLabel,
494
+ icon: renderIcon(),
495
+ label,
496
+ colors
495
497
  }
496
498
  );
497
499
  };
@@ -655,6 +657,12 @@ var TagLabel = ({
655
657
  entityType,
656
658
  subentityType,
657
659
  icon,
660
+ entityIcon,
661
+ showEntityIcon = true,
662
+ showEntityLabel,
663
+ subentityIcon,
664
+ showSubentityIcon = true,
665
+ showSubentityLabel,
658
666
  series,
659
667
  number,
660
668
  label,
@@ -668,6 +676,11 @@ var TagLabel = ({
668
676
  themeProductContext
669
677
  }) => {
670
678
  const { theme } = (0, import_xui_core.useResolvedTheme)({ themeMode, themeProductContext });
679
+ const entityLabelVisible = showEntityLabel ?? !compact;
680
+ const subentityLabelVisible = showSubentityLabel ?? !compact;
681
+ const resolvedEntityIcon = entityIcon ?? icon;
682
+ const renderEntity = Boolean(entityType) && (showEntityIcon || entityLabelVisible);
683
+ const renderSubentity = Boolean(subentityType) && (showSubentityIcon || subentityLabelVisible);
671
684
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
672
685
  Box,
673
686
  {
@@ -680,16 +693,26 @@ var TagLabel = ({
680
693
  ...style
681
694
  },
682
695
  children: [
683
- entityType && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
696
+ renderEntity && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
684
697
  TagLabelEntitySegment,
685
698
  {
686
699
  type: entityType,
687
- compact,
688
- icon,
700
+ showIcon: showEntityIcon,
701
+ showLabel: entityLabelVisible,
702
+ icon: resolvedEntityIcon,
703
+ theme
704
+ }
705
+ ),
706
+ renderSubentity && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
707
+ TagLabelSubentitySegment,
708
+ {
709
+ type: subentityType,
710
+ showIcon: showSubentityIcon,
711
+ showLabel: subentityLabelVisible,
712
+ icon: subentityIcon,
689
713
  theme
690
714
  }
691
715
  ),
692
- !compact && subentityType && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TagLabelSubentitySegment, { type: subentityType, theme }),
693
716
  (series || number) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
694
717
  TagLabelIdSegment,
695
718
  {