@synerise/ds-context-selector 1.3.42 → 1.3.44
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 +8 -0
- package/CLAUDE.md +186 -0
- package/package.json +16 -15
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.3.44](https://github.com/Synerise/synerise-design/compare/@synerise/ds-context-selector@1.3.43...@synerise/ds-context-selector@1.3.44) (2026-07-23)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @synerise/ds-context-selector
|
|
9
|
+
|
|
10
|
+
## [1.3.43](https://github.com/Synerise/synerise-design/compare/@synerise/ds-context-selector@1.3.42...@synerise/ds-context-selector@1.3.43) (2026-07-16)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @synerise/ds-context-selector
|
|
13
|
+
|
|
6
14
|
## [1.3.42](https://github.com/Synerise/synerise-design/compare/@synerise/ds-context-selector@1.3.41...@synerise/ds-context-selector@1.3.42) (2026-07-09)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @synerise/ds-context-selector
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# ContextSelector (`@synerise/ds-context-selector`)
|
|
2
|
+
|
|
3
|
+
> A dropdown-based selector for structured, grouped data (e.g. events, attributes, segments) with tabs, sub-group navigation, search, virtualized list rendering, and a hover info-card on the selected trigger.
|
|
4
|
+
|
|
5
|
+
## Package structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/
|
|
9
|
+
ContextSelector.tsx — main component; trigger button + Dropdown wrapper
|
|
10
|
+
ContextSelector.types.ts — all prop interfaces and shared types
|
|
11
|
+
ContextSelector.styles.ts — styled-components for dropdown internals
|
|
12
|
+
ContextSelectorDropdown/
|
|
13
|
+
ContextSelectorDropdown.tsx — dropdown overlay; tabs, search, virtualized list
|
|
14
|
+
ContextSelectorDropdownItem.tsx — single list row (wraps ds-list-item)
|
|
15
|
+
utils.ts — isListTitle, isGroup type guards
|
|
16
|
+
hooks/
|
|
17
|
+
useTexts.ts — merges i18n defaults with caller-provided texts
|
|
18
|
+
constants.ts — dropdown heights, item sizes
|
|
19
|
+
index.ts — public exports
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Public exports
|
|
23
|
+
|
|
24
|
+
### `ContextSelector` (default)
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Description |
|
|
27
|
+
|------|------|---------|-------------|
|
|
28
|
+
| `groups` | `ContextGroup[]` | — | **Required.** Defines top-level tabs when length > 1. |
|
|
29
|
+
| `items` | `ContextItem[]` | — | **Required.** All selectable leaf items. |
|
|
30
|
+
| `onSelectItem` | `(item: ContextItem \| ContextGroup \| undefined) => void` | — | **Required.** Called on item selection; dropdown closes. |
|
|
31
|
+
| `selectedItem` | `ContextItem \| undefined` | `undefined` | Currently selected item. Changes trigger button appearance. |
|
|
32
|
+
| `texts` | `Partial<ContextTexts>` | i18n defaults | Override any label text. Falls back to `react-intl` formatted messages. |
|
|
33
|
+
| `type` | `'default' \| 'attribute' \| 'event'` | `undefined` | Controls trigger colour when an item is selected: `'event'` → `cyan`, others → `green`. |
|
|
34
|
+
| `readOnly` | `boolean` | `false` | Skips the `Dropdown` entirely; renders only the trigger (no click handler). |
|
|
35
|
+
| `disabled` | `boolean` | `undefined` | Passes `disabled` to the trigger button. |
|
|
36
|
+
| `addMode` | `boolean` | `undefined` | When no item is selected, shows a primary `+` button instead of the colour-coded trigger. |
|
|
37
|
+
| `loading` | `boolean` | `undefined` | Shows a skeleton in the dropdown body. |
|
|
38
|
+
| `recentItems` | `ContextItem[]` | `undefined` | When provided and groups has ≤1 entry, items are split into "Recent" / "All" sections. |
|
|
39
|
+
| `defaultDropdownVisibility` | `boolean` | `false` | Initial open state; also re-synced via effect when the value changes. |
|
|
40
|
+
| `opened` | `boolean` | `undefined` | One-way external open trigger — setting to `true` opens the dropdown. |
|
|
41
|
+
| `onOpen` | `() => void` | `undefined` | Called when trigger button is clicked (before dropdown opens). |
|
|
42
|
+
| `onActivate` | `(fieldType: string) => void` | `undefined` | Called when dropdown becomes visible (receives empty string). |
|
|
43
|
+
| `onDeactivate` | `() => void` | `undefined` | Called on dropdown dismiss. |
|
|
44
|
+
| `onSetGroup` | `(item: ContextItem \| ContextGroup \| undefined) => void` | `undefined` | Called when a sub-group row is clicked (navigation into sub-group). |
|
|
45
|
+
| `onSearch` | `(query: string) => void` | `undefined` | Enables server-side search. When provided, client-side filtering is disabled. |
|
|
46
|
+
| `hideSearchField` | `boolean` | `false` | Hides the search input inside the dropdown. |
|
|
47
|
+
| `onFetchData` | `() => void` | `undefined` | Called when scrollbar reaches the bottom (infinite scroll). |
|
|
48
|
+
| `hasMoreItems` | `boolean` | `undefined` | Required for infinite scroll to fire `onFetchData`. |
|
|
49
|
+
| `onClickOutside` | `() => void` | `undefined` | Called on outside-press dismiss. |
|
|
50
|
+
| `onClickOutsideEvents` | `HandledEventsType[]` | `undefined` | Overrides the event types watched for outside-press. |
|
|
51
|
+
| `menuItemHeight` | `ItemSize` | `ItemSize.DEFAULT` | Height of each dropdown row: `'large'` (50px) or `'default'` (32px). |
|
|
52
|
+
| `dropdownWrapperStyles` | `CSSProperties` | `undefined` | Inline styles applied to `Dropdown.Wrapper`. |
|
|
53
|
+
| `customTriggerComponent` | `ReactNode` | `undefined` | Replaces the built-in trigger button entirely. |
|
|
54
|
+
| `trigger` | `PopoverTriggerType \| PopoverTriggerType[]` | `['click']` | Dropdown open trigger event(s). |
|
|
55
|
+
| `getPopupContainerOverride` | `(trigger: HTMLElement \| null) => HTMLElement` | `getPopupContainer` | Overrides popup container for both the dropdown and inner tooltips. |
|
|
56
|
+
| `dropdownProps` | `Omit<DropdownSharedProps, 'trigger' \| 'getPopupContainer' \| 'overlay' \| 'children'>` | `undefined` | Extra props forwarded to `ds-dropdown`. |
|
|
57
|
+
| `errorText` | `ReactNode` | `undefined` | Error message rendered below the component; also triggers error styling on the trigger. |
|
|
58
|
+
| `isError` | `boolean` | `undefined` | Shows error styling without a message. |
|
|
59
|
+
| `popoverDelay` | `DelayConfig` | `undefined` | Passed via `ListContextProvider` to all list item hover popovers. |
|
|
60
|
+
| `dropdownDimensionsConfig` | `{ defaultHeight?: number; lowerHeight?: number; threshold?: number }` | `{ 420, 350, 900 }` | Overrides responsive height thresholds (px). |
|
|
61
|
+
|
|
62
|
+
### Types
|
|
63
|
+
|
|
64
|
+
| Export | Description |
|
|
65
|
+
|--------|-------------|
|
|
66
|
+
| `ContextProps` | Full props for `ContextSelector` |
|
|
67
|
+
| `ContextItem` | A selectable leaf item (see below) |
|
|
68
|
+
| `ContextGroup` | A group / tab header (see below) |
|
|
69
|
+
| `ContextTexts` | Shape of the `texts` prop |
|
|
70
|
+
| `ContextDropdownProps` | Props for the internal `ContextSelectorDropdown` (not for external use) |
|
|
71
|
+
| `ContextSelectorDropdownItemProps` | Props for the internal list row (not for external use) |
|
|
72
|
+
| `ContextItemsInSubGroup` | `ContextItem & { isGroup?: boolean }` — internal navigation marker |
|
|
73
|
+
| `DropdownItemProps` | Union of all virtual-list row types |
|
|
74
|
+
|
|
75
|
+
#### `ContextItem` shape
|
|
76
|
+
|
|
77
|
+
| Field | Type | Required | Description |
|
|
78
|
+
|-------|------|----------|-------------|
|
|
79
|
+
| `id` | `ReactText \| null` | Yes | Unique identifier |
|
|
80
|
+
| `name` | `string` | Yes | Display label |
|
|
81
|
+
| `icon` | `ReactNode` | Yes | Icon shown in list and trigger |
|
|
82
|
+
| `groupId` | `ReactText` | No | Ties item to a `ContextGroup` |
|
|
83
|
+
| `groupName` | `string` | No | Used as section header when no tab groups |
|
|
84
|
+
| `subGroups` | `ContextGroup[]` | No | Nested sub-groups |
|
|
85
|
+
| `description` | `ReactNode` | No | Shown below name (use with `menuItemHeight="large"`) |
|
|
86
|
+
| `subtitle` | `string` | No | Shown in the hover info-card |
|
|
87
|
+
| `value` | `ReactText \| null` | No | Alternative value (not used in selection logic) |
|
|
88
|
+
| `customSuffix` | `ReactNode` | No | Replaces the check-mark suffix |
|
|
89
|
+
| `useCustomIcon` | `boolean` | No | Renders `icon` directly instead of wrapping in `<Icon>` |
|
|
90
|
+
| `excludeFromSearchResults` | `boolean` | No | Excludes item from client-side search |
|
|
91
|
+
| `informationCardProps` | `Partial<InformationCardProps>` | No | Overrides props on the hover info-card |
|
|
92
|
+
| `renderAdditionalDescription` | `() => ReactNode` | No | Extra content in hover info-card |
|
|
93
|
+
| `renderHoverTooltip` | `() => ReactNode` | No | Replaces the entire hover info-card |
|
|
94
|
+
| `popoverProps` / `disabled` | (from `ListItemProps`) | No | Forwarded to the underlying `ds-list-item` |
|
|
95
|
+
|
|
96
|
+
#### `ContextGroup` shape
|
|
97
|
+
|
|
98
|
+
| Field | Type | Required | Description |
|
|
99
|
+
|-------|------|----------|-------------|
|
|
100
|
+
| `id` | `ReactText` | Yes | Unique identifier; matched against `ContextItem.groupId` |
|
|
101
|
+
| `name` | `string` | Yes | Tab label |
|
|
102
|
+
| `defaultGroup` | `boolean` | No | Marks which tab is active on open |
|
|
103
|
+
| `icon` | `ReactNode` | No | Icon in sub-group list row |
|
|
104
|
+
| `subGroups` | `ContextGroup[]` | No | Enables sub-group navigation within a tab |
|
|
105
|
+
| `description` | `ReactNode` | No | Row description |
|
|
106
|
+
| `tooltip` | `string` | No | Tooltip on the group row |
|
|
107
|
+
| `itemType` / `customSuffix` / `useCustomIcon` | — | No | Same semantics as `ContextItem` |
|
|
108
|
+
|
|
109
|
+
## Usage patterns
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import ContextSelector from '@synerise/ds-context-selector';
|
|
113
|
+
|
|
114
|
+
// Minimal (with react-intl IntlProvider in the tree)
|
|
115
|
+
<ContextSelector
|
|
116
|
+
groups={[{ id: 'all', name: 'All', defaultGroup: true }]}
|
|
117
|
+
items={[{ id: 1, name: 'Revenue', icon: <ChartLineM />, groupId: 'all' }]}
|
|
118
|
+
onSelectItem={(item) => setSelected(item)}
|
|
119
|
+
selectedItem={selected}
|
|
120
|
+
/>
|
|
121
|
+
|
|
122
|
+
// With tabs (groups.length > 1 renders tabs)
|
|
123
|
+
<ContextSelector
|
|
124
|
+
groups={[
|
|
125
|
+
{ id: 'events', name: 'Events', defaultGroup: true },
|
|
126
|
+
{ id: 'attrs', name: 'Attributes' },
|
|
127
|
+
]}
|
|
128
|
+
items={items}
|
|
129
|
+
onSelectItem={handleSelect}
|
|
130
|
+
type="event"
|
|
131
|
+
/>
|
|
132
|
+
|
|
133
|
+
// Server-side search + infinite scroll
|
|
134
|
+
<ContextSelector
|
|
135
|
+
groups={groups}
|
|
136
|
+
items={items}
|
|
137
|
+
onSelectItem={handleSelect}
|
|
138
|
+
onSearch={handleSearch}
|
|
139
|
+
onFetchData={fetchNextPage}
|
|
140
|
+
hasMoreItems={hasMore}
|
|
141
|
+
loading={isLoading}
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
// ReadOnly — renders trigger only, no dropdown
|
|
145
|
+
<ContextSelector
|
|
146
|
+
groups={[]} items={[]}
|
|
147
|
+
onSelectItem={() => {}}
|
|
148
|
+
selectedItem={selected}
|
|
149
|
+
readOnly
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Custom hook
|
|
154
|
+
|
|
155
|
+
### `useTexts`
|
|
156
|
+
|
|
157
|
+
Merges i18n defaults (via `react-intl` `useIntl`) with caller-provided `Partial<ContextTexts>`. Returns a complete `ContextTexts` object.
|
|
158
|
+
|
|
159
|
+
**Requires `IntlProvider` in the React tree.** If no custom texts are provided, defaults are: `buttonLabel='Choose'`, `searchPlaceholder='Search'`, `noResults='No results'`, `showMore='Show more'`, `recentItemsGroupName='Recent'`, `allItemsGroupName='All'`.
|
|
160
|
+
|
|
161
|
+
## Styling
|
|
162
|
+
|
|
163
|
+
`ContextSelector.styles.ts` exports internal building blocks (`ItemsList`, `Title`, `ErrorWrapper`, `Skeleton`, etc.). Uses `@synerise/ds-core` theme palette tokens. No variant/theme prop pattern on the styles themselves — visual variants are controlled by props (`type`, `readOnly`, `addMode`).
|
|
164
|
+
|
|
165
|
+
## Key dependencies
|
|
166
|
+
|
|
167
|
+
- `@synerise/ds-dropdown` — outer `Dropdown` and `Dropdown.Wrapper` / `SearchInput` / `BackAction`
|
|
168
|
+
- `@synerise/ds-button` — trigger button with `custom-color`, `primary` modes
|
|
169
|
+
- `@synerise/ds-information-card` — hover card shown on the selected item trigger
|
|
170
|
+
- `@synerise/ds-list-item` — each dropdown row; `ListContextProvider` distributes `popoverDelay`
|
|
171
|
+
- `react-window` (`VariableSizeList`) — virtualised rendering of dropdown items
|
|
172
|
+
- `@synerise/ds-tabs` — tab bar when `groups.length > 1`
|
|
173
|
+
- `@synerise/ds-utils` — `useSearchResults` (client-side search), `focusWithArrowKeys`, `getClosest`
|
|
174
|
+
- `react-intl` — i18n for default text labels (peer requirement via `useTexts`)
|
|
175
|
+
- `uuid` — generates unique CSS class names for keyboard focus management in the list
|
|
176
|
+
|
|
177
|
+
## Implementation notes
|
|
178
|
+
|
|
179
|
+
- **`readOnly` short-circuits the entire Dropdown** — the component returns only the trigger when `readOnly=true`. No dropdown is mounted, no event listeners are attached.
|
|
180
|
+
- **Dismiss ignores `.ds-info-card` clicks** — the `dismissConfig.outsidePress` handler checks `getClosest(target, '.ds-info-card')`; clicks inside the hover info-card do not close the dropdown.
|
|
181
|
+
- **`opened` is one-way** — setting `opened=true` opens the dropdown but the component manages its own closed state internally. Setting `opened` back to `false` does nothing.
|
|
182
|
+
- **Viewport height adaptation** — a `resize` event listener adjusts dropdown height: `< 900px` → 350px, otherwise 420px. Override via `dropdownDimensionsConfig`.
|
|
183
|
+
- **`maxSearchResultsInGroup`** — hard-coded default of `4` inside `ContextSelectorDropdown`; not exposed through `ContextProps`.
|
|
184
|
+
- **Sub-group navigation resets on select** — selecting any item clears `activeGroup` and resets `activeTab` to the `defaultGroup` index.
|
|
185
|
+
- **`uuid` per render instance** — a unique CSS class is generated once per `ContextSelectorDropdown` mount and used for keyboard arrow-key focus management between search input and list items.
|
|
186
|
+
- **`@ts-expect-error` in groupByGroupName** — `groupName` is not on the `ContextGroup` type but is used at runtime when items are merged with their group names for the "Recent / All" split view.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synerise/ds-context-selector",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.44",
|
|
4
4
|
"description": "ContextSelector UI Component for the Synerise Design System",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": "Synerise/synerise-design",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"/dist",
|
|
19
19
|
"CHANGELOG.md",
|
|
20
|
+
"CLAUDE.md",
|
|
20
21
|
"README.md",
|
|
21
22
|
"package.json",
|
|
22
23
|
"LICENSE.md"
|
|
@@ -35,26 +36,26 @@
|
|
|
35
36
|
"check:circular-dependencies": "madge --circular --extensions ts,tsx,js,jsx --ts-config tsconfig.json src/ --exclude '/dist/'",
|
|
36
37
|
"upgrade:ds": "ncu -f \"@synerise/ds-*\" -u"
|
|
37
38
|
},
|
|
38
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9",
|
|
39
40
|
"sideEffects": [
|
|
40
41
|
"dist/style/*",
|
|
41
42
|
"*.less"
|
|
42
43
|
],
|
|
43
44
|
"types": "dist/index.d.ts",
|
|
44
45
|
"dependencies": {
|
|
45
|
-
"@synerise/ds-button": "^1.5.
|
|
46
|
-
"@synerise/ds-divider": "^1.3.
|
|
47
|
-
"@synerise/ds-dropdown": "^1.3.
|
|
48
|
-
"@synerise/ds-factors": "^1.12.
|
|
49
|
-
"@synerise/ds-icon": "^1.18.
|
|
50
|
-
"@synerise/ds-information-card": "^1.7.
|
|
51
|
-
"@synerise/ds-list-item": "^1.6.
|
|
52
|
-
"@synerise/ds-popover": "^1.6.
|
|
53
|
-
"@synerise/ds-result": "^1.0.
|
|
54
|
-
"@synerise/ds-scrollbar": "^1.5.
|
|
55
|
-
"@synerise/ds-skeleton": "^1.0.
|
|
56
|
-
"@synerise/ds-tabs": "^1.2.
|
|
57
|
-
"@synerise/ds-utils": "^1.10.
|
|
46
|
+
"@synerise/ds-button": "^1.5.35",
|
|
47
|
+
"@synerise/ds-divider": "^1.3.16",
|
|
48
|
+
"@synerise/ds-dropdown": "^1.3.20",
|
|
49
|
+
"@synerise/ds-factors": "^1.12.11",
|
|
50
|
+
"@synerise/ds-icon": "^1.18.5",
|
|
51
|
+
"@synerise/ds-information-card": "^1.7.8",
|
|
52
|
+
"@synerise/ds-list-item": "^1.6.2",
|
|
53
|
+
"@synerise/ds-popover": "^1.6.2",
|
|
54
|
+
"@synerise/ds-result": "^1.0.66",
|
|
55
|
+
"@synerise/ds-scrollbar": "^1.5.2",
|
|
56
|
+
"@synerise/ds-skeleton": "^1.0.60",
|
|
57
|
+
"@synerise/ds-tabs": "^1.2.6",
|
|
58
|
+
"@synerise/ds-utils": "^1.10.2",
|
|
58
59
|
"react-intl": "^6.8.7",
|
|
59
60
|
"react-window": "1.8.11",
|
|
60
61
|
"uuid": "^8.3.2"
|