@xsolla/xui-select 0.99.0 → 0.101.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 +326 -19
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,39 +1,346 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Select
|
|
2
2
|
|
|
3
|
-
|
|
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
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
+
npm install @xsolla/xui-select
|
|
9
|
+
# or
|
|
8
10
|
yarn add @xsolla/xui-select
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
##
|
|
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
|
|
12
84
|
|
|
13
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
|
|
14
127
|
import { Select } from '@xsolla/xui-select';
|
|
15
128
|
|
|
16
129
|
<Select
|
|
17
|
-
label="
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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")
|
|
21
140
|
/>
|
|
22
141
|
```
|
|
23
142
|
|
|
24
|
-
##
|
|
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
|
|
25
265
|
|
|
26
266
|
### Select
|
|
27
267
|
|
|
268
|
+
The main select component. Renders a button trigger with dropdown menu.
|
|
269
|
+
|
|
270
|
+
**Select Props:**
|
|
271
|
+
|
|
28
272
|
| Prop | Type | Default | Description |
|
|
29
|
-
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
| `
|
|
35
|
-
|
|
|
36
|
-
| `
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
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
|
+
## Accessibility
|
|
339
|
+
|
|
340
|
+
- Uses semantic button element for trigger
|
|
341
|
+
- Dropdown menu has proper focus management
|
|
342
|
+
- Keyboard navigation supported (Tab, Enter, Space, Escape)
|
|
343
|
+
- Selected item is visually highlighted
|
|
344
|
+
- Auto-scrolls to selected item when opened
|
|
345
|
+
- Focus indicators follow WCAG guidelines
|
|
346
|
+
- 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.
|
|
3
|
+
"version": "0.101.0",
|
|
4
4
|
"main": "./web/index.js",
|
|
5
5
|
"module": "./web/index.mjs",
|
|
6
6
|
"types": "./web/index.d.ts",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"build:native": "PLATFORM=native tsup"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@xsolla/xui-core": "0.
|
|
14
|
-
"@xsolla/xui-primitives-core": "0.
|
|
13
|
+
"@xsolla/xui-core": "0.101.0",
|
|
14
|
+
"@xsolla/xui-primitives-core": "0.101.0"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"react": ">=16.8.0",
|