@synerise/ds-select 1.3.34 → 1.5.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 +27 -0
- package/CLAUDE.md +136 -92
- 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 +42 -11
- package/dist/Select.styles.js +98 -66
- package/dist/Select.types.d.ts +141 -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 +97 -0
- package/dist/hooks/useResponsiveTagCount.d.ts +27 -0
- package/dist/hooks/useResponsiveTagCount.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 +8 -5
- package/dist/assets/style/index-tn0RQdqM.css +0 -0
- package/dist/style/index.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
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.5.0](https://github.com/synerise/synerise-design/compare/@synerise/ds-select@1.4.0...@synerise/ds-select@1.5.0) (2026-08-11)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **select:** support maxTagCount="responsive" fit-to-width chips ([cb113cf](https://github.com/synerise/synerise-design/commit/cb113cf9f38a7ae112e55a8d159185f128fa2e4a))
|
|
11
|
+
|
|
12
|
+
# [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)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- **select:** add onKeyDown, maxLength, dropdownAlign, popupClassName, maxTagPlaceholder ([1cf5f39](https://github.com/synerise/synerise-design/commit/1cf5f394055c10caee8b2bef81c83d04e19dcd6e))
|
|
17
|
+
- **select:** add suffixIcon, tabIndex, option style/children parity shims ([10c0bbc](https://github.com/synerise/synerise-design/commit/10c0bbc584534f7950bd5093764d9363a526149b))
|
|
18
|
+
- **select:** color clear/remove icons via currentColor, not svg fill ([0573124](https://github.com/synerise/synerise-design/commit/05731249ebc2d6d291879f0cb0f7443d8966a2b6))
|
|
19
|
+
- **select:** fire onFocus/onBlur and split render into sub-components ([44f73ec](https://github.com/synerise/synerise-design/commit/44f73ec0dc705c920950048acfa61ea108ec8072))
|
|
20
|
+
- **select:** forward data-_ and aria-_ attributes to the select root ([49294a8](https://github.com/synerise/synerise-design/commit/49294a8b1ab2b17967fc9d8ce9879eb48c5844cb))
|
|
21
|
+
- **select:** mark the current option selected via ListItem selected prop ([b5cb80a](https://github.com/synerise/synerise-design/commit/b5cb80a9d6e8a0411752a58fb0e66770f5c19408))
|
|
22
|
+
- **select:** move onClick off the dropdown trigger; focus inputs in interaction tests ([ed1a79c](https://github.com/synerise/synerise-design/commit/ed1a79c45bf056304a11e959ceb086dc1258b55e))
|
|
23
|
+
- **select:** multiple chip keeps its label-defined width; X squeezes label on hover ([5c9908d](https://github.com/synerise/synerise-design/commit/5c9908d8ff86119aa3948a1f366497827598bd3d))
|
|
24
|
+
- **select:** overlay search input and blur it on selection ([f312354](https://github.com/synerise/synerise-design/commit/f31235487542b29f31b2435c2b9951716803d20c))
|
|
25
|
+
- **select:** restore antd-parity props for consumer back-compat ([ceac672](https://github.com/synerise/synerise-design/commit/ceac6729c4c4815ee918a927a98aa17de0407e8d))
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
- **select:** forward per-option data-_/aria-_ to the rendered option row ([1a8162d](https://github.com/synerise/synerise-design/commit/1a8162d9dae98a5cf96b0f35f70f9148eb025e88))
|
|
30
|
+
- **select:** implement maxTagCount/maxTagTextLength/maxTagPlaceholder + onPopupScroll ([060d2c6](https://github.com/synerise/synerise-design/commit/060d2c6b74118c065d928786dad67aa1b88500c7))
|
|
31
|
+
- **select:** keyboard-arrow option navigation + combobox/listbox ARIA ([74e5466](https://github.com/synerise/synerise-design/commit/74e5466b23dc2d062c0bd734cc84334f55b99ab8))
|
|
32
|
+
|
|
6
33
|
## [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)
|
|
7
34
|
|
|
8
35
|
**Note:** Version bump only for package @synerise/ds-select
|
package/CLAUDE.md
CHANGED
|
@@ -1,140 +1,184 @@
|
|
|
1
1
|
# Select (`@synerise/ds-select`)
|
|
2
2
|
|
|
3
|
-
> A DS-
|
|
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.
|
|
4
7
|
|
|
5
8
|
## Package structure
|
|
6
9
|
|
|
7
10
|
```
|
|
8
11
|
src/
|
|
9
|
-
Select.tsx — main component (forwardRef, compound with .Option
|
|
10
|
-
Select.types.ts —
|
|
11
|
-
Select.styles.ts — styled-components
|
|
12
|
-
|
|
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
|
|
13
18
|
modules.d.ts — imports @testing-library/jest-dom
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
hooks/
|
|
20
|
+
useSelectOptions.ts — resolve options (prop → children), client filtering, tags create-row
|
|
21
|
+
useResponsiveTagCount.ts — maxTagCount="responsive": fit-to-width chip count (ResizeObserver)
|
|
22
|
+
components/
|
|
23
|
+
OptionList.tsx — dropdown overlay: loading / empty / scrollable listbox of options
|
|
24
|
+
SelectorContent.tsx — selector inner content: chips / selected label / placeholder + search input
|
|
25
|
+
utils/
|
|
26
|
+
getOptionsFromChildren.ts — read <Select.Option> children into SelectOption[]; findOption()
|
|
27
|
+
helpers.ts — cx(), toArray(), defaultFilter(), DEFAULT_LIST_HEIGHT
|
|
17
28
|
__specs__/
|
|
18
|
-
|
|
29
|
+
Select.spec.tsx — Vitest + React Testing Library tests
|
|
19
30
|
```
|
|
20
31
|
|
|
32
|
+
> No `style/` dir and no `antd` peerDep — the component is styled purely with styled-components. The
|
|
33
|
+
> old antd-era LESS (`select.mixin.less`, `.ant-select-*` overrides) was relocated to `ds-table`
|
|
34
|
+
> (`table/src/style/`), the only consumer that still renders antd selects.
|
|
35
|
+
|
|
21
36
|
## Public exports
|
|
22
37
|
|
|
23
38
|
```ts
|
|
24
|
-
export default
|
|
25
|
-
export
|
|
39
|
+
export { default } from './Select'; // compound: Select + .Option
|
|
40
|
+
export { Option, type OptionProps } from './Option';
|
|
41
|
+
export type {
|
|
42
|
+
Props, SelectProps, SelectValue, SelectOption, SelectMode,
|
|
43
|
+
SelectHandler, RawValueType, FilterOptionFn,
|
|
44
|
+
} from './Select.types';
|
|
26
45
|
export * as SelectStyles from './Select.styles';
|
|
46
|
+
export { getOptionsFromChildren, findOption } from './utils/getOptionsFromChildren';
|
|
27
47
|
```
|
|
28
48
|
|
|
29
49
|
### `Select` (default)
|
|
30
50
|
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
|
|
51
|
+
`forwardRef<HTMLDivElement, SelectProps>`, augmented into a compound component with a single
|
|
52
|
+
sub-component: **`Select.Option`** (the DS `Option` marker). `Select.OptGroup` is intentionally
|
|
53
|
+
**not** reimplemented (zero real usage).
|
|
34
54
|
|
|
35
|
-
|
|
55
|
+
`SelectValue = string | number | (string | number)[] | undefined` — antd-free (no `LabeledValue`).
|
|
36
56
|
|
|
37
57
|
#### DS-specific props
|
|
38
58
|
|
|
39
59
|
| Prop | Type | Default | Description |
|
|
40
60
|
|------|------|---------|-------------|
|
|
41
|
-
| `label` | `ReactNode` | `undefined` |
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
| `label` / `description` / `tooltip` / `tooltipConfig` | `ReactNode` / `TooltipProps` | `undefined` | `FormField` chrome (from `FormFieldCommonProps`). |
|
|
62
|
+
| `errorText` | `ReactNode` | `undefined` | Error message below the field; also activates the error visual state. |
|
|
63
|
+
| `error` | `boolean` | `undefined` | Error visual state without a message. |
|
|
64
|
+
| `clearTooltip` | `string` | `undefined` | Tooltip on hover of the clear (×) control. |
|
|
65
|
+
| `prefixel` / `suffixel` | `ReactNode` | `undefined` | Addon nodes attached left/right of the selector (shared border). |
|
|
66
|
+
| `grey` | `boolean` | `undefined` | `grey-050` selector background when not in error state. |
|
|
67
|
+
| `asFormElement` | `boolean` | `undefined` | Forces a 16 px bottom margin even without `errorText`/`description`. |
|
|
68
|
+
| `raw` | `boolean` | `undefined` | Skips the `FormField` wrapper — renders only the selector; `ref` attaches to `SelectWrapper`. |
|
|
69
|
+
| `readOnly` | `boolean` | `undefined` | Non-interactive with readable styling (white bg, `default` cursor, `grey-600` text). |
|
|
70
|
+
| `disabled` | `boolean` | `undefined` | Standard disabled state; ORed with `readOnly` to block interaction. |
|
|
71
|
+
| `selectorStyle` | `CSSObject` | `undefined` | Inline style object applied to the `Selector` box. |
|
|
72
|
+
| `listHeight` | `number \| string` | `256` | Max dropdown list height (px). |
|
|
73
|
+
| `style` | `CSSProperties` | `undefined` | Applied to `SelectWrapper` (the flex row: selector + addons). |
|
|
74
|
+
| `className` | `string` | `undefined` | Added to the outer `SelectContainer`. |
|
|
75
|
+
| `getPopupContainer` | `(node) => HTMLElement \| ParentNode \| null` | `defaultGetPopupContainer` (`@synerise/ds-utils`) | Container the dropdown mounts into. |
|
|
76
|
+
| `size` | `'default' \| 'middle' \| 'large'` | `'default'` | Selector height (`middle` maps to `default`). |
|
|
77
|
+
|
|
78
|
+
Native `data-*` / `aria-*` attributes are forwarded onto the select root (`.ds-select-wrapper`).
|
|
79
|
+
|
|
80
|
+
#### antd-parity props (additive back-compat)
|
|
81
|
+
|
|
82
|
+
Kept so antd-era consumers need no change: `searchValue`, `onClear`, `onClick`, `onInputKeyDown`,
|
|
83
|
+
`onKeyDown`, `suffixIcon`, `clearIcon`, `maxLength`, `maxTagCount`, `maxTagTextLength`,
|
|
84
|
+
`maxTagPlaceholder`, `onPopupScroll`, `popupClassName` (alias of `dropdownClassName`),
|
|
85
|
+
`dropdownMatchSelectWidth` (`boolean | number`), `dropdownRender`, `showArrow`,
|
|
86
|
+
`autoFocus`, `tabIndex`, `rowKey`, plus the standard
|
|
87
|
+
`mode`/`options`/`showSearch`/`filterOption`/`allowClear`/`open`/`onChange`/`onSearch`/… surface.
|
|
88
|
+
`SelectHandler` type and the `SelectStyles.Selector` styled export are re-exported for parity.
|
|
89
|
+
|
|
90
|
+
`maxTagCount` (`number | 'responsive'` — collapse extra chips into a `+N` overflow chip, or fit them
|
|
91
|
+
to the selector width on one line), `maxTagTextLength` (truncate chip labels) and `onPopupScroll` are
|
|
92
|
+
fully implemented. `listItemHeight`, `dropdownAlign` and `defaultActiveFirstOption` are accepted for
|
|
93
|
+
compatibility but have **no runtime effect**.
|
|
62
94
|
|
|
63
95
|
## Usage patterns
|
|
64
96
|
|
|
65
97
|
```tsx
|
|
66
98
|
import Select from '@synerise/ds-select';
|
|
67
99
|
|
|
68
|
-
const { Option
|
|
69
|
-
|
|
70
|
-
// Basic with FormField label / description
|
|
71
|
-
<Select label="Platform" description="Choose your platform" defaultValue="insta">
|
|
72
|
-
<OptGroup label="Social">
|
|
73
|
-
<Option value="insta">Instagram</Option>
|
|
74
|
-
<Option value="fb">Facebook</Option>
|
|
75
|
-
</OptGroup>
|
|
76
|
-
</Select>
|
|
77
|
-
|
|
78
|
-
// Multiple mode
|
|
79
|
-
<Select mode="multiple" placeholder="Select tags" allowClear>
|
|
80
|
-
<Option value="a">Alpha</Option>
|
|
81
|
-
<Option value="b">Beta</Option>
|
|
82
|
-
</Select>
|
|
100
|
+
const { Option } = Select;
|
|
83
101
|
|
|
84
|
-
//
|
|
85
|
-
<Select
|
|
102
|
+
// Options as data (preferred)
|
|
103
|
+
<Select label="Platform" options={[{ value: 'insta', label: 'Instagram' }]} defaultValue="insta" />
|
|
86
104
|
|
|
87
|
-
//
|
|
88
|
-
<Select
|
|
105
|
+
// Declarative children (read only when `options` is absent)
|
|
106
|
+
<Select label="Platform"><Option value="insta">Instagram</Option></Select>
|
|
89
107
|
|
|
90
|
-
//
|
|
91
|
-
<Select
|
|
108
|
+
// Multiple (removable chips) / tags (free-text) / search
|
|
109
|
+
<Select mode="multiple" placeholder="Select tags" allowClear options={opts} />
|
|
110
|
+
<Select mode="tags" tokenSeparators={[',']} />
|
|
111
|
+
<Select showSearch filterOption optionFilterProp="label" options={opts} />
|
|
92
112
|
|
|
93
|
-
//
|
|
94
|
-
<Select
|
|
113
|
+
// Remote search: filter server-side, feed options from onSearch
|
|
114
|
+
<Select showSearch filterOption={false} onSearch={fetchOptions} options={opts} />
|
|
95
115
|
|
|
96
|
-
//
|
|
116
|
+
// readOnly / raw / prefix-suffix
|
|
117
|
+
<Select readOnly value="locked" />
|
|
97
118
|
<Select raw ref={myRef} placeholder="Compact" />
|
|
98
|
-
|
|
99
|
-
// Prefix / suffix addons
|
|
100
119
|
<Select prefixel={<span>$</span>} suffixel={<span>USD</span>} />
|
|
101
|
-
|
|
102
|
-
// Clear button tooltip
|
|
103
|
-
<Select allowClear clearTooltip="Clear selection" />
|
|
104
120
|
```
|
|
105
121
|
|
|
106
122
|
## Styling
|
|
107
123
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
**styled-components (`Select.styles.ts`) is the source of truth.** Key styled parts:
|
|
125
|
+
- `SelectContainer` — column flex; adds a 16 px bottom margin when `hasBottomMargin`.
|
|
126
|
+
- `SelectWrapper` (`.ds-select-wrapper`) — the flex row (selector + addons); carries the root
|
|
127
|
+
`onFocus`/`onBlur`/`onClick` and `data-*`/`aria-*` passthrough.
|
|
128
|
+
- `Selector` (`.ds-select`) — the trigger box; `large` height, `withPrefixel`/`withSuffixel`
|
|
129
|
+
border-radius removal, open/focus ring (`blue-600`/`blue-050`), error (`red-600`/`red-050`),
|
|
130
|
+
`readOnly` vs `disabled` differentiation, and the `selectorStyle` interpolation.
|
|
131
|
+
- `PrefixWrapper` / `SuffixWrapper` — `grey-050` addons with flush border join.
|
|
132
|
+
- Dropdown / options: `DropdownWrapper`, `ScrollList`, `Inner` (`role="listbox"`), `OptionItem`
|
|
133
|
+
(styled `ds-list-item`), `NotFound`, `Loading`. Selector content: `SelectionItem`, `Placeholder`,
|
|
134
|
+
`MultiValueArea`, `Chip`/`ChipLabel`/`ChipRemove`, `Arrow`, `ClearWrapper`, `SearchInputEl`.
|
|
135
|
+
|
|
136
|
+
Class hooks are `ds-select-*` (`.ds-select`, `.ds-select-selection-item`, `.ds-select-dropdown`,
|
|
137
|
+
`.ds-select-arrow`, `.ds-select-clear`, `.ds-select-search`, …).
|
|
121
138
|
|
|
122
139
|
## Key dependencies
|
|
123
140
|
|
|
124
|
-
-
|
|
125
|
-
- `@synerise/ds-
|
|
126
|
-
- `@synerise/ds-
|
|
127
|
-
- `@synerise/ds-
|
|
128
|
-
- `@synerise/ds-
|
|
129
|
-
- `@synerise/ds-
|
|
141
|
+
- `@synerise/ds-dropdown` — floating-ui popover positioning + overlay (the `Selector` is the `asChild` trigger).
|
|
142
|
+
- `@synerise/ds-list-item` — the option row (`OptionItem`) and list wrapper (`ScrollList`).
|
|
143
|
+
- `@synerise/ds-scrollbar` / `@synerise/ds-loader` — dropdown scroll container / loading spinner.
|
|
144
|
+
- `@synerise/ds-form-field` — label / description / error layout (skipped when `raw`).
|
|
145
|
+
- `@synerise/ds-icon` — `AngleDownS` (arrow), `Close3M` (clear), `CloseS` (chip remove).
|
|
146
|
+
- `@synerise/ds-tooltip` — wraps the clear control for `clearTooltip`.
|
|
147
|
+
- `@synerise/ds-utils` — default `getPopupContainer`.
|
|
148
|
+
- `@synerise/ds-core` — theme tokens (peerDep). **No `antd` peerDep** — the component imports zero
|
|
149
|
+
antd; the LESS that pulled `~antd/lib/select/style` was relocated to `ds-table` (see below).
|
|
130
150
|
|
|
131
151
|
## Implementation notes
|
|
132
152
|
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- **`
|
|
137
|
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
153
|
+
- **Option resolution** — `useSelectOptions` returns `resolvedOptions` (from `options` prop, else
|
|
154
|
+
`getOptionsFromChildren(children)`) and `displayedOptions` (after client filtering and, in `tags`
|
|
155
|
+
mode, a create-row prepended for the typed text). `filterOption={false}` disables local filtering.
|
|
156
|
+
- **`Option.value` is optional** — falls back to the element's React `key` (antd parity); callbacks
|
|
157
|
+
expose `option.key`.
|
|
158
|
+
- **Keyboard nav is hand-rolled (not ds-dropdown's)** — Select is a *combobox*: focus stays on the
|
|
159
|
+
input/selector via `aria-activedescendant`, whereas ds-dropdown uses roving DOM focus. `activeIndex`
|
|
160
|
+
+ `moveActive` + three effects drive highlight; `handleKeyDown` handles Arrow/Home/End/Enter/Escape/
|
|
161
|
+
Space and Backspace (drop last chip).
|
|
162
|
+
- **Focus / blur** — `onFocus`/`onBlur` fire on the root only when focus truly enters/leaves the
|
|
163
|
+
select (relatedTarget guard ignores selector↔input moves). `autoFocus` focuses the `Selector` in
|
|
164
|
+
select-only mode (no search input to receive it). The dropdown `onMouseDown` prevents focus loss so
|
|
165
|
+
selecting an option / scrolling isn't treated as a blur (needed by `subtle-form`'s revert-on-blur).
|
|
166
|
+
- **`readOnly` is implemented via `disabled`** — both flags are ORed into `isDisabled`; the visual
|
|
167
|
+
distinction comes from the `$readOnly` transient prop on `Selector`.
|
|
168
|
+
- **`maxTagCount="responsive"`** — `useResponsiveTagCount` measures an off-flow ghost row
|
|
169
|
+
(`TagMeasureRow`, one hidden chip per value + a worst-case `+N` chip) rather than the visible
|
|
170
|
+
chips: a hidden chip would measure 0, and the ghost's width never depends on the count derived
|
|
171
|
+
from it, so the `ResizeObserver` (on the chip row *and* the ghosts, for font/label changes) can't
|
|
172
|
+
feed itself. The row switches to `nowrap` and reserves 30 px of caret room unless disabled/readOnly.
|
|
173
|
+
Unmeasurable layout (SSR, `display: none`, no `ResizeObserver` → `window.resize` fallback) degrades
|
|
174
|
+
to showing every chip; a lone oversized chip ellipsis-clips instead of collapsing into `+ 1`.
|
|
175
|
+
- **Controlled/uncontrolled** — `value`/`open`/`searchValue` are controlled when defined, else backed
|
|
176
|
+
by internal state; `onSearch` still fires when `searchValue` is controlled.
|
|
177
|
+
- **antd-free; no LESS** — styling is entirely styled-components. The old antd-era LESS
|
|
178
|
+
(`style/index.less` + `select.mixin.less`, `.ant-select-*` overrides for antd selects) was
|
|
179
|
+
**relocated to `ds-table`** (`table/src/style/select.mixin.less` + a direct
|
|
180
|
+
`@import '~antd/lib/select/style'`), since `ds-table` (out of scope, stays on antd) was the only
|
|
181
|
+
remaining consumer. ds-select ships no `dist/style` and no longer declares an `antd` peerDep.
|
|
182
|
+
- **Tests** — Vitest + React Testing Library (`src/__specs__/Select.spec.tsx`): render/parity,
|
|
183
|
+
keyboard + ARIA, and focus/blur (autofocus, onBlur on leave / not on internal move, onFocus).
|
|
184
|
+
```
|