@synerise/ds-cascader 1.1.50 → 1.1.51

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 (3) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/CLAUDE.md +126 -0
  3. package/package.json +10 -9
package/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
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.1.51](https://github.com/Synerise/synerise-design/compare/@synerise/ds-cascader@1.1.50...@synerise/ds-cascader@1.1.51) (2026-07-23)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-cascader
9
+
6
10
  ## [1.1.50](https://github.com/Synerise/synerise-design/compare/@synerise/ds-cascader@1.1.49...@synerise/ds-cascader@1.1.50) (2026-07-16)
7
11
 
8
12
  **Note:** Version bump only for package @synerise/ds-cascader
package/CLAUDE.md ADDED
@@ -0,0 +1,126 @@
1
+ # Cascader (`@synerise/ds-cascader`)
2
+
3
+ > A hierarchical category-browser with built-in search, breadcrumb navigation, and multi-select; the category tree is passed as a deeply-nested `Category` object rather than a flat array.
4
+
5
+ ## Package structure
6
+
7
+ ```
8
+ src/
9
+ Cascader.tsx — main component (search + navigation + category list)
10
+ Cascader.types.ts — CascaderProps, Category, Path, Texts
11
+ Cascader.styles.tsx — styled-components (Wrapper, SearchResults, CascaderScrollbar)
12
+ utils.ts — tree traversal: getAllPaths, filterPaths, hasNestedCategories, searchCategoryWithId
13
+ index.ts — public exports
14
+ Elements/
15
+ BackAction/ — "go back" button shown when navigating > 1 level deep
16
+ BottomAction/ — generic bottom action slot (not currently used by Cascader directly)
17
+ Breadcrumb/ — renders a path as chevron-separated crumbs; also exported publicly
18
+ BreadcrumbsList/ — virtualised list of Breadcrumb rows for search results
19
+ CategoriesList/ — renders children of the active category as ListItems
20
+ Navigation/ — composes Breadcrumb + BackAction into the nav header
21
+ ```
22
+
23
+ ## Public exports
24
+
25
+ ### `Cascader` (default export)
26
+
27
+ | Prop | Type | Default | Description |
28
+ |------|------|---------|-------------|
29
+ | `rootCategory` | `Category` | — | **Required.** The root node of the category tree. Nested categories are arbitrary object keys whose values are `Category` objects. |
30
+ | `selectedCategoriesIds` | `ReactText[]` | — | **Required.** Controlled list of selected category ids. Drives the green check icon and selection state. |
31
+ | `categorySuffix` | `ReactNode` | — | **Required.** Element shown in the suffix slot of each unselected leaf item (e.g. an "add" button). Replaced by a green `CheckS` icon when the item is selected. |
32
+ | `onCategorySelect` | `(item: Category, selected: boolean) => void` | `undefined` | Fires when a leaf category is toggled. `selected` is the new state. |
33
+ | `searchClearTooltip` | `ReactNode` | `undefined` | Tooltip on the search-bar clear button. |
34
+ | `searchInputPlaceholder` | `string` | `''` | Placeholder for the search input. |
35
+ | `maxHeight` | `number` | `undefined` | Constrains the category list height (px) to enable scrolling. Height is snapped to a multiple of `CATEGORY_ITEM_HEIGHT` (32px). |
36
+ | `contentStyles` | `CSSProperties` | `undefined` | Inline styles applied to the `SearchResults` wrapper. |
37
+
38
+ ### `Breadcrumb`
39
+
40
+ Re-exported standalone component for rendering a path as a row of `›`-separated crumbs. Extends `ListItemProps` from `@synerise/ds-list-item`.
41
+
42
+ | Prop | Type | Default | Description |
43
+ |------|------|---------|-------------|
44
+ | `path` | `string[]` | — | **Required.** Array of path segments. |
45
+ | `onPathClick` | `(path: string & { id?: number \| string }) => void` | `undefined` | Called when a crumb is clicked. |
46
+ | `highlight` | `string` | `undefined` | Search term to highlight inside crumb text and description. |
47
+ | `description` | `ReactNode` | `undefined` | Optional secondary line above the path row. Highlighted if string + `highlight` is set. |
48
+ | `compact` | `boolean` | `undefined` | Reverses the path array so deepest item appears first. |
49
+ | `startWithArrow` | `boolean` | `undefined` | Renders an arrow before the first item. |
50
+ | `gradientOverlap` | `boolean` | `undefined` | Fades out overflowing content with a gradient. Uses a `ResizeObserver`-like ref check. |
51
+ | `highlightActivePath` | `boolean` | `undefined` | Adds `.active` class to the last (deepest) path segment. |
52
+ | `prefixel` | `ReactNode` | `undefined` | Element prepended before the crumb content (e.g. a home icon). |
53
+ | `isNavigation` | `boolean` | `undefined` | Applies navigation-mode styling. |
54
+ | `disabled` | `boolean` | `undefined` | Greyed-out state. |
55
+ | `className` | `string` | `undefined` | Additional class (`ds-breadcrumb` always added). |
56
+ | `style` | `CSSProperties` | `undefined` | Inline styles. |
57
+
58
+ ### Type exports
59
+
60
+ `CascaderProps`, `Category`, `Texts`, `Path`
61
+
62
+ ## Data model
63
+
64
+ The `Category` type is intentionally minimal — the actual tree structure relies on **arbitrary object keys** holding nested `Category` values:
65
+
66
+ ```ts
67
+ type Category = {
68
+ id: ReactText; // string | number
69
+ name: string;
70
+ path: string[]; // full path from root to this node, e.g. ['Home', 'Computers', 'Laptops']
71
+ // any additional key: Category ← nested children (not in the type, handled with @ts-expect-error)
72
+ };
73
+ ```
74
+
75
+ This is a known limitation tracked as `STOR-1904`. All tree-traversal utilities use `Object.keys` + `typeof value === 'object'` duck-typing to find children.
76
+
77
+ ## Usage patterns
78
+
79
+ ```tsx
80
+ import Cascader from '@synerise/ds-cascader';
81
+
82
+ const rootCategory = {
83
+ id: 0,
84
+ name: 'Home',
85
+ path: ['Home'],
86
+ Phones: { id: 1, name: 'Phones', path: ['Home', 'Phones'] },
87
+ Computers: {
88
+ id: 2,
89
+ name: 'Computers',
90
+ path: ['Home', 'Computers'],
91
+ Laptops: { id: 3, name: 'Laptops', path: ['Home', 'Computers', 'Laptops'] },
92
+ },
93
+ };
94
+
95
+ const [selected, setSelected] = useState<(string | number)[]>([]);
96
+
97
+ <Cascader
98
+ rootCategory={rootCategory}
99
+ selectedCategoriesIds={selected}
100
+ categorySuffix={<Button>Add</Button>}
101
+ onCategorySelect={(item, isSelected) =>
102
+ setSelected(prev =>
103
+ isSelected ? [...prev, item.id] : prev.filter(id => id !== item.id)
104
+ )
105
+ }
106
+ searchInputPlaceholder="Search categories…"
107
+ maxHeight={400}
108
+ />
109
+ ```
110
+
111
+ ## Key dependencies
112
+
113
+ - `@synerise/ds-search-bar` — the search input at the top
114
+ - `@synerise/ds-list-item` — each category row in `CategoriesList`; `Breadcrumb` extends `ListItemProps`
115
+ - `@synerise/ds-scrollbar` — `CascaderScrollbar` wraps both the search results and category list
116
+ - `@synerise/ds-utils` (`useResize`, `renderWithHighlight`) — container height measurement and search term highlighting
117
+
118
+ ## Implementation notes
119
+
120
+ - **Navigation is state-only**: drilling into a category pushes it onto `enteredCategories` and sets `activeCategory`. Going back (breadcrumb click / back-action) pops from `enteredCategories` and re-finds the target via `searchCategoryWithId`.
121
+ - **Leaf vs. branch detection**: `hasNestedCategories` returns `true` if any object-valued key exists. Clicking a branch navigates into it; clicking a leaf calls `onItemSelect` (toggle).
122
+ - **Search overrides navigation**: when `searchQuery` is non-empty the category list is hidden and `BreadcrumbsList` shows `filteredPaths` instead. `filterPaths` matches only the **last element** of each path string array against the query (case-insensitive).
123
+ - **`selectedCategoriesIds` is both controlled and internally mirrored**: an internal `selectedIds` state is synced via `useEffect([selectedCategoriesIds])`. Local toggles update `selectedIds` immediately without waiting for the parent to propagate a new prop — this gives an optimistic UI feel.
124
+ - **`maxHeight` is approximate**: it floors to a multiple of 32px (`CATEGORY_ITEM_HEIGHT`) after subtracting the categories container's `offsetTop`. This means the exact pixel value you pass will rarely match the actual clamped height.
125
+ - **`backActionVisible`** requires `enteredCategories.length > 1` (not just `> 0`) so the back action only appears from the second level onwards.
126
+ - **`Texts` type** is exported but unused internally — it defines a single key `'searchPlaceholder'` and appears to be a leftover from an earlier i18n pattern.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-cascader",
3
- "version": "1.1.50",
3
+ "version": "1.1.51",
4
4
  "description": "Cascader 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"
@@ -41,13 +42,13 @@
41
42
  ],
