@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.
Files changed (2) hide show
  1. package/README.md +358 -0
  2. 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.0",
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.0",
17
- "@xsolla/xui-icons-base": "0.148.0",
18
- "@xsolla/xui-primitives-core": "0.148.0"
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",