@xsolla/xui-multi-select 0.158.0 → 0.159.0-pr290.1779453807
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 +47 -44
- package/native/index.d.mts +2 -0
- package/native/index.d.ts +2 -0
- package/native/index.js +37 -10
- package/native/index.js.map +1 -1
- package/native/index.mjs +37 -10
- package/native/index.mjs.map +1 -1
- package/package.json +5 -5
- package/web/index.d.mts +2 -0
- package/web/index.d.ts +2 -0
- package/web/index.js +37 -10
- package/web/index.js.map +1 -1
- package/web/index.mjs +37 -10
- package/web/index.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npm install @xsolla/xui-multi-select
|
|
|
11
11
|
## Imports
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
|
-
import { MultiSelect } from
|
|
14
|
+
import { MultiSelect } from "@xsolla/xui-multi-select";
|
|
15
15
|
import type {
|
|
16
16
|
MultiSelectProps,
|
|
17
17
|
MultiSelectOption,
|
|
@@ -19,16 +19,16 @@ import type {
|
|
|
19
19
|
MultiSelectVariant,
|
|
20
20
|
MultiSelectSize,
|
|
21
21
|
MultiSelectState,
|
|
22
|
-
} from
|
|
22
|
+
} from "@xsolla/xui-multi-select";
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Quick start
|
|
26
26
|
|
|
27
27
|
```tsx
|
|
28
28
|
const options = [
|
|
29
|
-
{ label:
|
|
30
|
-
{ label:
|
|
31
|
-
{ label:
|
|
29
|
+
{ label: "React", value: "react" },
|
|
30
|
+
{ label: "Vue", value: "vue" },
|
|
31
|
+
{ label: "Angular", value: "angular" },
|
|
32
32
|
];
|
|
33
33
|
|
|
34
34
|
const [selected, setSelected] = useState<MultiSelectValue>([]);
|
|
@@ -47,15 +47,17 @@ const [selected, setSelected] = useState<MultiSelectValue>([]);
|
|
|
47
47
|
When the option list is rendered elsewhere (for example [`@xsolla/xui-b2b-group-select`](./b2b-group-select.md)), set **`dropdownMenu={false}`** so the control does not open the built-in list. Wire the same **`value`** / **`onChange`** to both components; use **`onTriggerPress`** to toggle your panel, **`menuOpen`** for chevron/open styling, and **`menuMinWidth`** (default **540**, aligned with `GROUP_SELECT_MIN_PANEL_WIDTH`) so the field matches the panel width.
|
|
48
48
|
|
|
49
49
|
```tsx
|
|
50
|
-
import * as React from
|
|
51
|
-
import { MultiSelect } from
|
|
50
|
+
import * as React from "react";
|
|
51
|
+
import { MultiSelect } from "@xsolla/xui-multi-select";
|
|
52
52
|
import {
|
|
53
53
|
GroupSelect,
|
|
54
54
|
GROUP_SELECT_MIN_PANEL_WIDTH,
|
|
55
55
|
type GroupSelectGroup,
|
|
56
|
-
} from
|
|
56
|
+
} from "@xsolla/xui-b2b-group-select";
|
|
57
57
|
|
|
58
|
-
const groups: GroupSelectGroup[] = [
|
|
58
|
+
const groups: GroupSelectGroup[] = [
|
|
59
|
+
/* ... */
|
|
60
|
+
];
|
|
59
61
|
const flatOptions = groups.flatMap((g) =>
|
|
60
62
|
g.items.map((it) => ({ value: it.id, label: it.label }))
|
|
61
63
|
);
|
|
@@ -91,28 +93,29 @@ Add backdrop, click-outside, and Escape handling in your layout as needed (see S
|
|
|
91
93
|
|
|
92
94
|
### `<MultiSelect>`
|
|
93
95
|
|
|
94
|
-
| Prop
|
|
95
|
-
|
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
96
|
+
| Prop | Type | Default | Description |
|
|
97
|
+
| ------------------- | --------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
98
|
+
| `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
|
|
99
|
+
| `options` | `MultiSelectOption[]` | — | Available options. |
|
|
100
|
+
| `value` | `MultiSelectValue` | `[]` | Selected values. |
|
|
101
|
+
| `onChange` | `(values: MultiSelectValue) => void` | — | Fired when the selection changes. |
|
|
102
|
+
| `placeholder` | `string` | `'Select'` | Placeholder shown when empty. |
|
|
103
|
+
| `label` | `string` | — | Label rendered above the control. |
|
|
104
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Control size. |
|
|
105
|
+
| `state` | `'default' \| 'hover' \| 'focus' \| 'disable' \| 'error'` | — | Forced visual state. |
|
|
106
|
+
| `disabled` | `boolean` | `false` | Disable the control. |
|
|
107
|
+
| `errorMessage` | `string` | — | Error message; also marks the control invalid. |
|
|
108
|
+
| `variant` | `'tag' \| 'text'` | `'tag'` | How selected options are displayed. |
|
|
109
|
+
| `flexible` | `boolean` | `true` | When `true` the control grows with content; otherwise fixed-height. |
|
|
110
|
+
| `removeTagsButtons` | `boolean` | `true` | Show a remove button on each tag. |
|
|
111
|
+
| `extraClear` | `boolean` | `false` | Show a clear-all button. |
|
|
112
|
+
| `maxHeight` | `number` | `300` | Maximum dropdown height in pixels. |
|
|
113
|
+
| `iconLeft` | `ReactNode` | — | Icon rendered on the left of the control. |
|
|
114
|
+
| `iconRight` | `ReactNode` | — | Icon on the right (overrides the default caret). |
|
|
115
|
+
| `dropdownMenu` | `boolean` | `true` | When `false`, hides the built-in list and disables click-to-open; use with an external picker (e.g. `GroupSelect`) wired to the same `value` / `onChange`. |
|
|
116
|
+
| `onTriggerPress` | `() => void` | — | When `dropdownMenu` is `false`: fired when the user activates the field. Typically toggles the external panel. |
|
|
117
|
+
| `menuOpen` | `boolean` | `false` | When `dropdownMenu` is `false`: drives chevron direction and layering like the built-in open state. |
|
|
118
|
+
| `menuMinWidth` | `number` | `540` | When `dropdownMenu` is `false`: field `min-width` in px (matches `GroupSelect`). Use `0` for no minimum. |
|
|
116
119
|
|
|
117
120
|
Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
|
|
118
121
|
|
|
@@ -120,9 +123,9 @@ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
|
|
|
120
123
|
|
|
121
124
|
```ts
|
|
122
125
|
type MultiSelectValue = (string | number)[];
|
|
123
|
-
type MultiSelectVariant =
|
|
124
|
-
type MultiSelectSize =
|
|
125
|
-
type MultiSelectState =
|
|
126
|
+
type MultiSelectVariant = "tag" | "text";
|
|
127
|
+
type MultiSelectSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
128
|
+
type MultiSelectState = "default" | "hover" | "focus" | "disable" | "error";
|
|
126
129
|
|
|
127
130
|
interface MultiSelectOption {
|
|
128
131
|
label: ReactNode;
|
|
@@ -153,9 +156,9 @@ const options = [
|
|
|
153
156
|
|
|
154
157
|
```tsx
|
|
155
158
|
const options = [
|
|
156
|
-
{ label:
|
|
157
|
-
{ label:
|
|
158
|
-
{ label:
|
|
159
|
+
{ label: "React", value: "react" },
|
|
160
|
+
{ label: "Vue", value: "vue" },
|
|
161
|
+
{ label: "Angular", value: "angular" },
|
|
159
162
|
];
|
|
160
163
|
|
|
161
164
|
const [selected, setSelected] = useState<MultiSelectValue>([]);
|
|
@@ -173,9 +176,9 @@ const [selected, setSelected] = useState<MultiSelectValue>([]);
|
|
|
173
176
|
|
|
174
177
|
```tsx
|
|
175
178
|
const options = [
|
|
176
|
-
{ label:
|
|
177
|
-
{ label:
|
|
178
|
-
{ label:
|
|
179
|
+
{ label: "Design", value: "design" },
|
|
180
|
+
{ label: "Engineering", value: "engineering" },
|
|
181
|
+
{ label: "Product", value: "product" },
|
|
179
182
|
];
|
|
180
183
|
|
|
181
184
|
const [skills, setSkills] = useState<MultiSelectValue>([]);
|
|
@@ -193,12 +196,12 @@ const [skills, setSkills] = useState<MultiSelectValue>([]);
|
|
|
193
196
|
|
|
194
197
|
```tsx
|
|
195
198
|
const options = [
|
|
196
|
-
{ label:
|
|
197
|
-
{ label:
|
|
198
|
-
{ label:
|
|
199
|
+
{ label: "React", value: "react" },
|
|
200
|
+
{ label: "Vue", value: "vue" },
|
|
201
|
+
{ label: "Angular", value: "angular" },
|
|
199
202
|
];
|
|
200
203
|
|
|
201
|
-
<MultiSelect options={options} value={[
|
|
204
|
+
<MultiSelect options={options} value={["react"]} disabled />;
|
|
202
205
|
```
|
|
203
206
|
|
|
204
207
|
## Accessibility
|
package/native/index.d.mts
CHANGED
|
@@ -106,6 +106,8 @@ interface MultiSelectProps extends ThemeOverrideProps {
|
|
|
106
106
|
* no minimum. Ignored when the built-in dropdown is enabled.
|
|
107
107
|
*/
|
|
108
108
|
menuMinWidth?: number;
|
|
109
|
+
/** Test ID for testing frameworks */
|
|
110
|
+
testID?: string;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
declare const MultiSelect: react.ForwardRefExoticComponent<MultiSelectProps & react.RefAttributes<HTMLDivElement>>;
|
package/native/index.d.ts
CHANGED
|
@@ -106,6 +106,8 @@ interface MultiSelectProps extends ThemeOverrideProps {
|
|
|
106
106
|
* no minimum. Ignored when the built-in dropdown is enabled.
|
|
107
107
|
*/
|
|
108
108
|
menuMinWidth?: number;
|
|
109
|
+
/** Test ID for testing frameworks */
|
|
110
|
+
testID?: string;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
declare const MultiSelect: react.ForwardRefExoticComponent<MultiSelectProps & react.RefAttributes<HTMLDivElement>>;
|
package/native/index.js
CHANGED
|
@@ -238,6 +238,8 @@ var Text = ({
|
|
|
238
238
|
numberOfLines,
|
|
239
239
|
id,
|
|
240
240
|
role,
|
|
241
|
+
testID,
|
|
242
|
+
"data-testid": dataTestId,
|
|
241
243
|
style: styleProp,
|
|
242
244
|
...props
|
|
243
245
|
}) => {
|
|
@@ -267,7 +269,7 @@ var Text = ({
|
|
|
267
269
|
{
|
|
268
270
|
style: baseStyle,
|
|
269
271
|
numberOfLines,
|
|
270
|
-
testID: id,
|
|
272
|
+
testID: dataTestId || testID || id,
|
|
271
273
|
accessibilityRole,
|
|
272
274
|
children
|
|
273
275
|
}
|
|
@@ -278,7 +280,13 @@ var Text = ({
|
|
|
278
280
|
var import_react = __toESM(require("react"));
|
|
279
281
|
var import_react_native3 = require("react-native");
|
|
280
282
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
281
|
-
var Icon = ({
|
|
283
|
+
var Icon = ({
|
|
284
|
+
children,
|
|
285
|
+
color,
|
|
286
|
+
size,
|
|
287
|
+
testID,
|
|
288
|
+
"data-testid": dataTestId
|
|
289
|
+
}) => {
|
|
282
290
|
const style = {
|
|
283
291
|
width: typeof size === "number" ? size : void 0,
|
|
284
292
|
height: typeof size === "number" ? size : void 0,
|
|
@@ -295,7 +303,7 @@ var Icon = ({ children, color, size }) => {
|
|
|
295
303
|
}
|
|
296
304
|
return child;
|
|
297
305
|
});
|
|
298
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style, children: childrenWithProps });
|
|
306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style, testID: dataTestId || testID, children: childrenWithProps });
|
|
299
307
|
};
|
|
300
308
|
|
|
301
309
|
// src/MultiSelect.tsx
|
|
@@ -1050,6 +1058,7 @@ var BaseIcon = ({
|
|
|
1050
1058
|
className,
|
|
1051
1059
|
style,
|
|
1052
1060
|
"data-testid": testId,
|
|
1061
|
+
testID,
|
|
1053
1062
|
"aria-label": ariaLabel,
|
|
1054
1063
|
"aria-hidden": ariaHidden
|
|
1055
1064
|
}) => {
|
|
@@ -1062,7 +1071,7 @@ var BaseIcon = ({
|
|
|
1062
1071
|
$color: color,
|
|
1063
1072
|
className,
|
|
1064
1073
|
style,
|
|
1065
|
-
"data-testid": testId,
|
|
1074
|
+
"data-testid": testId || testID,
|
|
1066
1075
|
role: ariaLabel ? "img" : void 0,
|
|
1067
1076
|
"aria-label": ariaLabel,
|
|
1068
1077
|
"aria-hidden": ariaHidden != null ? ariaHidden : ariaLabel ? void 0 : true,
|
|
@@ -1257,8 +1266,13 @@ var StyledIcon2 = (0, import_styled_components2.default)(FilteredDiv)`
|
|
|
1257
1266
|
stroke: currentColor;
|
|
1258
1267
|
}
|
|
1259
1268
|
`;
|
|
1260
|
-
var Icon3 = ({
|
|
1261
|
-
|
|
1269
|
+
var Icon3 = ({
|
|
1270
|
+
children,
|
|
1271
|
+
testID,
|
|
1272
|
+
"data-testid": dataTestId,
|
|
1273
|
+
...props
|
|
1274
|
+
}) => {
|
|
1275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime725.jsx)(StyledIcon2, { "data-testid": dataTestId || testID, ...props, children });
|
|
1262
1276
|
};
|
|
1263
1277
|
var X2 = (props) => /* @__PURE__ */ (0, import_jsx_runtime726.jsx)(Icon3, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime726.jsx)(X, { size: "100%" }) });
|
|
1264
1278
|
|
|
@@ -1515,6 +1529,8 @@ var Text2 = ({
|
|
|
1515
1529
|
className,
|
|
1516
1530
|
id,
|
|
1517
1531
|
role,
|
|
1532
|
+
testID,
|
|
1533
|
+
"data-testid": dataTestId,
|
|
1518
1534
|
numberOfLines: _numberOfLines,
|
|
1519
1535
|
...props
|
|
1520
1536
|
}) => {
|
|
@@ -1525,7 +1541,8 @@ var Text2 = ({
|
|
|
1525
1541
|
style,
|
|
1526
1542
|
className,
|
|
1527
1543
|
id,
|
|
1528
|
-
role
|
|
1544
|
+
role,
|
|
1545
|
+
"data-testid": dataTestId || testID
|
|
1529
1546
|
}
|
|
1530
1547
|
);
|
|
1531
1548
|
};
|
|
@@ -1545,8 +1562,13 @@ var StyledIcon3 = (0, import_styled_components5.default)(FilteredDiv22)`
|
|
|
1545
1562
|
stroke: currentColor;
|
|
1546
1563
|
}
|
|
1547
1564
|
`;
|
|
1548
|
-
var Icon4 = ({
|
|
1549
|
-
|
|
1565
|
+
var Icon4 = ({
|
|
1566
|
+
children,
|
|
1567
|
+
testID,
|
|
1568
|
+
"data-testid": dataTestId,
|
|
1569
|
+
...props
|
|
1570
|
+
}) => {
|
|
1571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime729.jsx)(StyledIcon3, { "data-testid": dataTestId || testID, ...props, children });
|
|
1550
1572
|
};
|
|
1551
1573
|
var Tag = ({
|
|
1552
1574
|
size = "md",
|
|
@@ -1556,6 +1578,7 @@ var Tag = ({
|
|
|
1556
1578
|
iconLeft,
|
|
1557
1579
|
iconRight,
|
|
1558
1580
|
onRemove,
|
|
1581
|
+
testID,
|
|
1559
1582
|
themeMode,
|
|
1560
1583
|
themeProductContext
|
|
1561
1584
|
}) => {
|
|
@@ -1619,6 +1642,7 @@ var Tag = ({
|
|
|
1619
1642
|
return /* @__PURE__ */ (0, import_jsx_runtime730.jsxs)(
|
|
1620
1643
|
Box2,
|
|
1621
1644
|
{
|
|
1645
|
+
testID,
|
|
1622
1646
|
backgroundColor: bg,
|
|
1623
1647
|
borderRadius: sizeStyles.radius,
|
|
1624
1648
|
height: sizeStyles.height,
|
|
@@ -2175,6 +2199,7 @@ var MultiSelect = (0, import_react10.forwardRef)(
|
|
|
2175
2199
|
onTriggerPress,
|
|
2176
2200
|
menuOpen = false,
|
|
2177
2201
|
menuMinWidth,
|
|
2202
|
+
testID,
|
|
2178
2203
|
themeMode,
|
|
2179
2204
|
themeProductContext
|
|
2180
2205
|
}, ref) => {
|
|
@@ -2232,6 +2257,7 @@ var MultiSelect = (0, import_react10.forwardRef)(
|
|
|
2232
2257
|
return /* @__PURE__ */ (0, import_jsx_runtime733.jsxs)(
|
|
2233
2258
|
Box,
|
|
2234
2259
|
{
|
|
2260
|
+
testID,
|
|
2235
2261
|
flexDirection: "column",
|
|
2236
2262
|
gap: sizeStyles.fieldGap,
|
|
2237
2263
|
style: externalFieldLayout,
|
|
@@ -2302,7 +2328,7 @@ var MultiSelect = (0, import_react10.forwardRef)(
|
|
|
2302
2328
|
backgroundColor: theme.colors.background.secondary,
|
|
2303
2329
|
borderColor: theme.colors.border.secondary,
|
|
2304
2330
|
borderWidth: 1,
|
|
2305
|
-
borderRadius: theme.
|
|
2331
|
+
borderRadius: theme.shape.input[size].borderRadius,
|
|
2306
2332
|
paddingVertical: 4,
|
|
2307
2333
|
style: {
|
|
2308
2334
|
position: "absolute",
|
|
@@ -2322,6 +2348,7 @@ var MultiSelect = (0, import_react10.forwardRef)(
|
|
|
2322
2348
|
return /* @__PURE__ */ (0, import_jsx_runtime733.jsx)(
|
|
2323
2349
|
Box,
|
|
2324
2350
|
{
|
|
2351
|
+
testID,
|
|
2325
2352
|
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
2326
2353
|
paddingVertical: 8,
|
|
2327
2354
|
onPress: () => {
|