42
43
  "types": "dist/index.d.ts",
43
44
  "dependencies": {
44
- "@synerise/ds-divider": "^1.3.15",
45
- "@synerise/ds-icon": "^1.18.4",
46
- "@synerise/ds-list-item": "^1.6.1",
47
- "@synerise/ds-scrollbar": "^1.5.1",
48
- "@synerise/ds-search": "^1.5.33",
49
- "@synerise/ds-search-bar": "^1.4.34",
50
- "@synerise/ds-utils": "^1.10.1"
45
+ "@synerise/ds-divider": "^1.3.16",
46
+ "@synerise/ds-icon": "^1.18.5",
47
+ "@synerise/ds-list-item": "^1.6.2",
48
+ "@synerise/ds-scrollbar": "^1.5.2",
49
+ "@synerise/ds-search": "^1.5.34",
50
+ "@synerise/ds-search-bar": "^1.4.35",
51
+ "@synerise/ds-utils": "^1.10.2"
51
52
  },
52
53
  "devDependencies": {
53
54
  "vitest": "4"
@@ -57,5 +58,5 @@
57
58
  "react": ">=16.9.0 <= 18.3.1",
58
59
  "styled-components": "^5.3.3"
59
60
  },
60
- "gitHead": "a81ab6519d49a3dea9c0cfebcdc9104cbb4f4226"
61
+ "gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9"
61
62
  }