@synerise/ds-select 1.3.33 → 1.4.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/CHANGELOG.md +25 -0
- package/CLAUDE.md +175 -0
- package/README.md +163 -99
- package/dist/Option.d.ts +28 -0
- package/dist/Option.js +5 -0
- package/dist/Select.d.ts +82 -17
- package/dist/Select.js +386 -64
- package/dist/Select.styles.d.ts +39 -11
- package/dist/Select.styles.js +92 -65
- package/dist/Select.types.d.ts +137 -11
- package/dist/components/OptionList.d.ts +23 -0
- package/dist/components/OptionList.js +32 -0
- package/dist/components/SelectorContent.d.ts +34 -0
- package/dist/components/SelectorContent.js +72 -0
- package/dist/hooks/useSelectOptions.d.ts +28 -0
- package/dist/hooks/useSelectOptions.js +41 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +6 -1
- package/dist/utils/getOptionsFromChildren.d.ts +11 -0
- package/dist/utils/getOptionsFromChildren.js +41 -0
- package/dist/utils/helpers.d.ts +9 -0
- package/dist/utils/helpers.js +18 -0
- package/package.json +11 -7
- package/dist/assets/style/index-tn0RQdqM.css +0 -0
- package/dist/style/index.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.4.0](https://github.com/synerise/synerise-design/compare/@synerise/ds-select@1.3.34...@synerise/ds-select@1.4.0) (2026-07-24)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **select:** add onKeyDown, maxLength, dropdownAlign, popupClassName, maxTagPlaceholder ([1cf5f39](https://github.com/synerise/synerise-design/commit/1cf5f394055c10caee8b2bef81c83d04e19dcd6e))
|
|
11
|
+
- **select:** add suffixIcon, tabIndex, option style/children parity shims ([10c0bbc](https://github.com/synerise/synerise-design/commit/10c0bbc584534f7950bd5093764d9363a526149b))
|
|
12
|
+
- **select:** color clear/remove icons via currentColor, not svg fill ([0573124](https://github.com/synerise/synerise-design/commit/05731249ebc2d6d291879f0cb0f7443d8966a2b6))
|
|
13
|
+
- **select:** fire onFocus/onBlur and split render into sub-components ([44f73ec](https://github.com/synerise/synerise-design/commit/44f73ec0dc705c920950048acfa61ea108ec8072))
|
|
14
|
+
- **select:** forward data-_ and aria-_ attributes to the select root ([49294a8](https://github.com/synerise/synerise-design/commit/49294a8b1ab2b17967fc9d8ce9879eb48c5844cb))
|
|
15
|
+
- **select:** mark the current option selected via ListItem selected prop ([b5cb80a](https://github.com/synerise/synerise-design/commit/b5cb80a9d6e8a0411752a58fb0e66770f5c19408))
|
|
16
|
+
- **select:** move onClick off the dropdown trigger; focus inputs in interaction tests ([ed1a79c](https://github.com/synerise/synerise-design/commit/ed1a79c45bf056304a11e959ceb086dc1258b55e))
|
|
17
|
+
- **select:** multiple chip keeps its label-defined width; X squeezes label on hover ([5c9908d](https://github.com/synerise/synerise-design/commit/5c9908d8ff86119aa3948a1f366497827598bd3d))
|
|
18
|
+
- **select:** overlay search input and blur it on selection ([f312354](https://github.com/synerise/synerise-design/commit/f31235487542b29f31b2435c2b9951716803d20c))
|
|
19
|
+
- **select:** restore antd-parity props for consumer back-compat ([ceac672](https://github.com/synerise/synerise-design/commit/ceac6729c4c4815ee918a927a98aa17de0407e8d))
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- **select:** forward per-option data-_/aria-_ to the rendered option row ([1a8162d](https://github.com/synerise/synerise-design/commit/1a8162d9dae98a5cf96b0f35f70f9148eb025e88))
|
|
24
|
+
- **select:** implement maxTagCount/maxTagTextLength/maxTagPlaceholder + onPopupScroll ([060d2c6](https://github.com/synerise/synerise-design/commit/060d2c6b74118c065d928786dad67aa1b88500c7))
|
|
25
|
+
- **select:** keyboard-arrow option navigation + combobox/listbox ARIA ([74e5466](https://github.com/synerise/synerise-design/commit/74e5466b23dc2d062c0bd734cc84334f55b99ab8))
|
|
26
|
+
|
|
27
|
+
## [1.3.34](https://github.com/synerise/synerise-design/compare/@synerise/ds-select@1.3.33...@synerise/ds-select@1.3.34) (2026-07-23)
|
|
28
|
+
|
|
29
|
+
**Note:** Version bump only for package @synerise/ds-select
|
|
30
|
+
|
|
6
31
|
## [1.3.33](https://github.com/synerise/synerise-design/compare/@synerise/ds-select@1.3.32...@synerise/ds-select@1.3.33) (2026-06-17)
|
|
7
32
|
|
|
8
33
|
**Note:** Version bump only for package @synerise/ds-select
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Select (`@synerise/ds-select`)
|
|
2
|
+
|
|
3
|
+
> A DS-native select dropdown (no Ant Design): a selector trigger + floating options dropdown built
|
|
4
|
+
> on `@synerise/ds-dropdown` (floating-ui) and `@synerise/ds-list-item`, wrapped in `FormField`.
|
|
5
|
+
> Supports single-select, `multiple` (chips), `tags` (free-text) and in-selector search, with full
|
|
6
|
+
> keyboard navigation, combobox/listbox ARIA, prefix/suffix addons, `readOnly`, and a `raw` variant.
|
|
7
|
+
|
|
8
|
+
## Package structure
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
src/
|
|
12
|
+
Select.tsx — main component (forwardRef, compound with .Option); composes the sub-components below
|
|
13
|
+
Select.types.ts — SelectProps, SelectValue, SelectOption, SelectMode, SelectHandler, RawValueType, FilterOptionFn
|
|
14
|
+
Select.styles.ts — styled-components (Selector = the .ds-select box, SelectWrapper, chips, dropdown, …)
|
|
15
|
+
Option.tsx — declarative <Select.Option> marker (renders null) + OptionProps
|
|
16
|
+
index.ts — default export + types + SelectStyles namespace + getOptionsFromChildren/findOption
|
|
17
|
+
Select.figma.tsx — Figma Code Connect mapping
|
|
18
|
+
modules.d.ts — imports @testing-library/jest-dom
|
|
19
|
+
hooks/
|
|
20
|
+
useSelectOptions.ts — resolve options (prop → children), client filtering, tags create-row
|
|
21
|
+
components/
|
|
22
|
+
OptionList.tsx — dropdown overlay: loading / empty / scrollable listbox of options
|
|
23
|
+
SelectorContent.tsx — selector inner content: chips / selected label / placeholder + search input
|
|
24
|
+
utils/
|
|
25
|
+
getOptionsFromChildren.ts — read <Select.Option> children into SelectOption[]; findOption()
|
|
26
|
+
helpers.ts — cx(), toArray(), defaultFilter(), DEFAULT_LIST_HEIGHT
|
|
27
|
+
__specs__/
|
|
28
|
+
Select.spec.tsx — Vitest + React Testing Library tests
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> No `style/` dir and no `antd` peerDep — the component is styled purely with styled-components. The
|
|
32
|
+
> old antd-era LESS (`select.mixin.less`, `.ant-select-*` overrides) was relocated to `ds-table`
|
|
33
|
+
> (`table/src/style/`), the only consumer that still renders antd selects.
|
|
34
|
+
|
|
35
|
+
## Public exports
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
export { default } from './Select'; // compound: Select + .Option
|
|
39
|
+
export { Option, type OptionProps } from './Option';
|
|
40
|
+
export type {
|
|
41
|
+
Props, SelectProps, SelectValue, SelectOption, SelectMode,
|
|
42
|
+
SelectHandler, RawValueType, FilterOptionFn,
|
|
43
|
+
} from './Select.types';
|
|
44
|
+
export * as SelectStyles from './Select.styles';
|
|
45
|
+
export { getOptionsFromChildren, findOption } from './utils/getOptionsFromChildren';
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `Select` (default)
|
|
49
|
+
|
|
50
|
+
`forwardRef<HTMLDivElement, SelectProps>`, augmented into a compound component with a single
|
|
51
|
+
sub-component: **`Select.Option`** (the DS `Option` marker). `Select.OptGroup` is intentionally
|
|
52
|
+
**not** reimplemented (zero real usage).
|
|
53
|
+
|
|
54
|
+
`SelectValue = string | number | (string | number)[] | undefined` — antd-free (no `LabeledValue`).
|
|
55
|
+
|
|
56
|
+
#### DS-specific props
|
|
57
|
+
|
|
58
|
+
| Prop | Type | Default | Description |
|
|
59
|
+
|------|------|---------|-------------|
|
|
60
|
+
| `label` / `description` / `tooltip` / `tooltipConfig` | `ReactNode` / `TooltipProps` | `undefined` | `FormField` chrome (from `FormFieldCommonProps`). |
|
|
61
|
+
| `errorText` | `ReactNode` | `undefined` | Error message below the field; also activates the error visual state. |
|
|
62
|
+
| `error` | `boolean` | `undefined` | Error visual state without a message. |
|
|
63
|
+
| `clearTooltip` | `string` | `undefined` | Tooltip on hover of the clear (×) control. |
|
|
64
|
+
| `prefixel` / `suffixel` | `ReactNode` | `undefined` | Addon nodes attached left/right of the selector (shared border). |
|
|
65
|
+
| `grey` | `boolean` | `undefined` | `grey-050` selector background when not in error state. |
|
|
66
|
+
| `asFormElement` | `boolean` | `undefined` | Forces a 16 px bottom margin even without `errorText`/`description`. |
|
|
67
|
+
| `raw` | `boolean` | `undefined` | Skips the `FormField` wrapper — renders only the selector; `ref` attaches to `SelectWrapper`. |
|
|
68
|
+
| `readOnly` | `boolean` | `undefined` | Non-interactive with readable styling (white bg, `default` cursor, `grey-600` text). |
|
|
69
|
+
| `disabled` | `boolean` | `undefined` | Standard disabled state; ORed with `readOnly` to block interaction. |
|
|
70
|
+
| `selectorStyle` | `CSSObject` | `undefined` | Inline style object applied to the `Selector` box. |
|
|
71
|
+
| `listHeight` | `number \| string` | `256` | Max dropdown list height (px). |
|
|
72
|
+
| `style` | `CSSProperties` | `undefined` | Applied to `SelectWrapper` (the flex row: selector + addons). |
|
|
73
|
+
| `className` | `string` | `undefined` | Added to the outer `SelectContainer`. |
|
|
74
|
+
| `getPopupContainer` | `(node) => HTMLElement \| ParentNode \| null` | `defaultGetPopupContainer` (`@synerise/ds-utils`) | Container the dropdown mounts into. |
|
|
75
|
+
| `size` | `'default' \| 'middle' \| 'large'` | `'default'` | Selector height (`middle` maps to `default`). |
|
|
76
|
+
|
|
77
|
+
Native `data-*` / `aria-*` attributes are forwarded onto the select root (`.ds-select-wrapper`).
|
|
78
|
+
|
|
79
|
+
#### antd-parity props (additive back-compat)
|
|
80
|
+
|
|
81
|
+
Kept so antd-era consumers need no change: `searchValue`, `onClear`, `onClick`, `onInputKeyDown`,
|
|
82
|
+
`onKeyDown`, `suffixIcon`, `clearIcon`, `maxLength`, `maxTagCount`, `maxTagTextLength`,
|
|
83
|
+
`maxTagPlaceholder`, `onPopupScroll`, `popupClassName` (alias of `dropdownClassName`),
|
|
84
|
+
`dropdownMatchSelectWidth` (`boolean | number`), `dropdownRender`, `showArrow`,
|
|
85
|
+
`autoFocus`, `tabIndex`, `rowKey`, plus the standard
|
|
86
|
+
`mode`/`options`/`showSearch`/`filterOption`/`allowClear`/`open`/`onChange`/`onSearch`/… surface.
|
|
87
|
+
`SelectHandler` type and the `SelectStyles.Selector` styled export are re-exported for parity.
|
|
88
|
+
|
|
89
|
+
`maxTagCount` (collapse extra chips into a `+N` overflow chip), `maxTagTextLength` (truncate chip
|
|
90
|
+
labels) and `onPopupScroll` are fully implemented. `listItemHeight`, `dropdownAlign` and
|
|
91
|
+
`defaultActiveFirstOption` are accepted for compatibility but have **no runtime effect**.
|
|
92
|
+
|
|
93
|
+
## Usage patterns
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import Select from '@synerise/ds-select';
|
|
97
|
+
|
|
98
|
+
const { Option } = Select;
|
|
99
|
+
|
|
100
|
+
// Options as data (preferred)
|
|
101
|
+
<Select label="Platform" options={[{ value: 'insta', label: 'Instagram' }]} defaultValue="insta" />
|
|
102
|
+
|
|
103
|
+
// Declarative children (read only when `options` is absent)
|
|
104
|
+
<Select label="Platform"><Option value="insta">Instagram</Option></Select>
|
|
105
|
+
|
|
106
|
+
// Multiple (removable chips) / tags (free-text) / search
|
|
107
|
+
<Select mode="multiple" placeholder="Select tags" allowClear options={opts} />
|
|
108
|
+
<Select mode="tags" tokenSeparators={[',']} />
|
|
109
|
+
<Select showSearch filterOption optionFilterProp="label" options={opts} />
|
|
110
|
+
|
|
111
|
+
// Remote search: filter server-side, feed options from onSearch
|
|
112
|
+
<Select showSearch filterOption={false} onSearch={fetchOptions} options={opts} />
|
|
113
|
+
|
|
114
|
+
// readOnly / raw / prefix-suffix
|
|
115
|
+
<Select readOnly value="locked" />
|
|
116
|
+
<Select raw ref={myRef} placeholder="Compact" />
|
|
117
|
+
<Select prefixel={<span>$</span>} suffixel={<span>USD</span>} />
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Styling
|
|
121
|
+
|
|
122
|
+
**styled-components (`Select.styles.ts`) is the source of truth.** Key styled parts:
|
|
123
|
+
- `SelectContainer` — column flex; adds a 16 px bottom margin when `hasBottomMargin`.
|
|
124
|
+
- `SelectWrapper` (`.ds-select-wrapper`) — the flex row (selector + addons); carries the root
|
|
125
|
+
`onFocus`/`onBlur`/`onClick` and `data-*`/`aria-*` passthrough.
|
|
126
|
+
- `Selector` (`.ds-select`) — the trigger box; `large` height, `withPrefixel`/`withSuffixel`
|
|
127
|
+
border-radius removal, open/focus ring (`blue-600`/`blue-050`), error (`red-600`/`red-050`),
|
|
128
|
+
`readOnly` vs `disabled` differentiation, and the `selectorStyle` interpolation.
|
|
129
|
+
- `PrefixWrapper` / `SuffixWrapper` — `grey-050` addons with flush border join.
|
|
130
|
+
- Dropdown / options: `DropdownWrapper`, `ScrollList`, `Inner` (`role="listbox"`), `OptionItem`
|
|
131
|
+
(styled `ds-list-item`), `NotFound`, `Loading`. Selector content: `SelectionItem`, `Placeholder`,
|
|
132
|
+
`MultiValueArea`, `Chip`/`ChipLabel`/`ChipRemove`, `Arrow`, `ClearWrapper`, `SearchInputEl`.
|
|
133
|
+
|
|
134
|
+
Class hooks are `ds-select-*` (`.ds-select`, `.ds-select-selection-item`, `.ds-select-dropdown`,
|
|
135
|
+
`.ds-select-arrow`, `.ds-select-clear`, `.ds-select-search`, …).
|
|
136
|
+
|
|
137
|
+
## Key dependencies
|
|
138
|
+
|
|
139
|
+
- `@synerise/ds-dropdown` — floating-ui popover positioning + overlay (the `Selector` is the `asChild` trigger).
|
|
140
|
+
- `@synerise/ds-list-item` — the option row (`OptionItem`) and list wrapper (`ScrollList`).
|
|
141
|
+
- `@synerise/ds-scrollbar` / `@synerise/ds-loader` — dropdown scroll container / loading spinner.
|
|
142
|
+
- `@synerise/ds-form-field` — label / description / error layout (skipped when `raw`).
|
|
143
|
+
- `@synerise/ds-icon` — `AngleDownS` (arrow), `Close3M` (clear), `CloseS` (chip remove).
|
|
144
|
+
- `@synerise/ds-tooltip` — wraps the clear control for `clearTooltip`.
|
|
145
|
+
- `@synerise/ds-utils` — default `getPopupContainer`.
|
|
146
|
+
- `@synerise/ds-core` — theme tokens (peerDep). **No `antd` peerDep** — the component imports zero
|
|
147
|
+
antd; the LESS that pulled `~antd/lib/select/style` was relocated to `ds-table` (see below).
|
|
148
|
+
|
|
149
|
+
## Implementation notes
|
|
150
|
+
|
|
151
|
+
- **Option resolution** — `useSelectOptions` returns `resolvedOptions` (from `options` prop, else
|
|
152
|
+
`getOptionsFromChildren(children)`) and `displayedOptions` (after client filtering and, in `tags`
|
|
153
|
+
mode, a create-row prepended for the typed text). `filterOption={false}` disables local filtering.
|
|
154
|
+
- **`Option.value` is optional** — falls back to the element's React `key` (antd parity); callbacks
|
|
155
|
+
expose `option.key`.
|
|
156
|
+
- **Keyboard nav is hand-rolled (not ds-dropdown's)** — Select is a *combobox*: focus stays on the
|
|
157
|
+
input/selector via `aria-activedescendant`, whereas ds-dropdown uses roving DOM focus. `activeIndex`
|
|
158
|
+
+ `moveActive` + three effects drive highlight; `handleKeyDown` handles Arrow/Home/End/Enter/Escape/
|
|
159
|
+
Space and Backspace (drop last chip).
|
|
160
|
+
- **Focus / blur** — `onFocus`/`onBlur` fire on the root only when focus truly enters/leaves the
|
|
161
|
+
select (relatedTarget guard ignores selector↔input moves). `autoFocus` focuses the `Selector` in
|
|
162
|
+
select-only mode (no search input to receive it). The dropdown `onMouseDown` prevents focus loss so
|
|
163
|
+
selecting an option / scrolling isn't treated as a blur (needed by `subtle-form`'s revert-on-blur).
|
|
164
|
+
- **`readOnly` is implemented via `disabled`** — both flags are ORed into `isDisabled`; the visual
|
|
165
|
+
distinction comes from the `$readOnly` transient prop on `Selector`.
|
|
166
|
+
- **Controlled/uncontrolled** — `value`/`open`/`searchValue` are controlled when defined, else backed
|
|
167
|
+
by internal state; `onSearch` still fires when `searchValue` is controlled.
|
|
168
|
+
- **antd-free; no LESS** — styling is entirely styled-components. The old antd-era LESS
|
|
169
|
+
(`style/index.less` + `select.mixin.less`, `.ant-select-*` overrides for antd selects) was
|
|
170
|
+
**relocated to `ds-table`** (`table/src/style/select.mixin.less` + a direct
|
|
171
|
+
`@import '~antd/lib/select/style'`), since `ds-table` (out of scope, stays on antd) was the only
|
|
172
|
+
remaining consumer. ds-select ships no `dist/style` and no longer declares an `antd` peerDep.
|
|
173
|
+
- **Tests** — Vitest + React Testing Library (`src/__specs__/Select.spec.tsx`): render/parity,
|
|
174
|
+
keyboard + ARIA, and focus/blur (autofocus, onBlur on leave / not on internal move, onFocus).
|
|
175
|
+
```
|
package/README.md
CHANGED
|
@@ -3,9 +3,13 @@ id: select
|
|
|
3
3
|
title: Select
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Select UI Component
|
|
6
|
+
Select UI Component.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
A fully DS-native select (no Ant Design): a selector trigger plus a floating options
|
|
9
|
+
dropdown built on [`@synerise/ds-dropdown`](https://design.synerise.com/docs/components/dropdown)
|
|
10
|
+
(floating-ui) and `@synerise/ds-list-item`, wrapped in a `FormField` label/description/error
|
|
11
|
+
layer. Supports single-select, `multiple` (chip selector), `tags` (free-text) and in-selector
|
|
12
|
+
search, with full keyboard navigation and combobox/listbox ARIA.
|
|
9
13
|
|
|
10
14
|
## Installation
|
|
11
15
|
|
|
@@ -22,112 +26,172 @@ pnpm add @synerise/ds-select
|
|
|
22
26
|
```jsx
|
|
23
27
|
import Select from '@synerise/ds-select';
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
// Options as data
|
|
30
|
+
<Select
|
|
31
|
+
label="Platform"
|
|
32
|
+
description="Choose your platform"
|
|
33
|
+
defaultValue="insta"
|
|
34
|
+
options={[
|
|
35
|
+
{ value: 'insta', label: 'Instagram' },
|
|
36
|
+
{ value: 'fb', label: 'Facebook' },
|
|
37
|
+
]}
|
|
38
|
+
/>;
|
|
39
|
+
|
|
40
|
+
// Or declarative <Select.Option> children (read only when `options` is absent)
|
|
41
|
+
const { Option } = Select;
|
|
26
42
|
|
|
27
43
|
<Select defaultValue="insta">
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
<Option value="fb">Facebook</Option>
|
|
31
|
-
</OptGroup>
|
|
32
|
-
<OptGroup label="Followers">
|
|
33
|
-
<Option value="1M">1 Million</Option>
|
|
34
|
-
<Option value="1B">1 Billion</Option>
|
|
35
|
-
</OptGroup>
|
|
44
|
+
<Option value="insta">Instagram</Option>
|
|
45
|
+
<Option value="fb">Facebook</Option>
|
|
36
46
|
</Select>;
|
|
37
47
|
```
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<iframe src="/storybook-static/iframe.html?id=components-select-basic--default"></iframe>
|
|
49
|
+
> There is **no `OptGroup`** — the antd `Select.OptGroup` is intentionally not reimplemented.
|
|
42
50
|
|
|
43
|
-
##
|
|
51
|
+
## Examples
|
|
44
52
|
|
|
53
|
+
<iframe src="/storybook-static/iframe.html?id=components-select--default"></iframe>
|
|
45
54
|
<iframe src="/storybook-static/iframe.html?id=components-select--multiple-mode"></iframe>
|
|
55
|
+
<iframe src="/storybook-static/iframe.html?id=components-select--with-search"></iframe>
|
|
56
|
+
<iframe src="/storybook-static/iframe.html?id=components-select--tags"></iframe>
|
|
46
57
|
|
|
47
|
-
##
|
|
58
|
+
## API
|
|
48
59
|
|
|
49
|
-
|
|
60
|
+
`Select` also extends `FormFieldCommonProps` (`label`, `description`, `errorText`, `tooltip`,
|
|
61
|
+
`tooltipConfig`) and `AriaAttributes`, and forwards native `data-*` / `aria-*` attributes to the
|
|
62
|
+
select root.
|
|
63
|
+
|
|
64
|
+
### Value & selection
|
|
65
|
+
|
|
66
|
+
| Property | Description | Type | Default |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| value / defaultValue | Controlled / uncontrolled value. Array for `multiple` / `tags`. | `SelectValue` (`string \| number \| (string \| number)[]`) | - |
|
|
69
|
+
| mode | Omit for single-select; `multiple` = chips; `tags` = free-text create. | `'multiple' \| 'tags'` | - |
|
|
70
|
+
| onChange | Fired when the selection changes. | `(value, option?) => void` | - |
|
|
71
|
+
| onSelect / onDeselect | Fired when an option is added / removed. | `(value, option?) => void` | - |
|
|
72
|
+
| onClear | Fired when the clear affordance is used. | `() => void` | - |
|
|
73
|
+
| allowClear | Show a clear control (replaces the chevron on hover) when a value is set. | `boolean` | `false` |
|
|
74
|
+
| clearIcon | Custom clear icon. | `ReactNode` | - |
|
|
75
|
+
| clearTooltip | Tooltip on hover of the clear button. | `string` | - |
|
|
76
|
+
|
|
77
|
+
### Options & search
|
|
78
|
+
|
|
79
|
+
| Property | Description | Type | Default |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| options | Options as data; when absent, `<Select.Option>` children are read. | `SelectOption[]` | - |
|
|
82
|
+
| showSearch | Render an in-selector search input. | `boolean` | `false` |
|
|
83
|
+
| searchValue | Controlled search-input value (pairs with `onSearch`). | `string` | - |
|
|
84
|
+
| onSearch | Fired on each keystroke in the search input (remote search). | `(value: string) => void` | - |
|
|
85
|
+
| filterOption | Client filtering. `false` = remote (feed `options` from `onSearch`); a function = custom predicate. | `boolean \| ((input, option) => boolean)` | `true` |
|
|
86
|
+
| optionFilterProp | Option field the built-in filter matches against. | `string` | label |
|
|
87
|
+
| optionLabelProp | Option field rendered in the selector. | `string` | label |
|
|
88
|
+
| notFoundContent | Shown when there are no (filtered) options. | `ReactNode` | `'No data'` |
|
|
89
|
+
| tokenSeparators | Characters that create a tag in `tags` mode. | `string[]` | - |
|
|
90
|
+
| loading | Show a spinner inside the dropdown. | `boolean` | `false` |
|
|
91
|
+
| rowKey | Item key extractor for options / children. | `(option) => Key` | - |
|
|
92
|
+
|
|
93
|
+
### Dropdown
|
|
94
|
+
|
|
95
|
+
| Property | Description | Type | Default |
|
|
96
|
+
| --- | --- | --- | --- |
|
|
97
|
+
| open / defaultOpen | Controlled / initial dropdown visibility. | `boolean` | - |
|
|
98
|
+
| onDropdownVisibleChange | Fired when dropdown visibility changes. | `(open: boolean) => void` | - |
|
|
99
|
+
| onPopupScroll | Fired as the open option list scrolls (e.g. to page in more options). | `(event: UIEvent<HTMLDivElement>) => void` | - |
|
|
100
|
+
| getPopupContainer | Container the floating dropdown mounts into. | `(node: HTMLElement) => HTMLElement \| ParentNode \| null` | ds-utils default |
|
|
101
|
+
| placement | Dropdown placement. | `DropdownPlacement` | - |
|
|
102
|
+
| dropdownClassName / popupClassName | Class on the dropdown overlay (`popupClassName` is the antd v4 alias). | `string` | - |
|
|
103
|
+
| dropdownAlign | Dropdown alignment config (accepted for compatibility). | `object` | - |
|
|
104
|
+
| dropdownStyle | Inline style on the dropdown overlay. | `CSSProperties` | - |
|
|
105
|
+
| dropdownMatchSelectWidth | Match dropdown width to the selector; a number fixes the width (px). | `boolean \| number` | `true` |
|
|
106
|
+
| dropdownRender | Wrap the rendered option menu (custom footer / scroll container). | `(menu: ReactElement) => ReactNode` | - |
|
|
107
|
+
| listHeight | Max dropdown list height (px). | `number \| string` | `256` |
|
|
108
|
+
| listItemHeight | Fixed height per option row (accepted; list is non-virtualised). | `number` | - |
|
|
109
|
+
|
|
110
|
+
### Display & tags
|
|
111
|
+
|
|
112
|
+
| Property | Description | Type | Default |
|
|
113
|
+
| --- | --- | --- | --- |
|
|
114
|
+
| placeholder | Placeholder of the select. | `ReactNode` | - |
|
|
115
|
+
| showArrow | Show the dropdown chevron. | `boolean` | `true` |
|
|
116
|
+
| suffixIcon | Custom icon replacing the dropdown arrow. | `ReactNode` | - |
|
|
117
|
+
| maxTagCount | Max tags shown before collapsing (multiple / tags). | `number` | - |
|
|
118
|
+
| maxTagTextLength | Max characters per tag. | `number` | - |
|
|
119
|
+
| maxTagPlaceholder | Node shown for the collapsed overflow count. | `ReactNode` | - |
|
|
120
|
+
| size | Selector height. | `'default' \| 'middle' \| 'large'` | `'default'` |
|
|
121
|
+
| grey | `grey-050` selector background (when not in error state). | `boolean` | `false` |
|
|
122
|
+
|
|
123
|
+
### State & focus
|
|
124
|
+
|
|
125
|
+
| Property | Description | Type | Default |
|
|
126
|
+
| --- | --- | --- | --- |
|
|
127
|
+
| disabled | Disabled state; blocks interaction and opening. | `boolean` | `false` |
|
|
128
|
+
| readOnly | Non-interactive with readable styling (white bg, `default` cursor, `grey-600` text) instead of the disabled look. | `boolean` | - |
|
|
129
|
+
| error | Error visual state without a message. | `boolean` | - |
|
|
130
|
+
| errorText | Error message below the field; also activates the error state. | `ReactNode` | - |
|
|
131
|
+
| autoFocus | Focus the selector / search input on mount. | `boolean` | `false` |
|
|
132
|
+
| defaultActiveFirstOption | Accepted for antd back-compat; **no effect** — the dropdown always highlights the selected / first option on open. | `boolean` | - |
|
|
133
|
+
| tabIndex | Tab index forwarded to the selector / search input. | `number` | - |
|
|
134
|
+
| onFocus / onBlur | Fired when focus enters / leaves the whole select. | `(event) => void` | - |
|
|
135
|
+
| onClick | Click handler on the selector box. | `(event) => void` | - |
|
|
136
|
+
| onKeyDown / onInputKeyDown | Keydown on the selector / on the inner search input. | `(event) => void` | - |
|
|
137
|
+
|
|
138
|
+
### Layout & DS-specific
|
|
139
|
+
|
|
140
|
+
| Property | Description | Type | Default |
|
|
141
|
+
| --- | --- | --- | --- |
|
|
142
|
+
| label / description / tooltip / tooltipConfig | `FormField` chrome (label, helper text, info tooltip). | `ReactNode` / `TooltipProps` | - |
|
|
143
|
+
| prefixel / suffixel | Addon nodes attached to the left / right of the selector (shared border). | `ReactNode` | - |
|
|
144
|
+
| raw | Skip the `FormField` wrapper; render only the selector. `ref` attaches to the selector wrapper. | `boolean` | - |
|
|
145
|
+
| asFormElement | Force a 16 px bottom margin even when `errorText` / `description` are absent. | `boolean` | - |
|
|
146
|
+
| selectorStyle | Inline style object applied to the selector box. | `CSSObject` | - |
|
|
147
|
+
| style | Applied to the selector wrapper (flex row: selector + addons). | `CSSProperties` | - |
|
|
148
|
+
| className | Added to the outer container. | `string` | - |
|
|
149
|
+
| id | Forwarded to the search input. | `string` | - |
|
|
150
|
+
|
|
151
|
+
### `Select.Option` props
|
|
152
|
+
|
|
153
|
+
Marker component — renders nothing; `Select` reads its props to build the option list when the
|
|
154
|
+
`options` prop is absent.
|
|
155
|
+
|
|
156
|
+
| Property | Description | Type | Default |
|
|
157
|
+
| --- | --- | --- | --- |
|
|
158
|
+
| value | Option value. Optional — falls back to the element's React `key` when omitted. | `string \| number` | - |
|
|
159
|
+
| children | Rendered content / label of the option. | `ReactNode` | - |
|
|
160
|
+
| label | Rendered in the selector instead of `children` (antd `optionLabelProp`). | `ReactNode` | - |
|
|
161
|
+
| disabled | Disable this option. | `boolean` | `false` |
|
|
162
|
+
| title | Native hover title (any node; coerced to a string at render). | `ReactNode` | - |
|
|
163
|
+
| style | Forwarded to the rendered option row. | `CSSProperties` | - |
|
|
164
|
+
| className | Added to the option row. | `string` | - |
|
|
165
|
+
|
|
166
|
+
## Exports
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import Select, {
|
|
170
|
+
Option,
|
|
171
|
+
SelectStyles, // styled-components namespace (Selector, SelectWrapper, …)
|
|
172
|
+
getOptionsFromChildren,
|
|
173
|
+
findOption,
|
|
174
|
+
} from '@synerise/ds-select';
|
|
175
|
+
|
|
176
|
+
import type {
|
|
177
|
+
SelectProps,
|
|
178
|
+
SelectValue,
|
|
179
|
+
SelectOption,
|
|
180
|
+
SelectMode,
|
|
181
|
+
SelectHandler,
|
|
182
|
+
RawValueType,
|
|
183
|
+
FilterOptionFn,
|
|
184
|
+
OptionProps,
|
|
185
|
+
} from '@synerise/ds-select';
|
|
186
|
+
```
|
|
50
187
|
|
|
51
|
-
##
|
|
188
|
+
## Notes
|
|
52
189
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
| defaultActiveFirstOption | Whether active first option by default | boolean | `true` |
|
|
62
|
-
| defaultOpen | Initial open state of dropdown | boolean | - |
|
|
63
|
-
| defaultValue | Initial selected option. | `string` / `string[]` / `number` / `number[]` / `LabeledValue` / `LabeledValue[]` | - |
|
|
64
|
-
| description | input description | ReactNode | - |
|
|
65
|
-
| disabled | Whether disabled select | boolean | `false` |
|
|
66
|
-
| dropdownClassName | className of dropdown menu | string | - |
|
|
67
|
-
| dropdownMatchSelectWidth | Whether dropdown's width is same with select. | boolean | `true` |
|
|
68
|
-
| dropdownMenuStyle | additional style applied to dropdown menu | React.CSSProperties | - |
|
|
69
|
-
| dropdownRender | Customize dropdown content | (menuNode: React.ReactNode, props) => React.ReactNode | - |
|
|
70
|
-
| dropdownStyle | style of dropdown menu | React.CSSProperties | - |
|
|
71
|
-
| errorText | error message, if provided input will be set in error state | ReactNode | - |
|
|
72
|
-
| error | if provided input will be set in error state, without error message | boolean | - |
|
|
73
|
-
| filterOption | If true, filter options by input, if function, filter options against it. | boolean / (inputValue: string / number / LabeledValue, option: Option) => void | `true` |
|
|
74
|
-
| firstActiveValue | Value of action option by default | string or string[] | - |
|
|
75
|
-
| grey | Turn on grey background of the component | boolean | false |
|
|
76
|
-
| getPopupContainer | Parent Node which the selector should be rendered to. Default to body | (triggerNode: React.ReactNode) => void | () => document.body |
|
|
77
|
-
| label | input label | ReactNode | - |
|
|
78
|
-
| labelInValue | whether to embed label in value | boolean | `false` |
|
|
79
|
-
| loading | indicate loading state | Boolean | `false` |
|
|
80
|
-
| maxTagCount | Max tag count to show | number | - |
|
|
81
|
-
| maxTagPlaceholder | Placeholder for not showing tags | React.ReactNode/function(omittedValues) | - |
|
|
82
|
-
| maxTagTextLength | Max tag count to show | number | - |
|
|
83
|
-
| menuItemSelectedIcon | The custom menuItemSelected icon with multiple options | React.ReactNode | - |
|
|
84
|
-
| mode | Set mode of Select | `default` / `multiple` / `tags` | `default` |
|
|
85
|
-
| notFoundContent | Specify content to show when no result matches. | string | `Not Found` |
|
|
86
|
-
| onBlur | Called when blur | (e: Event) => void | - |
|
|
87
|
-
| onChange | Called when select an option or input value change, or value of input is changed in combobox mode | (value: string / number / LabeledValue, option: Option / Option[]) => void | - |
|
|
88
|
-
| onDeselect | Called when a option is deselected, param is the selected option's value. | (value: string / number / LabeledValue) => void | - |
|
|
89
|
-
| onDropdownVisibleChange | Call when dropdown open | (open: boolean) => void | - |
|
|
90
|
-
| onFocus | Called when focus | (e: Event) => void | - |
|
|
91
|
-
| onInputKeyDown | Called when key pressed | (e: Event) => void | - |
|
|
92
|
-
| onMouseEnter | Called when mouse enter | (e: Event) => void | - |
|
|
93
|
-
| onMouseLeave | Called when mouse leave | (e: Event) => void | - |
|
|
94
|
-
| onPopupScroll | Called when dropdown scrolls | (e: Event) => void | - |
|
|
95
|
-
| onSearch | Callback function that is fired when input changed. | (value: string) => void | |
|
|
96
|
-
| onSelect | Called when a option is selected, the params are option's value (or key) and option instance. | (value: string / number / LabeledValue, option:Option) => void | - |
|
|
97
|
-
| open | Controlled open state of dropdown | boolean | - |
|
|
98
|
-
| optionFilterProp | Which prop value of option will be used for filter if filterOption is `true` | string | value |
|
|
99
|
-
| optionLabelProp | Which prop value of option will render as content of select. | string | value for combobox, children for other modes |
|
|
100
|
-
| placeholder | Placeholder of select | string / React.ReactNode | - |
|
|
101
|
-
| removeIcon | The custom remove icon | React.ReactNode | - |
|
|
102
|
-
| showArrow | Whether to show the drop-down arrow | boolean | `true` |
|
|
103
|
-
| showSearch | Whether show search input in single mode. | boolean | `false` |
|
|
104
|
-
| size | Size of Select input. `default` or `large`. `small` is deprecated | string | `default` |
|
|
105
|
-
| suffixIcon | The custom suffix icon | React.ReactNode | - |
|
|
106
|
-
| tokenSeparators | Separator used to tokenize on tag/multiple mode | string[] | |
|
|
107
|
-
| tooltip | Tooltip content | React.ReactNode | - |
|
|
108
|
-
| tooltipConfig | Config of tooltip | [TooltipProps](https://design.synerise.com/docs/components/tooltip#api) | - |
|
|
109
|
-
| value | Current selected option. | `string` / `string[]` / `number` / `number[]` / `LabeledValue` / `LabeledValue[]` | - |
|
|
110
|
-
| asFormElement | Forces 16px bottom margin even when `errorText` and `description` are absent | boolean | - |
|
|
111
|
-
| clearTooltip | Tooltip text shown on hover of the clear (×) button | string | - |
|
|
112
|
-
| prefixel | Addon node attached to the left of the selector | React.ReactNode | - |
|
|
113
|
-
| raw | Skips the FormField wrapper; renders only the selector div | boolean | - |
|
|
114
|
-
| readOnly | Disables selection while using readable styling (white bg, default cursor, grey-600 text) | boolean | - |
|
|
115
|
-
| selectorStyle | Additional CSS applied to the inner `.ant-select-selector` element | CSSObject | - |
|
|
116
|
-
| suffixel | Addon node attached to the right of the selector | React.ReactNode | - |
|
|
117
|
-
|
|
118
|
-
### Option props
|
|
119
|
-
|
|
120
|
-
| Property | Description | Type | Default |
|
|
121
|
-
| --------- | -------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- |
|
|
122
|
-
| disabled | Disable this option | boolean | `false` |
|
|
123
|
-
| key | Same usage as value. If React request you to set this property, you can set it to value of option, and then omit value property. | string | |
|
|
124
|
-
| title | title of Select after select this Option | string | - |
|
|
125
|
-
| value | default to filter with this property string | number | - |
|
|
126
|
-
| className | additional class to option string | - | |
|
|
127
|
-
|
|
128
|
-
### Option group props
|
|
129
|
-
|
|
130
|
-
| Property | Description | Type | Default | |
|
|
131
|
-
| -------- | ---------------- | ------- | -------------- | --- |
|
|
132
|
-
| key | Key of an option | string | - | |
|
|
133
|
-
| label | Group label | `string | React.Element` | - |
|
|
190
|
+
- **Class hooks are `ds-select-*`** — the antd `.ant-select-*` classes are gone; target
|
|
191
|
+
`.ds-select`, `.ds-select-wrapper`, `.ds-select-selection-item`, `.ds-select-dropdown`, etc.
|
|
192
|
+
- **Remote search** — set `filterOption={false}` and update `options` from your `onSearch`
|
|
193
|
+
handler; the component won't filter locally in that mode.
|
|
194
|
+
- **Keyboard & ARIA** — Arrow / Home / End / Enter / Escape / Space (and Backspace to drop the
|
|
195
|
+
last chip in multiple mode), with combobox / listbox `aria-activedescendant`.
|
|
196
|
+
- **Not reimplemented from antd** — `OptGroup`, `labelInValue` / `LabeledValue`,
|
|
197
|
+
`autoClearSearchValue`, `firstActiveValue`, `menuItemSelectedIcon`.
|
package/dist/Option.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { RawValueType } from './Select.types';
|
|
3
|
+
export type OptionProps = {
|
|
4
|
+
/** antd parity: optional — falls back to the element's React `key` when omitted. */
|
|
5
|
+
value?: RawValueType;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
/** Native title (hover text). antd parity: accepts any node (coerced to a string title at render). */
|
|
8
|
+
title?: ReactNode;
|
|
9
|
+
/** When set, rendered in the selector instead of `children` (antd `optionLabelProp`). */
|
|
10
|
+
label?: ReactNode;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
/** antd parity: forwarded to the rendered option row. */
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
className?: string;
|
|
15
|
+
/** antd parity: native `data-*` / `aria-*` attributes, forwarded to the rendered option row. */
|
|
16
|
+
[dataAttr: `data-${string}`]: unknown;
|
|
17
|
+
[ariaAttr: `aria-${string}`]: unknown;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Declarative option marker. Renders nothing on its own — `Select` reads its
|
|
21
|
+
* props (`value`, `children` → label, `disabled`, `title`) to build the internal
|
|
22
|
+
* options list. Kept for back-compat with the antd `Select.Option` API. The antd
|
|
23
|
+
* `Select.OptGroup` is intentionally NOT reimplemented (zero real usage).
|
|
24
|
+
*/
|
|
25
|
+
export declare const Option: {
|
|
26
|
+
(_props: OptionProps): null;
|
|
27
|
+
displayName: string;
|
|
28
|
+
};
|