@synerise/ds-filter 1.2.59 → 1.2.60

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 +8 -7
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.2.60](https://github.com/Synerise/synerise-design/compare/@synerise/ds-filter@1.2.59...@synerise/ds-filter@1.2.60) (2026-07-23)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-filter
9
+
6
10
  ## [1.2.59](https://github.com/Synerise/synerise-design/compare/@synerise/ds-filter@1.2.58...@synerise/ds-filter@1.2.59) (2026-07-16)
7
11
 
8
12
  **Note:** Version bump only for package @synerise/ds-filter
package/CLAUDE.md ADDED
@@ -0,0 +1,126 @@
1
+ # Filter (`@synerise/ds-filter`)
2
+
3
+ > A container component that renders and manages a list of filter expressions (step cards with optional logic operators between them), supporting drag-and-drop reordering, per-step actions, a conditions limit, and a fully render-prop-based content API.
4
+
5
+ ## Package structure
6
+
7
+ ```
8
+ src/
9
+ Filter.tsx — main component
10
+ Filter.types.ts — FilterProps and all data-model types
11
+ Filter.styles.ts — styled-components
12
+ index.ts — public exports
13
+ utils.ts — isStepType() type guard
14
+ components/
15
+ ExpressionItem/
16
+ index.ts — re-exports ExpressionItem, DraggableExpressionItem, ExpressionItemProps
17
+ ExpressionItem.tsx — renders a single StepCard + optional Logic between items
18
+ ExpressionItem.types.ts — ExpressionItemProps, SortableItemProps
19
+ DraggableExpressionItem.tsx — wraps ExpressionItem with useDndMonitor for drag support
20
+ __specs__/
21
+ Filter.spec.tsx — Vitest tests
22
+ ```
23
+
24
+ ## Public exports
25
+
26
+ ### `Filter` (default export)
27
+
28
+ | Prop | Type | Default | Description |
29
+ |------|------|---------|-------------|
30
+ | `expressions` | `Expression[]` | — | **Required.** The ordered list of STEP and LOGIC expressions to render |
31
+ | `matching` | `MatchingProps` | — | Top-level matching toggle props (from `@synerise/ds-logic`) |
32
+ | `onChangeOrder` | `(newOrder: Expression[]) => void` | — | Order-change callback; also activates drag mode when `expressions.length > 1` |
33
+ | `onChangeLogic` | `(id: string, logic: LogicOperatorValue) => void` | — | Called when the Logic operator between steps changes |
34
+ | `onChangeStepMatching` | `(id: string, matching: boolean) => void` | — | Called when a step's matching toggle changes |
35
+ | `onChangeStepName` | `(id: string, name: string) => void` | — | Called when a step's name input changes |
36
+ | `onDeleteStep` | `(id: string) => void` | — | Called when a step's delete button is clicked |
37
+ | `onDuplicateStep` | `(id: string) => void` | — | Called on duplicate; silently disabled (button hidden) if `maxConditionsLimit` is exceeded |
38
+ | `renderStepFooter` | `(expression: Expression) => ReactNode` | — | Render prop for the footer slot of each StepCard |
39
+ | `renderStepContent` | `(expression: Expression, hoverDisabled?: boolean) => ReactNode` | — | Render prop for the body of each StepCard; `hoverDisabled` is `true` when another step is active |
40
+ | `renderStepHeaderRightSide` | `(expression: Expression, index: number, options?: { placeholder?: boolean }) => ReactNode` | — | Render prop for the right side of each StepCard header |
41
+ | `renderHeaderRightSide` | `(expressions: Expression[]) => ReactNode` | — | Render prop for the right side of the Filter header bar |
42
+ | `addFilterComponent` | `ReactNode \| ((arg: { isLimitExceeded: boolean }) => ReactNode)` | — | "Add filter" button area; hidden in `readOnly` mode; function form receives limit state |
43
+ | `logicOptions` | `LogicOperator[]` | — | Available logic operator choices for Logic components |
44
+ | `maxConditionsLimit` | `number` | — | When set, shows `count/limit` in header and disables duplicate once reached |
45
+ | `readOnly` | `boolean` | `false` | Disables all editing interactions |
46
+ | `singleStepCondition` | `boolean` | `false` | Passed through to StepCard to render single-condition UI variant |
47
+ | `visibilityConfig` | `{ isStepCardHeaderVisible?: boolean }` | `{ isStepCardHeaderVisible: true }` | Controls StepCard header visibility |
48
+ | `getMoveByLabel` | `(moveByOffset: number) => string` | — | Produces accessible aria label for keyboard-move buttons |
49
+ | `texts` | `DeepPartial<FilterTexts>` | — | Overrides any subset of i18n strings (merged with react-intl defaults) |
50
+
51
+ No `forwardRef`.
52
+
53
+ ### `Expression`
54
+
55
+ Union type: `StepType | LogicType`
56
+
57
+ ### `StepType`
58
+
59
+ | Field | Type | Description |
60
+ |-------|------|-------------|
61
+ | `type` | `'STEP'` | Discriminant |
62
+ | `id` | `string` | Unique identifier |
63
+ | `data` | `Partial<StepCardProps>` | Props passed to the StepCard |
64
+ | `logic` | `LogicType` (optional) | Logic operator displayed before this step |
65
+ | `expressionType` | `'attribute' \| 'event'` (optional) | Controls matching text variants shown in the step header |
66
+
67
+ ### `LogicType`
68
+
69
+ | Field | Type | Description |
70
+ |-------|------|-------------|
71
+ | `type` | `'LOGIC'` | Discriminant |
72
+ | `id` | `string` | Unique identifier |
73
+ | `data` | `Partial<LogicProps>` | Props passed to the Logic component |
74
+
75
+ ### `FilterProps`
76
+
77
+ TypeScript type re-exported for consumers.
78
+
79
+ ## Usage patterns
80
+
81
+ ```tsx
82
+ import Filter from '@synerise/ds-filter';
83
+ import type { Expression } from '@synerise/ds-filter';
84
+
85
+ const [expressions, setExpressions] = useState<Expression[]>([]);
86
+
87
+ <Filter
88
+ expressions={expressions}
89
+ matching={{ matching: true, onChange: (v) => setMatching(v) }}
90
+ onChangeOrder={setExpressions}
91
+ onDeleteStep={(id) => setExpressions(prev => prev.filter(e => e.id !== id))}
92
+ onDuplicateStep={(id) => { /* clone and append */ }}
93
+ onChangeStepName={(id, name) => { /* update */ }}
94
+ onChangeLogic={(id, logic) => { /* update */ }}
95
+ maxConditionsLimit={5}
96
+ addFilterComponent={({ isLimitExceeded }) => (
97
+ <Button disabled={isLimitExceeded} onClick={handleAdd}>Add filter</Button>
98
+ )}
99
+ renderStepContent={(expression) => <MyConditionEditor expression={expression} />}
100
+ renderStepFooter={(expression) => <MyFooter expression={expression} />}
101
+ />
102
+ ```
103
+
104
+ ## Styling
105
+
106
+ Styles in `Filter.styles.ts` use `@synerise/ds-core` theme palette tokens. `placeholderCss` is passed to `@synerise/ds-sortable` to style the drag-and-drop placeholder. No hardcoded values.
107
+
108
+ ## Key dependencies
109
+
110
+ - `@synerise/ds-logic` — `Matching`, `Placeholder`, `Logic` components and related types
111
+ - `@synerise/ds-step-card` — `StepCard` rendered for each STEP expression
112
+ - `@synerise/ds-sortable` — drag-and-drop container used when `isDraggable` is true
113
+ - `@synerise/ds-utils` — `usePrevious`, `NOOP`, `DeepPartial`
114
+ - `react-intl` — i18n for all default text strings
115
+
116
+ ## Implementation notes
117
+
118
+ - **Drag mode is automatic**: `isDraggable = Boolean(onChangeOrder && expressions.length > 1)`. With only 1 expression, static rendering is used. Drag wraps expressions in `Sortable`; without it, `ExpressionItem` is rendered directly.
119
+ - **CSS reorder animation**: On order change, the component calculates translateY offsets via DOM `getBoundingClientRect`, sets them synchronously, then clears them in a `requestAnimationFrame` to trigger CSS transitions. `z-index` is cleaned up on `transitionend`.
120
+ - **Active expression tracking**: The last-added expression becomes active (highlighted); clicking any expression activates it. Active state passes `hoverDisabled=true` to other steps' `renderStepContent`.
121
+ - **`addFilterComponent` function form**: Pass a function `(arg) => ReactNode` to receive `{ isLimitExceeded }` — useful for disabling the add button when the limit is hit. The `readOnly` prop hides the add area entirely.
122
+ - **`texts.overwritten.filterTitle`**: When set, replaces the entire matching + conditions-limit header row with a plain text title.
123
+ - **`logic` is on StepType, not separate**: The LOGIC operator before a step is embedded as `step.logic` — it is not a standalone sibling item in the `expressions` array. The `ExpressionItem` renders it conditionally (not shown for the last item or during drag).
124
+ - **`// @ts-expect-error` in ExpressionItem.tsx**: Type mismatches between `StepCardProps` and `LogicProps` are suppressed — this is a known issue.
125
+ - **Uses Vitest**: `jest.config.js` present — not yet migrated.
126
+ - **`react-intl` is a peer dependency** — component throws at runtime without an `IntlProvider` ancestor.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-filter",
3
- "version": "1.2.59",
3
+ "version": "1.2.60",
4
4
  "description": "Filter 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,11 +42,11 @@
41
42
  ],
42
43
  "types": "dist/index.d.ts",
43
44
  "dependencies": {
44
- "@synerise/ds-button": "^1.5.34",
45
- "@synerise/ds-logic": "^1.1.45",
46
- "@synerise/ds-sortable": "^1.3.20",
47
- "@synerise/ds-step-card": "^1.2.56",
48
- "@synerise/ds-utils": "^1.10.1"
45
+ "@synerise/ds-button": "^1.5.35",
46
+ "@synerise/ds-logic": "^1.1.46",
47
+ "@synerise/ds-sortable": "^1.3.21",
48
+ "@synerise/ds-step-card": "^1.2.57",
49
+ "@synerise/ds-utils": "^1.10.2"
49
50
  },
50
51
  "peerDependencies": {
51
52
  "@synerise/ds-core": "*",
@@ -54,5 +55,5 @@
54
55
  "styled-components": "^5.3.3",
55
56
  "vitest": "4"
56
57
  },
57
- "gitHead": "a81ab6519d49a3dea9c0cfebcdc9104cbb4f4226"
58
+ "gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9"
58
59
  }