@xsolla/xui-select 0.148.0 → 0.148.2
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 +358 -0
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# Select
|
|
2
|
+
|
|
3
|
+
A cross-platform React select component for choosing from a list of predefined options with dropdown menu. Works on both React (web) and React Native.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @xsolla/xui-select
|
|
9
|
+
# or
|
|
10
|
+
yarn add @xsolla/xui-select
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Demo
|
|
14
|
+
|
|
15
|
+
### Basic Select
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import * as React from 'react';
|
|
19
|
+
import { Select } from '@xsolla/xui-select';
|
|
20
|
+
|
|
21
|
+
export default function BasicSelect() {
|
|
22
|
+
const [value, setValue] = React.useState('');
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Select
|
|
26
|
+
value={value}
|
|
27
|
+
onChange={setValue}
|
|
28
|
+
options={['Option 1', 'Option 2', 'Option 3']}
|
|
29
|
+
placeholder="Select an option"
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Select with Label
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import * as React from 'react';
|
|
39
|
+
import { Select } from '@xsolla/xui-select';
|
|
40
|
+
|
|
41
|
+
export default function LabeledSelect() {
|
|
42
|
+
const [country, setCountry] = React.useState('');
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Select
|
|
46
|
+
label="Country"
|
|
47
|
+
value={country}
|
|
48
|
+
onChange={setCountry}
|
|
49
|
+
options={['United States', 'Canada', 'United Kingdom', 'Germany', 'France']}
|
|
50
|
+
placeholder="Select a country"
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Select with Object Options
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import * as React from 'react';
|
|
60
|
+
import { Select } from '@xsolla/xui-select';
|
|
61
|
+
|
|
62
|
+
export default function ObjectOptionsSelect() {
|
|
63
|
+
const [status, setStatus] = React.useState('');
|
|
64
|
+
|
|
65
|
+
const options = [
|
|
66
|
+
{ label: 'Active', value: 'active' },
|
|
67
|
+
{ label: 'Pending', value: 'pending' },
|
|
68
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Select
|
|
73
|
+
label="Status"
|
|
74
|
+
value={status}
|
|
75
|
+
onChange={setStatus}
|
|
76
|
+
options={options}
|
|
77
|
+
placeholder="Select status"
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Select Sizes
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import * as React from 'react';
|
|
87
|
+
import { Select } from '@xsolla/xui-select';
|
|
88
|
+
|
|
89
|
+
export default function SelectSizes() {
|
|
90
|
+
const options = ['Small', 'Medium', 'Large'];
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
|
94
|
+
<Select size="xs" options={options} placeholder="Extra Small" />
|
|
95
|
+
<Select size="sm" options={options} placeholder="Small" />
|
|
96
|
+
<Select size="md" options={options} placeholder="Medium (default)" />
|
|
97
|
+
<Select size="lg" options={options} placeholder="Large" />
|
|
98
|
+
<Select size="xl" options={options} placeholder="Extra Large" />
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Select with Icons
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import * as React from 'react';
|
|
108
|
+
import { Select } from '@xsolla/xui-select';
|
|
109
|
+
import { Globe } from '@xsolla/xui-icons-base';
|
|
110
|
+
|
|
111
|
+
export default function SelectWithIcons() {
|
|
112
|
+
return (
|
|
113
|
+
<Select
|
|
114
|
+
iconLeft={<Globe />}
|
|
115
|
+
options={['English', 'Spanish', 'French', 'German']}
|
|
116
|
+
placeholder="Select language"
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Anatomy
|
|
123
|
+
|
|
124
|
+
Import the component and use it directly:
|
|
125
|
+
|
|
126
|
+
```jsx
|
|
127
|
+
import { Select } from '@xsolla/xui-select';
|
|
128
|
+
|
|
129
|
+
<Select
|
|
130
|
+
label="Field Label" // Optional label above select
|
|
131
|
+
value={value} // Controlled selected value
|
|
132
|
+
onChange={setValue} // Value change handler
|
|
133
|
+
options={['A', 'B', 'C']} // Array of options (strings or objects)
|
|
134
|
+
placeholder="Select..." // Placeholder text
|
|
135
|
+
iconLeft={<Icon />} // Optional left icon
|
|
136
|
+
iconRight={<Icon />} // Optional right icon (default: ChevronDown)
|
|
137
|
+
filled // Whether to show filled background
|
|
138
|
+
state="error" // State: "default" | "disable" | "error"
|
|
139
|
+
errorMessage="Error message" // Error message (shown when state="error")
|
|
140
|
+
/>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Examples
|
|
144
|
+
|
|
145
|
+
### Error State
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import * as React from 'react';
|
|
149
|
+
import { Select } from '@xsolla/xui-select';
|
|
150
|
+
|
|
151
|
+
export default function ErrorSelect() {
|
|
152
|
+
return (
|
|
153
|
+
<Select
|
|
154
|
+
label="Required Field"
|
|
155
|
+
state="error"
|
|
156
|
+
errorMessage="Please select an option"
|
|
157
|
+
options={['Option 1', 'Option 2', 'Option 3']}
|
|
158
|
+
placeholder="Select an option"
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Disabled Select
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import * as React from 'react';
|
|
168
|
+
import { Select } from '@xsolla/xui-select';
|
|
169
|
+
|
|
170
|
+
export default function DisabledSelect() {
|
|
171
|
+
return (
|
|
172
|
+
<Select
|
|
173
|
+
label="Disabled Field"
|
|
174
|
+
value="Option 1"
|
|
175
|
+
state="disable"
|
|
176
|
+
options={['Option 1', 'Option 2', 'Option 3']}
|
|
177
|
+
/>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Unfilled/Transparent Background
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
import * as React from 'react';
|
|
186
|
+
import { Select } from '@xsolla/xui-select';
|
|
187
|
+
|
|
188
|
+
export default function UnfilledSelect() {
|
|
189
|
+
return (
|
|
190
|
+
<Select
|
|
191
|
+
filled={false}
|
|
192
|
+
options={['Option 1', 'Option 2', 'Option 3']}
|
|
193
|
+
placeholder="Transparent background"
|
|
194
|
+
/>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Icon Only Select
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import * as React from 'react';
|
|
203
|
+
import { Select } from '@xsolla/xui-select';
|
|
204
|
+
import { Settings } from '@xsolla/xui-icons';
|
|
205
|
+
|
|
206
|
+
export default function IconOnlySelect() {
|
|
207
|
+
return (
|
|
208
|
+
<Select
|
|
209
|
+
iconOnly
|
|
210
|
+
iconLeft={<Settings />}
|
|
211
|
+
options={['Settings', 'Preferences', 'Advanced']}
|
|
212
|
+
/>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Form with Select
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import * as React from 'react';
|
|
221
|
+
import { Select } from '@xsolla/xui-select';
|
|
222
|
+
import { Input } from '@xsolla/xui-input';
|
|
223
|
+
import { Button } from '@xsolla/xui-button';
|
|
224
|
+
|
|
225
|
+
export default function FormWithSelect() {
|
|
226
|
+
const [form, setForm] = React.useState({
|
|
227
|
+
name: '',
|
|
228
|
+
category: '',
|
|
229
|
+
priority: '',
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>
|
|
234
|
+
<Input
|
|
235
|
+
label="Task Name"
|
|
236
|
+
value={form.name}
|
|
237
|
+
onChangeText={(name) => setForm(prev => ({ ...prev, name }))}
|
|
238
|
+
placeholder="Enter task name"
|
|
239
|
+
/>
|
|
240
|
+
<Select
|
|
241
|
+
label="Category"
|
|
242
|
+
value={form.category}
|
|
243
|
+
onChange={(category) => setForm(prev => ({ ...prev, category }))}
|
|
244
|
+
options={['Development', 'Design', 'Marketing', 'Sales']}
|
|
245
|
+
placeholder="Select category"
|
|
246
|
+
/>
|
|
247
|
+
<Select
|
|
248
|
+
label="Priority"
|
|
249
|
+
value={form.priority}
|
|
250
|
+
onChange={(priority) => setForm(prev => ({ ...prev, priority }))}
|
|
251
|
+
options={[
|
|
252
|
+
{ label: 'High', value: 'high' },
|
|
253
|
+
{ label: 'Medium', value: 'medium' },
|
|
254
|
+
{ label: 'Low', value: 'low' },
|
|
255
|
+
]}
|
|
256
|
+
placeholder="Select priority"
|
|
257
|
+
/>
|
|
258
|
+
<Button>Create Task</Button>
|
|
259
|
+
</div>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## API Reference
|
|
265
|
+
|
|
266
|
+
### Select
|
|
267
|
+
|
|
268
|
+
The main select component. Renders a button trigger with dropdown menu.
|
|
269
|
+
|
|
270
|
+
**Select Props:**
|
|
271
|
+
|
|
272
|
+
| Prop | Type | Default | Description |
|
|
273
|
+
| :--- | :--- | :------ | :---------- |
|
|
274
|
+
| value | `string` | - | The controlled selected value. |
|
|
275
|
+
| placeholder | `string` | `"Select"` | Placeholder text when no value selected. |
|
|
276
|
+
| onPress | `() => void` | - | Callback when select trigger is pressed. |
|
|
277
|
+
| size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"md"` | The size of the select. |
|
|
278
|
+
| state | `"default" \| "hover" \| "focus" \| "disable" \| "error"` | `"default"` | The visual state of the select. |
|
|
279
|
+
| label | `string` | - | Label text displayed above the select. |
|
|
280
|
+
| disabled | `boolean` | `false` | Whether the select is disabled. Also triggered when `state="disable"`. |
|
|
281
|
+
| errorMessage | `string` | - | Error message displayed below the select (also sets error styling). |
|
|
282
|
+
| iconLeft | `ReactNode` | - | Icon displayed on the left side. |
|
|
283
|
+
| iconRight | `ReactNode` | `<ChevronDown />` | Icon displayed on the right side. |
|
|
284
|
+
| filled | `boolean` | `true` | Whether to show filled background. |
|
|
285
|
+
| iconOnly | `boolean` | `false` | Whether to show only icon without text. |
|
|
286
|
+
| options | `(string \| SelectOption)[]` | `[]` | Array of options to display. |
|
|
287
|
+
| onChange | `(value: string) => void` | - | Callback when value changes. |
|
|
288
|
+
| searchable | `boolean` | `false` | Whether to show a search input in the dropdown. |
|
|
289
|
+
| searchPlaceholder | `string` | `"Search"` | Placeholder text for the search input. |
|
|
290
|
+
| noOptionsMessage | `string` | `"No results"` | Message shown when no options match the search. |
|
|
291
|
+
| maxHeight | `number` | `300` | Maximum height of the dropdown in pixels. |
|
|
292
|
+
|
|
293
|
+
**SelectOption Type:**
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
interface SelectOption {
|
|
297
|
+
label: string; // Display text
|
|
298
|
+
value: any; // Value to be selected
|
|
299
|
+
disabled?: boolean; // Whether this option is disabled
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Theming
|
|
304
|
+
|
|
305
|
+
Select components use the design system theme for colors and sizing:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Colors accessed via theme
|
|
309
|
+
theme.colors.control.input.bg // Background color
|
|
310
|
+
theme.colors.control.input.bgHover // Hover background
|
|
311
|
+
theme.colors.control.input.bgFocus // Focus background
|
|
312
|
+
theme.colors.control.input.bgDisable // Disabled background
|
|
313
|
+
theme.colors.control.input.border // Border color
|
|
314
|
+
theme.colors.control.input.borderFocus // Focus border color
|
|
315
|
+
theme.colors.control.input.borderError // Error border color
|
|
316
|
+
theme.colors.control.input.text // Text color
|
|
317
|
+
theme.colors.control.brand.primary.bg // Selected option background
|
|
318
|
+
|
|
319
|
+
// Sizing accessed via theme
|
|
320
|
+
theme.sizing.input(size).height
|
|
321
|
+
theme.sizing.input(size).paddingVertical
|
|
322
|
+
theme.sizing.input(size).paddingHorizontal
|
|
323
|
+
theme.sizing.input(size).fontSize
|
|
324
|
+
|
|
325
|
+
// Border radius
|
|
326
|
+
theme.radius.button
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Dropdown Styling:**
|
|
330
|
+
|
|
331
|
+
| Property | Value |
|
|
332
|
+
| :------- | :---- |
|
|
333
|
+
| Max Height | 300px (configurable via `maxHeight` prop) |
|
|
334
|
+
| Box Shadow | 0 4px 12px rgba(0,0,0,0.1) |
|
|
335
|
+
| Z-Index | 1000 |
|
|
336
|
+
| Scroll | overflowY: auto |
|
|
337
|
+
|
|
338
|
+
## React Native Notes
|
|
339
|
+
|
|
340
|
+
The Select component works on React Native with the following differences:
|
|
341
|
+
|
|
342
|
+
| Feature | Web | React Native |
|
|
343
|
+
|---------|-----|-------------|
|
|
344
|
+
| Searchable dropdown | Supported (`searchable` prop) | **Not available** — prop is ignored |
|
|
345
|
+
| Dropdown shadow | CSS `box-shadow` | Android `elevation: 4` |
|
|
346
|
+
| Scroll behavior | `overflowY: auto` | Native `ScrollView` |
|
|
347
|
+
| Cursor styles | `pointer` / `not-allowed` | Ignored |
|
|
348
|
+
| Click-outside dismiss | `document.addEventListener` | Not active (guarded by `isNative`) |
|
|
349
|
+
|
|
350
|
+
## Accessibility
|
|
351
|
+
|
|
352
|
+
- Uses semantic button element for trigger
|
|
353
|
+
- Dropdown menu has proper focus management
|
|
354
|
+
- Keyboard navigation supported (Tab, Enter, Space, Escape)
|
|
355
|
+
- Selected item is visually highlighted
|
|
356
|
+
- Auto-scrolls to selected item when opened (web only)
|
|
357
|
+
- Focus indicators follow WCAG guidelines
|
|
358
|
+
- Disabled state properly communicated to assistive technology
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsolla/xui-select",
|
|
3
|
-
"version": "0.148.
|
|
3
|
+
"version": "0.148.2",
|
|
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-core": "0.148.
|
|
17
|
-
"@xsolla/xui-icons-base": "0.148.
|
|
18
|
-
"@xsolla/xui-primitives-core": "0.148.
|
|
16
|
+
"@xsolla/xui-core": "0.148.2",
|
|
17
|
+
"@xsolla/xui-icons-base": "0.148.2",
|
|
18
|
+
"@xsolla/xui-primitives-core": "0.148.2"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"react": ">=16.8.0",
|