@xsolla/xui-tag 0.222.0 → 0.223.1
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 +60 -50
- package/native/index.d.mts +47 -2
- package/native/index.d.ts +47 -2
- package/native/index.js +368 -8
- package/native/index.js.map +1 -1
- package/native/index.mjs +373 -6
- package/native/index.mjs.map +1 -1
- package/package.json +8 -5
- package/web/index.d.mts +47 -2
- package/web/index.d.ts +47 -2
- package/web/index.js +366 -8
- package/web/index.js.map +1 -1
- package/web/index.mjs +371 -6
- package/web/index.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Tag
|
|
2
2
|
|
|
3
|
-
A cross-platform React tag component for displaying labels, categories, and removable chips. Supports multiple tones, solid/outlined types, and optional left/right icons.
|
|
3
|
+
A cross-platform React tag component for displaying labels, categories, and removable chips. Supports multiple tones, solid/outlined types, and optional left/right icons. The package also ships `TagInput`, a text field that turns typed values into removable chips.
|
|
4
4
|
<!-- BEGIN:xui-mcp-instructions:tag -->
|
|
5
5
|
A compact label chip used to categorise, classify, or annotate content. Renders as a pill-shaped container with a text label and optional leading and trailing icons. Supports two visual types (solid fill and outlined), seven semantic tones, and five sizes. Used in lists, cards, table cells, filters, and any context where a short categorical attribute needs to be visually marked.
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ A compact label chip used to categorise, classify, or annotate content. Renders
|
|
|
36
36
|
- Do not rely on Tone (colour) alone to communicate meaning — the label text or icon must also be present (WCAG 1.4.1 Use of Colour). For icon-only tags, provide aria-label on the element.
|
|
37
37
|
- Removable tags: the remove button (Icon right) must have aria-label=*"Remove [tag name]"* so screen readers can announce which tag is being removed. The button must be focusable and respond to Enter / Space.
|
|
38
38
|
- When tags are inside a list, wrap them in a <ul> with <li> elements and an aria-label on the list describing the group — e.g. aria-label=*"Product tags"*.
|
|
39
|
-
- Ensure sufficient colour contrast between the tag label text and the tag background in both Solid and Outlined variants, for all tones, meeting WCAG AA (4.5:1 for small text at XS/S sizes)
|
|
39
|
+
- Ensure sufficient colour contrast between the tag label text and the tag background in both Solid and Outlined variants, for all tones, meeting WCAG AA (4.5:1 for small text at XS/S sizes).
|
|
40
40
|
<!-- END:xui-mcp-instructions:tag -->
|
|
41
41
|
|
|
42
42
|
## Installation
|
|
@@ -208,7 +208,8 @@ import { Tag } from "@xsolla/xui-tag";
|
|
|
208
208
|
type="solid" // Solid or outlined
|
|
209
209
|
iconLeft={<Icon />} // Optional leading icon
|
|
210
210
|
iconRight={<Icon />} // Optional trailing icon
|
|
211
|
-
onRemove={handleRemove} // Makes tag removable (renders X
|
|
211
|
+
onRemove={handleRemove} // Makes tag removable (renders an X button)
|
|
212
|
+
removeLabel="Remove brand" // Optional accessible name for the X button
|
|
212
213
|
>
|
|
213
214
|
Tag Label
|
|
214
215
|
</Tag>;
|
|
@@ -268,48 +269,33 @@ export default function StatusTags() {
|
|
|
268
269
|
|
|
269
270
|
### Tag Input
|
|
270
271
|
|
|
272
|
+
Use `TagInput` to let users type free-form values that become removable chips inside the field. Chips wrap onto new lines as the list grows.
|
|
273
|
+
|
|
271
274
|
```tsx
|
|
272
275
|
import * as React from "react";
|
|
273
|
-
import {
|
|
274
|
-
import { Input } from "@xsolla/xui-input";
|
|
276
|
+
import { TagInput } from "@xsolla/xui-tag";
|
|
275
277
|
|
|
276
|
-
export default function
|
|
277
|
-
const [
|
|
278
|
-
const [inputValue, setInputValue] = React.useState("");
|
|
279
|
-
|
|
280
|
-
const addTag = () => {
|
|
281
|
-
if (inputValue.trim() && !tags.includes(inputValue.trim())) {
|
|
282
|
-
setTags([...tags, inputValue.trim()]);
|
|
283
|
-
setInputValue("");
|
|
284
|
-
}
|
|
285
|
-
};
|
|
278
|
+
export default function ItemIdsField() {
|
|
279
|
+
const [ids, setIds] = React.useState<string[]>([]);
|
|
286
280
|
|
|
287
281
|
return (
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
key={tag}
|
|
295
|
-
tone="primary"
|
|
296
|
-
onRemove={() => setTags(tags.filter((t) => t !== tag))}
|
|
297
|
-
>
|
|
298
|
-
{tag}
|
|
299
|
-
</Tag>
|
|
300
|
-
))}
|
|
301
|
-
</div>
|
|
302
|
-
<Input
|
|
303
|
-
value={inputValue}
|
|
304
|
-
onChangeText={setInputValue}
|
|
305
|
-
placeholder="Add a tag..."
|
|
306
|
-
onKeyDown={(e) => e.key === "Enter" && addTag()}
|
|
307
|
-
/>
|
|
308
|
-
</div>
|
|
282
|
+
<TagInput
|
|
283
|
+
label="Epic Audience Item IDs"
|
|
284
|
+
value={ids}
|
|
285
|
+
onChange={setIds}
|
|
286
|
+
placeholder="Type an ID and press Enter"
|
|
287
|
+
/>
|
|
309
288
|
);
|
|
310
289
|
}
|
|
311
290
|
```
|
|
312
291
|
|
|
292
|
+
Behaviour:
|
|
293
|
+
|
|
294
|
+
- **Enter** adds the typed text as a chip and does not submit the surrounding form. While an input method (IME) is composing, Enter confirms the composition instead.
|
|
295
|
+
- **Leaving the field** adds the typed text too.
|
|
296
|
+
- **Backspace** in an empty field removes the last chip.
|
|
297
|
+
- Values are kept as typed — no trimming and no de-duplication. Empty input is ignored.
|
|
298
|
+
|
|
313
299
|
## API Reference
|
|
314
300
|
|
|
315
301
|
### Tag
|
|
@@ -318,16 +304,17 @@ A tag/chip component.
|
|
|
318
304
|
|
|
319
305
|
**Tag Props:**
|
|
320
306
|
|
|
321
|
-
| Prop
|
|
322
|
-
|
|
|
323
|
-
| `testID`
|
|
324
|
-
| children
|
|
325
|
-
| size
|
|
326
|
-
| tone
|
|
327
|
-
| type
|
|
328
|
-
| iconLeft
|
|
329
|
-
| iconRight
|
|
330
|
-
| onRemove
|
|
307
|
+
| Prop | Type | Default | Description |
|
|
308
|
+
| :---------- | :--------------------------------------------------------------------------------------- | :---------- | :------------------------------------------------------------------------------------------------------------ |
|
|
309
|
+
| `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
|
|
310
|
+
| children | `ReactNode` | - | Tag content. Optional for icon-only tags. |
|
|
311
|
+
| size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"md"` | Size of the tag. |
|
|
312
|
+
| tone | `"primary" \| "brand" \| "brandExtra" \| "success" \| "warning" \| "alert" \| "neutral"` | `"primary"` | Color tone. |
|
|
313
|
+
| type | `"solid" \| "outlined"` | `"solid"` | Visual type. Solid fills background; outlined uses a border with lighter background. |
|
|
314
|
+
| iconLeft | `ReactNode` | - | Leading icon. |
|
|
315
|
+
| iconRight | `ReactNode` | - | Trailing icon. |
|
|
316
|
+
| onRemove | `() => void` | - | Callback for the remove button. Renders an X button in the trailing position. |
|
|
317
|
+
| removeLabel | `string` | - | Accessible name of the remove button. Defaults to `"Remove {children}"` for text labels, otherwise `"Remove"`. |
|
|
331
318
|
|
|
332
319
|
**Solid Tone Color Mapping:**
|
|
333
320
|
|
|
@@ -353,9 +340,32 @@ A tag/chip component.
|
|
|
353
340
|
| alert | Alert secondary | Border alert | Content alert primary |
|
|
354
341
|
| neutral | Neutral secondary | Border neutral | Content neutral primary |
|
|
355
342
|
|
|
343
|
+
### TagInput
|
|
344
|
+
|
|
345
|
+
A controlled text field that turns typed values into removable chips. The ref is forwarded to the text field.
|
|
346
|
+
|
|
347
|
+
**TagInput Props:**
|
|
348
|
+
|
|
349
|
+
| Prop | Type | Default | Description |
|
|
350
|
+
| :------------- | :------------------------------------- | :------ | :-------------------------------------------------------------------------- |
|
|
351
|
+
| value | `string[]` | — | Current list of chip values. Required. |
|
|
352
|
+
| onChange | `(value: string[]) => void` | — | Called with the next list when a chip is added or removed. Required. |
|
|
353
|
+
| placeholder | `string` | - | Placeholder shown while there are no chips. |
|
|
354
|
+
| size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"md"` | Size of the field, matching `Input`. Chips are sized to fit inside it. |
|
|
355
|
+
| disabled | `boolean` | `false` | Disables typing and hides the chip remove buttons. |
|
|
356
|
+
| error | `boolean` | - | Highlights the field as invalid. |
|
|
357
|
+
| errorMessage | `string` | - | Error text below the field. Also highlights the field as invalid. |
|
|
358
|
+
| label | `string` | - | Visible label above the field. |
|
|
359
|
+
| `aria-label` | `string` | - | Accessible name for the text field when no `label` is set. |
|
|
360
|
+
| id | `string` | - | Id of the text field. Generated when omitted. |
|
|
361
|
+
| name | `string` | - | Name of the text field. |
|
|
362
|
+
| onFocus | `() => void` | - | Called when the text field receives focus. |
|
|
363
|
+
| onBlur | `() => void` | - | Called when the text field loses focus, after any typed text is committed. |
|
|
364
|
+
| `testID` | `string` | - | Test ID on the root element. |
|
|
365
|
+
|
|
356
366
|
## Accessibility
|
|
357
367
|
|
|
358
|
-
-
|
|
359
|
-
-
|
|
360
|
-
-
|
|
361
|
-
-
|
|
368
|
+
- The remove control is a native `<button type="button">`: it is reachable with Tab, activates on Enter / Space, and is announced as "Remove {label}" (override with `removeLabel`)
|
|
369
|
+
- `TagInput` links its visible label via `aria-labelledby`, falls back to `aria-label`, and links `errorMessage` via `aria-describedby` with `aria-invalid`
|
|
370
|
+
- `TagInput` chips use the same accessible remove button, labelled "Remove {value}"
|
|
371
|
+
- Enter does not add a chip while an input method (IME) is composing
|
package/native/index.d.mts
CHANGED
|
@@ -14,12 +14,57 @@ interface TagProps extends ThemeOverrideProps {
|
|
|
14
14
|
iconLeft?: ReactNode;
|
|
15
15
|
/** Icon displayed on the right side of the label */
|
|
16
16
|
iconRight?: ReactNode;
|
|
17
|
-
/** Callback when the remove (X)
|
|
17
|
+
/** Callback when the remove (X) button is pressed */
|
|
18
18
|
onRemove?: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Accessible name of the remove button. Defaults to "Remove {children}" when
|
|
21
|
+
* `children` is a string or number, otherwise "Remove".
|
|
22
|
+
*/
|
|
23
|
+
removeLabel?: string;
|
|
19
24
|
testID?: string;
|
|
20
25
|
/** Extra styles merged onto the chip. Used for fills the tone tokens do not cover. */
|
|
21
26
|
style?: React.CSSProperties;
|
|
22
27
|
}
|
|
23
28
|
declare const Tag: React.FC<TagProps>;
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
type TagInputSize = "xl" | "lg" | "md" | "sm" | "xs";
|
|
31
|
+
interface TagInputProps extends ThemeOverrideProps {
|
|
32
|
+
/** Current list of chip values (controlled). */
|
|
33
|
+
value: string[];
|
|
34
|
+
/** Called with the next list whenever a chip is added or removed. */
|
|
35
|
+
onChange: (value: string[]) => void;
|
|
36
|
+
/** Placeholder shown in the text field while no draft text is typed. */
|
|
37
|
+
placeholder?: string;
|
|
38
|
+
/** Size of the field. Chips are sized to fit inside it. */
|
|
39
|
+
size?: TagInputSize;
|
|
40
|
+
/** Disables typing and chip removal. */
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
/** Highlights the field as invalid. */
|
|
43
|
+
error?: boolean;
|
|
44
|
+
/** Error message rendered below the field. Also highlights the field as invalid. */
|
|
45
|
+
errorMessage?: string;
|
|
46
|
+
/** Visible label rendered above the field. */
|
|
47
|
+
label?: string;
|
|
48
|
+
/** Accessible label for the text field when no visible `label` is set. */
|
|
49
|
+
"aria-label"?: string;
|
|
50
|
+
/** Id of the text field. Generated when omitted. */
|
|
51
|
+
id?: string;
|
|
52
|
+
/** Name of the text field. */
|
|
53
|
+
name?: string;
|
|
54
|
+
/** Called when the text field receives focus. */
|
|
55
|
+
onFocus?: () => void;
|
|
56
|
+
/** Called when the text field loses focus (after any draft is committed). */
|
|
57
|
+
onBlur?: () => void;
|
|
58
|
+
testID?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Text field that turns typed values into removable chips.
|
|
62
|
+
*
|
|
63
|
+
* - Enter adds the typed text as a chip and never submits the surrounding form.
|
|
64
|
+
* - Leaving the field adds the typed text too.
|
|
65
|
+
* - Backspace in an empty field removes the last chip.
|
|
66
|
+
* - Values are kept as typed: no trimming and no de-duplication.
|
|
67
|
+
*/
|
|
68
|
+
declare const TagInput: React.ForwardRefExoticComponent<TagInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
69
|
+
|
|
70
|
+
export { Tag, TagInput, type TagInputProps, type TagProps };
|
package/native/index.d.ts
CHANGED
|
@@ -14,12 +14,57 @@ interface TagProps extends ThemeOverrideProps {
|
|
|
14
14
|
iconLeft?: ReactNode;
|
|
15
15
|
/** Icon displayed on the right side of the label */
|
|
16
16
|
iconRight?: ReactNode;
|
|
17
|
-
/** Callback when the remove (X)
|
|
17
|
+
/** Callback when the remove (X) button is pressed */
|
|
18
18
|
onRemove?: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Accessible name of the remove button. Defaults to "Remove {children}" when
|
|
21
|
+
* `children` is a string or number, otherwise "Remove".
|
|
22
|
+
*/
|
|
23
|
+
removeLabel?: string;
|
|
19
24
|
testID?: string;
|
|
20
25
|
/** Extra styles merged onto the chip. Used for fills the tone tokens do not cover. */
|
|
21
26
|
style?: React.CSSProperties;
|
|
22
27
|
}
|
|
23
28
|
declare const Tag: React.FC<TagProps>;
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
type TagInputSize = "xl" | "lg" | "md" | "sm" | "xs";
|
|
31
|
+
interface TagInputProps extends ThemeOverrideProps {
|
|
32
|
+
/** Current list of chip values (controlled). */
|
|
33
|
+
value: string[];
|
|
34
|
+
/** Called with the next list whenever a chip is added or removed. */
|
|
35
|
+
onChange: (value: string[]) => void;
|
|
36
|
+
/** Placeholder shown in the text field while no draft text is typed. */
|
|
37
|
+
placeholder?: string;
|
|
38
|
+
/** Size of the field. Chips are sized to fit inside it. */
|
|
39
|
+
size?: TagInputSize;
|
|
40
|
+
/** Disables typing and chip removal. */
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
/** Highlights the field as invalid. */
|
|
43
|
+
error?: boolean;
|
|
44
|
+
/** Error message rendered below the field. Also highlights the field as invalid. */
|
|
45
|
+
errorMessage?: string;
|
|
46
|
+
/** Visible label rendered above the field. */
|
|
47
|
+
label?: string;
|
|
48
|
+
/** Accessible label for the text field when no visible `label` is set. */
|
|
49
|
+
"aria-label"?: string;
|
|
50
|
+
/** Id of the text field. Generated when omitted. */
|
|
51
|
+
id?: string;
|
|
52
|
+
/** Name of the text field. */
|
|
53
|
+
name?: string;
|
|
54
|
+
/** Called when the text field receives focus. */
|
|
55
|
+
onFocus?: () => void;
|
|
56
|
+
/** Called when the text field loses focus (after any draft is committed). */
|
|
57
|
+
onBlur?: () => void;
|
|
58
|
+
testID?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Text field that turns typed values into removable chips.
|
|
62
|
+
*
|
|
63
|
+
* - Enter adds the typed text as a chip and never submits the surrounding form.
|
|
64
|
+
* - Leaving the field adds the typed text too.
|
|
65
|
+
* - Backspace in an empty field removes the last chip.
|
|
66
|
+
* - Values are kept as typed: no trimming and no de-duplication.
|
|
67
|
+
*/
|
|
68
|
+
declare const TagInput: React.ForwardRefExoticComponent<TagInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
69
|
+
|
|
70
|
+
export { Tag, TagInput, type TagInputProps, type TagProps };
|