@handled-ai/design-system 0.18.10 → 0.18.11
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/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/data-table-condition-filter.d.ts +14 -3
- package/dist/components/data-table-condition-filter.js +198 -33
- package/dist/components/data-table-condition-filter.js.map +1 -1
- package/dist/components/data-table-filter.js +1 -1
- package/dist/components/data-table-filter.js.map +1 -1
- package/dist/components/pill.d.ts +1 -1
- package/dist/components/tabs.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/__tests__/data-table-condition-filter.test.tsx +143 -7
- package/src/components/__tests__/data-table-filter.test.tsx +0 -45
- package/src/components/data-table-condition-filter.tsx +274 -49
- package/src/components/data-table-filter.tsx +1 -1
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const badgeVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | null | undefined;
|
|
7
7
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
8
|
declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
|
|
9
9
|
asChild?: boolean;
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
type ConditionOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "is_null" | "is_not_null";
|
|
4
|
+
interface ConditionOptionObject {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
type ConditionFieldOption = string | ConditionOptionObject;
|
|
4
9
|
interface ConditionFieldDef {
|
|
5
10
|
/** Unique field key (e.g., "Account_Balance__c") */
|
|
6
11
|
id: string;
|
|
7
12
|
/** Display label (e.g., "Account Balance") */
|
|
8
13
|
label: string;
|
|
9
14
|
/** Field data type — determines which operators are available and how the value input renders */
|
|
10
|
-
type: "text" | "number" | "currency" | "date";
|
|
15
|
+
type: "text" | "number" | "currency" | "date" | "select" | "multi_select";
|
|
11
16
|
/** Allowed operators for this field. Defaults based on type if not provided. */
|
|
12
17
|
operators?: ConditionOperator[];
|
|
18
|
+
/** Options used by select and multi-select fields. Strings use the same label and value. */
|
|
19
|
+
options?: ConditionFieldOption[];
|
|
20
|
+
/** Show a search box for option-backed value inputs. */
|
|
21
|
+
searchable?: boolean | {
|
|
22
|
+
threshold?: number;
|
|
23
|
+
};
|
|
13
24
|
}
|
|
14
25
|
interface ConditionFilterValue {
|
|
15
26
|
/** Stable identity — used as React key to avoid stale-state bugs on removal */
|
|
16
27
|
id: string;
|
|
17
28
|
field: string;
|
|
18
29
|
operator: ConditionOperator;
|
|
19
|
-
value: string | number | null;
|
|
30
|
+
value: string | number | string[] | null;
|
|
20
31
|
}
|
|
21
32
|
interface DataTableConditionFilterProps {
|
|
22
33
|
/** Available fields the user can filter on */
|
|
@@ -34,4 +45,4 @@ declare function generateConditionId(): string;
|
|
|
34
45
|
declare function getOperators(field: ConditionFieldDef): ConditionOperator[];
|
|
35
46
|
declare function DataTableConditionFilter({ fields, conditions, onConditionsChange, className, }: DataTableConditionFilterProps): React.JSX.Element;
|
|
36
47
|
|
|
37
|
-
export { type ConditionFieldDef, type ConditionFilterValue, type ConditionOperator, DEFAULT_OPERATORS, DataTableConditionFilter, type DataTableConditionFilterProps, OPERATOR_LABELS, generateConditionId, getOperators };
|
|
48
|
+
export { type ConditionFieldDef, type ConditionFieldOption, type ConditionFilterValue, type ConditionOperator, type ConditionOptionObject, DEFAULT_OPERATORS, DataTableConditionFilter, type DataTableConditionFilterProps, OPERATOR_LABELS, generateConditionId, getOperators };
|
|
@@ -24,6 +24,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
import * as React from "react";
|
|
25
25
|
import {
|
|
26
26
|
CalendarDays,
|
|
27
|
+
Check,
|
|
27
28
|
DollarSign,
|
|
28
29
|
Eye,
|
|
29
30
|
Hash,
|
|
@@ -49,7 +50,7 @@ const OPERATOR_LABELS = {
|
|
|
49
50
|
gte: "\u2265",
|
|
50
51
|
lt: "<",
|
|
51
52
|
lte: "\u2264",
|
|
52
|
-
in: "
|
|
53
|
+
in: "is any of",
|
|
53
54
|
is_null: "is empty",
|
|
54
55
|
is_not_null: "is not empty"
|
|
55
56
|
};
|
|
@@ -67,7 +68,9 @@ const DEFAULT_OPERATORS = {
|
|
|
67
68
|
text: ["eq", "neq", "is_null", "is_not_null"],
|
|
68
69
|
number: NUMERIC_OPERATORS,
|
|
69
70
|
currency: NUMERIC_OPERATORS,
|
|
70
|
-
date: ["gt", "gte", "lt", "lte", "eq", "neq", "is_null", "is_not_null"]
|
|
71
|
+
date: ["gt", "gte", "lt", "lte", "eq", "neq", "is_null", "is_not_null"],
|
|
72
|
+
select: ["eq", "neq", "is_null", "is_not_null"],
|
|
73
|
+
multi_select: ["in", "is_null", "is_not_null"]
|
|
71
74
|
};
|
|
72
75
|
function generateConditionId() {
|
|
73
76
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
@@ -77,7 +80,7 @@ function generateConditionId() {
|
|
|
77
80
|
}
|
|
78
81
|
function getOperators(field) {
|
|
79
82
|
var _a;
|
|
80
|
-
return (
|
|
83
|
+
return (_a = field.operators) != null ? _a : DEFAULT_OPERATORS[field.type];
|
|
81
84
|
}
|
|
82
85
|
function isUnaryOperator(op) {
|
|
83
86
|
return op === "is_null" || op === "is_not_null";
|
|
@@ -94,6 +97,13 @@ function createDraftCondition(field) {
|
|
|
94
97
|
value: null
|
|
95
98
|
};
|
|
96
99
|
}
|
|
100
|
+
function normalizeConditionValue(value, field, operator) {
|
|
101
|
+
if (isUnaryOperator(operator)) return null;
|
|
102
|
+
if (field.type === "multi_select") {
|
|
103
|
+
return Array.isArray(value) ? value : null;
|
|
104
|
+
}
|
|
105
|
+
return Array.isArray(value) ? null : value;
|
|
106
|
+
}
|
|
97
107
|
function normalizeCondition(condition, fields) {
|
|
98
108
|
var _a;
|
|
99
109
|
const field = (_a = fields.find((f) => f.id === condition.field)) != null ? _a : fields[0];
|
|
@@ -103,7 +113,7 @@ function normalizeCondition(condition, fields) {
|
|
|
103
113
|
return __spreadProps(__spreadValues({}, condition), {
|
|
104
114
|
field: field.id,
|
|
105
115
|
operator,
|
|
106
|
-
value:
|
|
116
|
+
value: normalizeConditionValue(condition.value, field, operator)
|
|
107
117
|
});
|
|
108
118
|
}
|
|
109
119
|
function parseConditionValue(raw, fieldType) {
|
|
@@ -119,25 +129,177 @@ function isCompleteCondition(condition, fields) {
|
|
|
119
129
|
if (!field) return false;
|
|
120
130
|
if (!getOperators(field).includes(condition.operator)) return false;
|
|
121
131
|
if (isUnaryOperator(condition.operator)) return true;
|
|
122
|
-
|
|
132
|
+
if (field.type === "multi_select") {
|
|
133
|
+
return Array.isArray(condition.value) && condition.value.length > 0;
|
|
134
|
+
}
|
|
135
|
+
return condition.value !== null && condition.value !== "" && !Array.isArray(condition.value);
|
|
136
|
+
}
|
|
137
|
+
function getConditionValueSignature(value) {
|
|
138
|
+
return Array.isArray(value) ? JSON.stringify(value) : String(value);
|
|
123
139
|
}
|
|
124
140
|
function getConditionsSignature(conditions) {
|
|
125
|
-
return conditions.map((condition) => `${condition.id}:${condition.field}:${condition.operator}:${
|
|
141
|
+
return conditions.map((condition) => `${condition.id}:${condition.field}:${condition.operator}:${getConditionValueSignature(condition.value)}`).join(";");
|
|
142
|
+
}
|
|
143
|
+
function normalizeFieldOptions(field) {
|
|
144
|
+
var _a;
|
|
145
|
+
return ((_a = field.options) != null ? _a : []).map(
|
|
146
|
+
(option) => typeof option === "string" ? { label: option, value: option } : option
|
|
147
|
+
);
|
|
126
148
|
}
|
|
127
149
|
function getFieldsSignature(fields) {
|
|
128
150
|
return fields.map((field) => {
|
|
129
|
-
var _a;
|
|
130
|
-
|
|
151
|
+
var _a, _b, _c;
|
|
152
|
+
const optionsSignature = normalizeFieldOptions(field).map((option) => `${option.label}:${option.value}`).join("|");
|
|
153
|
+
const searchSignature = typeof field.searchable === "object" ? `threshold:${(_a = field.searchable.threshold) != null ? _a : ""}` : String((_b = field.searchable) != null ? _b : "");
|
|
154
|
+
return `${field.id}:${field.type}:${field.label}:${((_c = field.operators) != null ? _c : []).join("|")}:${optionsSignature}:${searchSignature}`;
|
|
131
155
|
}).join(";");
|
|
132
156
|
}
|
|
133
157
|
function getCommittedConditions(drafts, fields) {
|
|
134
158
|
return drafts.map((condition) => normalizeCondition(condition, fields)).filter((condition) => isCompleteCondition(condition, fields));
|
|
135
159
|
}
|
|
160
|
+
const FIELD_ICON_BY_TYPE = {
|
|
161
|
+
text: Type,
|
|
162
|
+
number: Hash,
|
|
163
|
+
currency: DollarSign,
|
|
164
|
+
date: CalendarDays,
|
|
165
|
+
select: MoreHorizontal,
|
|
166
|
+
multi_select: MoreHorizontal
|
|
167
|
+
};
|
|
136
168
|
function getFieldIcon(type) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return
|
|
169
|
+
return FIELD_ICON_BY_TYPE[type];
|
|
170
|
+
}
|
|
171
|
+
function getInputType(fieldType) {
|
|
172
|
+
if (fieldType === "number" || fieldType === "currency") return "number";
|
|
173
|
+
if (fieldType === "date") return "date";
|
|
174
|
+
return "text";
|
|
175
|
+
}
|
|
176
|
+
function getInputPlaceholder(fieldType) {
|
|
177
|
+
if (fieldType === "currency") return "Amount";
|
|
178
|
+
if (fieldType === "number") return "Enter number...";
|
|
179
|
+
if (fieldType === "date") return "";
|
|
180
|
+
return "Enter value...";
|
|
181
|
+
}
|
|
182
|
+
function shouldShowOptionSearch(fieldDef, optionCount) {
|
|
183
|
+
var _a;
|
|
184
|
+
if (fieldDef.searchable === true) return true;
|
|
185
|
+
if (fieldDef.searchable === false) return false;
|
|
186
|
+
if (typeof fieldDef.searchable === "object") {
|
|
187
|
+
return optionCount >= ((_a = fieldDef.searchable.threshold) != null ? _a : 8);
|
|
188
|
+
}
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
function SelectConditionValueInput({
|
|
192
|
+
condition,
|
|
193
|
+
fieldDef,
|
|
194
|
+
onSelectValueChange
|
|
195
|
+
}) {
|
|
196
|
+
const [query, setQuery] = React.useState("");
|
|
197
|
+
const options = normalizeFieldOptions(fieldDef);
|
|
198
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
199
|
+
const filteredOptions = normalizedQuery ? options.filter((option) => option.label.toLowerCase().includes(normalizedQuery)) : options;
|
|
200
|
+
const showSearch = shouldShowOptionSearch(fieldDef, options.length);
|
|
201
|
+
return /* @__PURE__ */ jsxs(
|
|
202
|
+
Select,
|
|
203
|
+
{
|
|
204
|
+
value: typeof condition.value === "string" ? condition.value : "",
|
|
205
|
+
onValueChange: onSelectValueChange,
|
|
206
|
+
children: [
|
|
207
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 w-full", size: "sm", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select value..." }) }),
|
|
208
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
209
|
+
showSearch ? /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 border-b border-border bg-popover p-1.5", children: /* @__PURE__ */ jsx(
|
|
210
|
+
Input,
|
|
211
|
+
{
|
|
212
|
+
value: query,
|
|
213
|
+
onChange: (event) => setQuery(event.target.value),
|
|
214
|
+
onClick: (event) => event.stopPropagation(),
|
|
215
|
+
onKeyDown: (event) => event.stopPropagation(),
|
|
216
|
+
placeholder: "Search options...",
|
|
217
|
+
className: "h-7 text-xs"
|
|
218
|
+
}
|
|
219
|
+
) }) : null,
|
|
220
|
+
filteredOptions.length > 0 ? filteredOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) : /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: "No options" })
|
|
221
|
+
] })
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
function MultiSelectConditionValueInput({
|
|
227
|
+
condition,
|
|
228
|
+
fieldDef,
|
|
229
|
+
onMultiSelectValueToggle
|
|
230
|
+
}) {
|
|
231
|
+
const selectedValues = Array.isArray(condition.value) ? condition.value : [];
|
|
232
|
+
const options = normalizeFieldOptions(fieldDef);
|
|
233
|
+
return /* @__PURE__ */ jsx("div", { className: "max-h-28 overflow-y-auto rounded-md border border-border bg-background p-1", children: options.length > 0 ? options.map((option) => {
|
|
234
|
+
const checked = selectedValues.includes(option.value);
|
|
235
|
+
return /* @__PURE__ */ jsxs(
|
|
236
|
+
"button",
|
|
237
|
+
{
|
|
238
|
+
type: "button",
|
|
239
|
+
role: "checkbox",
|
|
240
|
+
"aria-checked": checked,
|
|
241
|
+
className: cn(
|
|
242
|
+
"flex w-full items-center gap-2 rounded-sm px-2 py-1 text-left text-xs hover:bg-muted",
|
|
243
|
+
checked && "text-brand-purple"
|
|
244
|
+
),
|
|
245
|
+
onClick: (event) => {
|
|
246
|
+
event.stopPropagation();
|
|
247
|
+
onMultiSelectValueToggle(option.value);
|
|
248
|
+
},
|
|
249
|
+
children: [
|
|
250
|
+
/* @__PURE__ */ jsx(
|
|
251
|
+
"span",
|
|
252
|
+
{
|
|
253
|
+
className: cn(
|
|
254
|
+
"flex h-3.5 w-3.5 items-center justify-center rounded-sm border border-border",
|
|
255
|
+
checked && "border-brand-purple bg-brand-purple text-white"
|
|
256
|
+
),
|
|
257
|
+
"aria-hidden": "true",
|
|
258
|
+
children: checked ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) : null
|
|
259
|
+
}
|
|
260
|
+
),
|
|
261
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: option.label })
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
option.value
|
|
265
|
+
);
|
|
266
|
+
}) : /* @__PURE__ */ jsx("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: "No options" }) });
|
|
267
|
+
}
|
|
268
|
+
function ScalarConditionValueInput({
|
|
269
|
+
condition,
|
|
270
|
+
fieldDef,
|
|
271
|
+
onValueChange,
|
|
272
|
+
onCommit
|
|
273
|
+
}) {
|
|
274
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
|
|
275
|
+
fieldDef.type === "currency" ? /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute left-2 text-sm text-muted-foreground", children: "$" }) : null,
|
|
276
|
+
/* @__PURE__ */ jsx(
|
|
277
|
+
Input,
|
|
278
|
+
{
|
|
279
|
+
type: getInputType(fieldDef.type),
|
|
280
|
+
value: condition.value != null && !Array.isArray(condition.value) ? String(condition.value) : "",
|
|
281
|
+
onChange: onValueChange,
|
|
282
|
+
onClick: (event) => event.stopPropagation(),
|
|
283
|
+
onKeyDown: (event) => {
|
|
284
|
+
event.stopPropagation();
|
|
285
|
+
if (event.key === "Enter") {
|
|
286
|
+
onCommit();
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
placeholder: getInputPlaceholder(fieldDef.type),
|
|
290
|
+
className: cn("h-8", fieldDef.type === "currency" && "pl-6")
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
] });
|
|
294
|
+
}
|
|
295
|
+
function ConditionValueInput(props) {
|
|
296
|
+
if (props.fieldDef.type === "select") {
|
|
297
|
+
return /* @__PURE__ */ jsx(SelectConditionValueInput, __spreadValues({}, props));
|
|
298
|
+
}
|
|
299
|
+
if (props.fieldDef.type === "multi_select") {
|
|
300
|
+
return /* @__PURE__ */ jsx(MultiSelectConditionValueInput, __spreadValues({}, props));
|
|
301
|
+
}
|
|
302
|
+
return /* @__PURE__ */ jsx(ScalarConditionValueInput, __spreadValues({}, props));
|
|
141
303
|
}
|
|
142
304
|
function ConditionRow({
|
|
143
305
|
condition,
|
|
@@ -165,7 +327,7 @@ function ConditionRow({
|
|
|
165
327
|
const handleOperatorChange = (newOp) => {
|
|
166
328
|
onChange(__spreadProps(__spreadValues({}, condition), {
|
|
167
329
|
operator: newOp,
|
|
168
|
-
value:
|
|
330
|
+
value: normalizeConditionValue(condition.value, fieldDef, newOp)
|
|
169
331
|
}));
|
|
170
332
|
};
|
|
171
333
|
const handleValueChange = (event) => {
|
|
@@ -173,6 +335,18 @@ function ConditionRow({
|
|
|
173
335
|
value: parseConditionValue(event.target.value, fieldDef.type)
|
|
174
336
|
}));
|
|
175
337
|
};
|
|
338
|
+
const handleSelectValueChange = (value) => {
|
|
339
|
+
onChange(__spreadProps(__spreadValues({}, condition), {
|
|
340
|
+
value
|
|
341
|
+
}));
|
|
342
|
+
};
|
|
343
|
+
const handleMultiSelectValueToggle = (value) => {
|
|
344
|
+
const currentValues = Array.isArray(condition.value) ? condition.value : [];
|
|
345
|
+
const nextValues = currentValues.includes(value) ? currentValues.filter((currentValue) => currentValue !== value) : [...currentValues, value];
|
|
346
|
+
onChange(__spreadProps(__spreadValues({}, condition), {
|
|
347
|
+
value: nextValues
|
|
348
|
+
}));
|
|
349
|
+
};
|
|
176
350
|
return /* @__PURE__ */ jsxs(
|
|
177
351
|
"div",
|
|
178
352
|
{
|
|
@@ -204,26 +378,17 @@ function ConditionRow({
|
|
|
204
378
|
]
|
|
205
379
|
}
|
|
206
380
|
),
|
|
207
|
-
isUnary ? /* @__PURE__ */ jsx("div", { className: "h-8 rounded-md border border-dashed border-border/70 bg-muted/30 px-3 py-1.5 text-xs text-muted-foreground", children: "No value needed" }) : /* @__PURE__ */
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (event.key === "Enter") {
|
|
219
|
-
onCommit();
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
placeholder: fieldDef.type === "currency" ? "Amount" : fieldDef.type === "number" ? "Enter number..." : fieldDef.type === "date" ? "" : "Enter value...",
|
|
223
|
-
className: cn("h-8", fieldDef.type === "currency" && "pl-6")
|
|
224
|
-
}
|
|
225
|
-
)
|
|
226
|
-
] }),
|
|
381
|
+
isUnary ? /* @__PURE__ */ jsx("div", { className: "h-8 rounded-md border border-dashed border-border/70 bg-muted/30 px-3 py-1.5 text-xs text-muted-foreground", children: "No value needed" }) : /* @__PURE__ */ jsx(
|
|
382
|
+
ConditionValueInput,
|
|
383
|
+
{
|
|
384
|
+
condition,
|
|
385
|
+
fieldDef,
|
|
386
|
+
onValueChange: handleValueChange,
|
|
387
|
+
onSelectValueChange: handleSelectValueChange,
|
|
388
|
+
onMultiSelectValueToggle: handleMultiSelectValueToggle,
|
|
389
|
+
onCommit
|
|
390
|
+
}
|
|
391
|
+
),
|
|
227
392
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
228
393
|
/* @__PURE__ */ jsx(
|
|
229
394
|
Button,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/data-table-condition-filter.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n CalendarDays,\n DollarSign,\n Eye,\n Hash,\n MoreHorizontal,\n Plus,\n Trash2,\n Type,\n} from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport { Button } from \"./button\"\nimport { Input } from \"./input\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select\"\n\n// ── Types ──────────────────────────────────────────────────────\n\nexport type ConditionOperator =\n | \"eq\"\n | \"neq\"\n | \"gt\"\n | \"gte\"\n | \"lt\"\n | \"lte\"\n | \"in\"\n | \"is_null\"\n | \"is_not_null\"\n\nexport interface ConditionFieldDef {\n /** Unique field key (e.g., \"Account_Balance__c\") */\n id: string\n /** Display label (e.g., \"Account Balance\") */\n label: string\n /** Field data type — determines which operators are available and how the value input renders */\n type: \"text\" | \"number\" | \"currency\" | \"date\"\n /** Allowed operators for this field. Defaults based on type if not provided. */\n operators?: ConditionOperator[]\n}\n\nexport interface ConditionFilterValue {\n /** Stable identity — used as React key to avoid stale-state bugs on removal */\n id: string\n field: string\n operator: ConditionOperator\n value: string | number | null\n}\n\ninterface DataTableConditionFilterProps {\n /** Available fields the user can filter on */\n fields: ConditionFieldDef[]\n /** Current active conditions */\n conditions: ConditionFilterValue[]\n /** Called when conditions change (add, update, remove) */\n onConditionsChange: (conditions: ConditionFilterValue[]) => void\n className?: string\n}\n\n// ── Constants ──────────────────────────────────────────────────\n\nconst OPERATOR_LABELS: Record<ConditionOperator, string> = {\n eq: \"=\",\n neq: \"≠\",\n gt: \">\",\n gte: \"≥\",\n lt: \"<\",\n lte: \"≤\",\n in: \"contains\",\n is_null: \"is empty\",\n is_not_null: \"is not empty\",\n}\n\nconst NUMERIC_OPERATORS: ConditionOperator[] = [\n \"eq\",\n \"neq\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"is_null\",\n \"is_not_null\",\n]\n\nconst DEFAULT_OPERATORS: Record<ConditionFieldDef[\"type\"], ConditionOperator[]> = {\n text: [\"eq\", \"neq\", \"is_null\", \"is_not_null\"],\n number: NUMERIC_OPERATORS,\n currency: NUMERIC_OPERATORS,\n date: [\"gt\", \"gte\", \"lt\", \"lte\", \"eq\", \"neq\", \"is_null\", \"is_not_null\"],\n}\n\n/** Generate a stable unique ID for a new condition row. */\nfunction generateConditionId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID()\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ── Helpers ────────────────────────────────────────────────────\n\nfunction getOperators(field: ConditionFieldDef): ConditionOperator[] {\n return (field.operators ?? DEFAULT_OPERATORS[field.type]).filter((op) => op !== \"in\")\n}\n\nfunction isUnaryOperator(op: ConditionOperator): boolean {\n return op === \"is_null\" || op === \"is_not_null\"\n}\n\nfunction getDefaultOperator(field: ConditionFieldDef): ConditionOperator {\n return getOperators(field)[0] ?? \"eq\"\n}\n\nfunction createDraftCondition(field: ConditionFieldDef): ConditionFilterValue {\n return {\n id: generateConditionId(),\n field: field.id,\n operator: getDefaultOperator(field),\n value: null,\n }\n}\n\nfunction normalizeCondition(\n condition: ConditionFilterValue,\n fields: ConditionFieldDef[],\n): ConditionFilterValue {\n const field = fields.find((f) => f.id === condition.field) ?? fields[0]\n if (!field) return condition\n\n const operators = getOperators(field)\n const operator = operators.includes(condition.operator)\n ? condition.operator\n : getDefaultOperator(field)\n\n return {\n ...condition,\n field: field.id,\n operator,\n value: isUnaryOperator(operator) ? null : condition.value,\n }\n}\n\nfunction parseConditionValue(\n raw: string,\n fieldType: ConditionFieldDef[\"type\"],\n): string | number | null {\n if (raw === \"\") return null\n if (fieldType === \"number\" || fieldType === \"currency\") {\n const parsed = Number(raw)\n return Number.isNaN(parsed) ? null : parsed\n }\n return raw\n}\n\nfunction isCompleteCondition(\n condition: ConditionFilterValue,\n fields: ConditionFieldDef[],\n): boolean {\n const field = fields.find((f) => f.id === condition.field)\n if (!field) return false\n if (!getOperators(field).includes(condition.operator)) return false\n if (isUnaryOperator(condition.operator)) return true\n return condition.value !== null && condition.value !== \"\"\n}\n\nfunction getConditionsSignature(conditions: ConditionFilterValue[]): string {\n return conditions\n .map((condition) => `${condition.id}:${condition.field}:${condition.operator}:${String(condition.value)}`)\n .join(\";\")\n}\n\nfunction getFieldsSignature(fields: ConditionFieldDef[]): string {\n return fields\n .map((field) => `${field.id}:${field.type}:${field.label}:${(field.operators ?? []).join(\"|\")}`)\n .join(\";\")\n}\n\nfunction getCommittedConditions(\n drafts: ConditionFilterValue[],\n fields: ConditionFieldDef[],\n): ConditionFilterValue[] {\n return drafts\n .map((condition) => normalizeCondition(condition, fields))\n .filter((condition) => isCompleteCondition(condition, fields))\n}\n\nfunction getFieldIcon(type: ConditionFieldDef[\"type\"]) {\n if (type === \"currency\") return DollarSign\n if (type === \"number\") return Hash\n if (type === \"date\") return CalendarDays\n return Type\n}\n\n// ── Condition Row ──────────────────────────────────────────────\n\ninterface ConditionRowProps {\n condition: ConditionFilterValue\n fields: ConditionFieldDef[]\n index: number\n onChange: (updated: ConditionFilterValue) => void\n onRemove: () => void\n onCommit: () => void\n}\n\nfunction ConditionRow({\n condition,\n fields,\n index,\n onChange,\n onRemove,\n onCommit,\n}: ConditionRowProps) {\n const fieldDef = fields.find((f) => f.id === condition.field) ?? fields[0]\n const operators = getOperators(fieldDef)\n const isUnary = isUnaryOperator(condition.operator)\n const FieldIcon = getFieldIcon(fieldDef.type)\n\n const handleFieldChange = (newFieldId: string) => {\n const newFieldDef = fields.find((f) => f.id === newFieldId) ?? fields[0]\n if (!newFieldDef) return\n onChange({\n ...condition,\n field: newFieldDef.id,\n operator: getDefaultOperator(newFieldDef),\n value: null,\n })\n }\n\n const handleOperatorChange = (newOp: ConditionOperator) => {\n onChange({\n ...condition,\n operator: newOp,\n value: isUnaryOperator(newOp) ? null : condition.value,\n })\n }\n\n const handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n onChange({\n ...condition,\n value: parseConditionValue(event.target.value, fieldDef.type),\n })\n }\n\n return (\n <div\n className=\"grid grid-cols-[52px_minmax(150px,1fr)_120px_minmax(140px,1fr)_auto] items-center gap-2 rounded-lg border border-border/70 bg-background p-2 shadow-sm\"\n data-slot=\"condition-row\"\n >\n <div className=\"text-xs font-medium text-muted-foreground\">\n {index === 0 ? \"Where\" : \"And\"}\n </div>\n\n <Select value={condition.field} onValueChange={handleFieldChange}>\n <SelectTrigger className=\"h-8 w-full justify-start gap-2\" size=\"sm\">\n <FieldIcon className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <SelectValue placeholder={fieldDef.label} />\n </SelectTrigger>\n <SelectContent>\n {fields.map((field) => {\n const Icon = getFieldIcon(field.type)\n return (\n <SelectItem key={field.id} value={field.id}>\n <span className=\"inline-flex items-center gap-2\">\n <Icon className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {field.label}\n </span>\n </SelectItem>\n )\n })}\n </SelectContent>\n </Select>\n\n <Select\n value={condition.operator}\n onValueChange={(value) => handleOperatorChange(value as ConditionOperator)}\n >\n <SelectTrigger className=\"h-8 w-full\" size=\"sm\">\n <SelectValue placeholder=\"Operator\" />\n </SelectTrigger>\n <SelectContent>\n {operators.map((op) => (\n <SelectItem key={op} value={op}>\n {OPERATOR_LABELS[op]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {isUnary ? (\n <div className=\"h-8 rounded-md border border-dashed border-border/70 bg-muted/30 px-3 py-1.5 text-xs text-muted-foreground\">\n No value needed\n </div>\n ) : (\n <div className=\"relative flex items-center\">\n {fieldDef.type === \"currency\" ? (\n <span className=\"pointer-events-none absolute left-2 text-sm text-muted-foreground\">\n $\n </span>\n ) : null}\n <Input\n type={\n fieldDef.type === \"number\" || fieldDef.type === \"currency\"\n ? \"number\"\n : fieldDef.type === \"date\"\n ? \"date\"\n : \"text\"\n }\n value={condition.value != null ? String(condition.value) : \"\"}\n onChange={handleValueChange}\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n event.stopPropagation()\n if (event.key === \"Enter\") {\n onCommit()\n }\n }}\n placeholder={\n fieldDef.type === \"currency\"\n ? \"Amount\"\n : fieldDef.type === \"number\"\n ? \"Enter number...\"\n : fieldDef.type === \"date\"\n ? \"\"\n : \"Enter value...\"\n }\n className={cn(\"h-8\", fieldDef.type === \"currency\" && \"pl-6\")}\n />\n </div>\n )}\n\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-muted-foreground\"\n aria-label=\"Toggle condition visibility\"\n onClick={(event) => event.preventDefault()}\n >\n <Eye className=\"size-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-muted-foreground\"\n aria-label=\"More condition actions\"\n onClick={(event) => event.preventDefault()}\n >\n <MoreHorizontal className=\"size-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-muted-foreground hover:text-destructive\"\n onClick={onRemove}\n aria-label=\"Remove condition\"\n >\n <Trash2 className=\"size-4\" />\n </Button>\n </div>\n </div>\n )\n}\n\n// ── Main Component ─────────────────────────────────────────────\n\nfunction DataTableConditionFilter({\n fields,\n conditions,\n onConditionsChange,\n className,\n}: DataTableConditionFilterProps) {\n const [drafts, setDrafts] = React.useState<ConditionFilterValue[]>(() =>\n conditions.map((condition) => normalizeCondition(condition, fields)),\n )\n\n const fieldsSignature = React.useMemo(() => getFieldsSignature(fields), [fields])\n const conditionsSignature = React.useMemo(() => getConditionsSignature(conditions), [conditions])\n const fieldsRef = React.useRef(fields)\n\n React.useEffect(() => {\n setDrafts(conditions.map((condition) => normalizeCondition(condition, fieldsRef.current)))\n }, [conditionsSignature])\n\n React.useEffect(() => {\n if (fieldsRef.current !== fields) {\n fieldsRef.current = fields\n setDrafts((current) => current.map((condition) => normalizeCondition(condition, fields)))\n }\n // Depend on a structural signature so inline-but-equivalent field arrays do\n // not wipe in-progress drafts before Apply.\n }, [fieldsSignature, fields])\n\n const commitDrafts = React.useCallback(\n (nextDrafts: ConditionFilterValue[] = drafts) => {\n onConditionsChange(getCommittedConditions(nextDrafts, fields))\n },\n [drafts, fields, onConditionsChange],\n )\n\n const handleAdd = () => {\n const firstField = fields[0]\n if (!firstField) return\n const committedDrafts = getCommittedConditions(drafts, fields)\n const nextDrafts = [...committedDrafts, createDraftCondition(firstField)]\n setDrafts(nextDrafts)\n onConditionsChange(committedDrafts)\n }\n\n const handleUpdate = (index: number, updated: ConditionFilterValue) => {\n setDrafts((current) => {\n const next = [...current]\n next[index] = normalizeCondition(updated, fields)\n return next\n })\n }\n\n const handleRemove = (index: number) => {\n setDrafts((current) => {\n const next = current.filter((_, currentIndex) => currentIndex !== index)\n commitDrafts(next)\n return next\n })\n }\n\n const handleClear = () => {\n setDrafts([])\n onConditionsChange([])\n }\n\n const hasAppliedConditions = conditions.length > 0\n const hasDrafts = drafts.length > 0\n\n return (\n <div\n className={cn(\n \"w-[min(760px,calc(100vw-2rem))] rounded-xl border border-border bg-background p-3 text-foreground shadow-xl\",\n className,\n )}\n data-slot=\"condition-filter\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") {\n event.stopPropagation()\n }\n }}\n >\n <div className=\"mb-3 flex items-center justify-between gap-3 border-b border-border/70 pb-3\">\n <div>\n <div className=\"text-sm font-semibold\">Filter builder</div>\n <div className=\"text-xs text-muted-foreground\">\n Build field, operator, and value conditions.\n </div>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs text-destructive hover:text-destructive\"\n onClick={handleClear}\n disabled={!hasAppliedConditions && !hasDrafts}\n >\n Clear filters\n </Button>\n </div>\n\n <div className=\"flex flex-col gap-2\">\n {drafts.map((condition, index) => (\n <ConditionRow\n key={condition.id}\n condition={condition}\n fields={fields}\n index={index}\n onChange={(updated) => handleUpdate(index, updated)}\n onRemove={() => handleRemove(index)}\n onCommit={() => commitDrafts()}\n />\n ))}\n </div>\n\n {!hasDrafts ? (\n <div className=\"rounded-lg border border-dashed border-border/80 bg-muted/20 px-3 py-5 text-center text-xs text-muted-foreground\">\n No builder filters yet. Add a filter to start a condition row.\n </div>\n ) : null}\n\n <div className=\"mt-3 flex flex-wrap items-center justify-between gap-2 border-t border-border/70 pt-3\">\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs text-muted-foreground\"\n onClick={handleAdd}\n >\n <Plus className=\"mr-1 size-3.5\" />\n Add filter\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs text-muted-foreground opacity-60\"\n disabled\n aria-disabled=\"true\"\n >\n <Plus className=\"mr-1 size-3.5\" />\n Add filter group\n </Button>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-8 text-xs\"\n onClick={() => commitDrafts()}\n >\n Apply\n </Button>\n </div>\n </div>\n )\n}\n\nexport {\n DataTableConditionFilter,\n OPERATOR_LABELS,\n DEFAULT_OPERATORS,\n generateConditionId,\n getOperators,\n}\nexport type { DataTableConditionFilterProps }\n"],"mappings":"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","names":["_a"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/data-table-condition-filter.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n CalendarDays,\n Check,\n DollarSign,\n Eye,\n Hash,\n MoreHorizontal,\n Plus,\n Trash2,\n Type,\n type LucideIcon,\n} from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport { Button } from \"./button\"\nimport { Input } from \"./input\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select\"\n\n// ── Types ──────────────────────────────────────────────────────\n\nexport type ConditionOperator =\n | \"eq\"\n | \"neq\"\n | \"gt\"\n | \"gte\"\n | \"lt\"\n | \"lte\"\n | \"in\"\n | \"is_null\"\n | \"is_not_null\"\n\nexport interface ConditionOptionObject {\n label: string\n value: string\n}\n\nexport type ConditionFieldOption = string | ConditionOptionObject\n\nexport interface ConditionFieldDef {\n /** Unique field key (e.g., \"Account_Balance__c\") */\n id: string\n /** Display label (e.g., \"Account Balance\") */\n label: string\n /** Field data type — determines which operators are available and how the value input renders */\n type: \"text\" | \"number\" | \"currency\" | \"date\" | \"select\" | \"multi_select\"\n /** Allowed operators for this field. Defaults based on type if not provided. */\n operators?: ConditionOperator[]\n /** Options used by select and multi-select fields. Strings use the same label and value. */\n options?: ConditionFieldOption[]\n /** Show a search box for option-backed value inputs. */\n searchable?: boolean | { threshold?: number }\n}\n\nexport interface ConditionFilterValue {\n /** Stable identity — used as React key to avoid stale-state bugs on removal */\n id: string\n field: string\n operator: ConditionOperator\n value: string | number | string[] | null\n}\n\ninterface DataTableConditionFilterProps {\n /** Available fields the user can filter on */\n fields: ConditionFieldDef[]\n /** Current active conditions */\n conditions: ConditionFilterValue[]\n /** Called when conditions change (add, update, remove) */\n onConditionsChange: (conditions: ConditionFilterValue[]) => void\n className?: string\n}\n\n// ── Constants ──────────────────────────────────────────────────\n\nconst OPERATOR_LABELS: Record<ConditionOperator, string> = {\n eq: \"=\",\n neq: \"≠\",\n gt: \">\",\n gte: \"≥\",\n lt: \"<\",\n lte: \"≤\",\n in: \"is any of\",\n is_null: \"is empty\",\n is_not_null: \"is not empty\",\n}\n\nconst NUMERIC_OPERATORS: ConditionOperator[] = [\n \"eq\",\n \"neq\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"is_null\",\n \"is_not_null\",\n]\n\nconst DEFAULT_OPERATORS: Record<ConditionFieldDef[\"type\"], ConditionOperator[]> = {\n text: [\"eq\", \"neq\", \"is_null\", \"is_not_null\"],\n number: NUMERIC_OPERATORS,\n currency: NUMERIC_OPERATORS,\n date: [\"gt\", \"gte\", \"lt\", \"lte\", \"eq\", \"neq\", \"is_null\", \"is_not_null\"],\n select: [\"eq\", \"neq\", \"is_null\", \"is_not_null\"],\n multi_select: [\"in\", \"is_null\", \"is_not_null\"],\n}\n\n/** Generate a stable unique ID for a new condition row. */\nfunction generateConditionId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID()\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ── Helpers ────────────────────────────────────────────────────\n\nfunction getOperators(field: ConditionFieldDef): ConditionOperator[] {\n return field.operators ?? DEFAULT_OPERATORS[field.type]\n}\n\nfunction isUnaryOperator(op: ConditionOperator): boolean {\n return op === \"is_null\" || op === \"is_not_null\"\n}\n\nfunction getDefaultOperator(field: ConditionFieldDef): ConditionOperator {\n return getOperators(field)[0] ?? \"eq\"\n}\n\nfunction createDraftCondition(field: ConditionFieldDef): ConditionFilterValue {\n return {\n id: generateConditionId(),\n field: field.id,\n operator: getDefaultOperator(field),\n value: null,\n }\n}\n\nfunction normalizeConditionValue(\n value: ConditionFilterValue[\"value\"],\n field: ConditionFieldDef,\n operator: ConditionOperator,\n): ConditionFilterValue[\"value\"] {\n if (isUnaryOperator(operator)) return null\n if (field.type === \"multi_select\") {\n return Array.isArray(value) ? value : null\n }\n return Array.isArray(value) ? null : value\n}\n\nfunction normalizeCondition(\n condition: ConditionFilterValue,\n fields: ConditionFieldDef[],\n): ConditionFilterValue {\n const field = fields.find((f) => f.id === condition.field) ?? fields[0]\n if (!field) return condition\n\n const operators = getOperators(field)\n const operator = operators.includes(condition.operator)\n ? condition.operator\n : getDefaultOperator(field)\n\n return {\n ...condition,\n field: field.id,\n operator,\n value: normalizeConditionValue(condition.value, field, operator),\n }\n}\n\nfunction parseConditionValue(\n raw: string,\n fieldType: ConditionFieldDef[\"type\"],\n): string | number | null {\n if (raw === \"\") return null\n if (fieldType === \"number\" || fieldType === \"currency\") {\n const parsed = Number(raw)\n return Number.isNaN(parsed) ? null : parsed\n }\n return raw\n}\n\nfunction isCompleteCondition(\n condition: ConditionFilterValue,\n fields: ConditionFieldDef[],\n): boolean {\n const field = fields.find((f) => f.id === condition.field)\n if (!field) return false\n if (!getOperators(field).includes(condition.operator)) return false\n if (isUnaryOperator(condition.operator)) return true\n if (field.type === \"multi_select\") {\n return Array.isArray(condition.value) && condition.value.length > 0\n }\n return condition.value !== null && condition.value !== \"\" && !Array.isArray(condition.value)\n}\n\nfunction getConditionValueSignature(value: ConditionFilterValue[\"value\"]): string {\n return Array.isArray(value) ? JSON.stringify(value) : String(value)\n}\n\nfunction getConditionsSignature(conditions: ConditionFilterValue[]): string {\n return conditions\n .map((condition) => `${condition.id}:${condition.field}:${condition.operator}:${getConditionValueSignature(condition.value)}`)\n .join(\";\")\n}\n\nfunction normalizeFieldOptions(field: ConditionFieldDef): ConditionOptionObject[] {\n return (field.options ?? []).map((option) =>\n typeof option === \"string\" ? { label: option, value: option } : option,\n )\n}\n\nfunction getFieldsSignature(fields: ConditionFieldDef[]): string {\n return fields\n .map((field) => {\n const optionsSignature = normalizeFieldOptions(field)\n .map((option) => `${option.label}:${option.value}`)\n .join(\"|\")\n const searchSignature =\n typeof field.searchable === \"object\"\n ? `threshold:${field.searchable.threshold ?? \"\"}`\n : String(field.searchable ?? \"\")\n return `${field.id}:${field.type}:${field.label}:${(field.operators ?? []).join(\"|\")}:${optionsSignature}:${searchSignature}`\n })\n .join(\";\")\n}\n\nfunction getCommittedConditions(\n drafts: ConditionFilterValue[],\n fields: ConditionFieldDef[],\n): ConditionFilterValue[] {\n return drafts\n .map((condition) => normalizeCondition(condition, fields))\n .filter((condition) => isCompleteCondition(condition, fields))\n}\n\nconst FIELD_ICON_BY_TYPE: Record<ConditionFieldDef[\"type\"], LucideIcon> = {\n text: Type,\n number: Hash,\n currency: DollarSign,\n date: CalendarDays,\n select: MoreHorizontal,\n multi_select: MoreHorizontal,\n}\n\nfunction getFieldIcon(type: ConditionFieldDef[\"type\"]): LucideIcon {\n return FIELD_ICON_BY_TYPE[type]\n}\n\n// ── Condition Row ──────────────────────────────────────────────\n\nfunction getInputType(fieldType: ConditionFieldDef[\"type\"]): \"text\" | \"number\" | \"date\" {\n if (fieldType === \"number\" || fieldType === \"currency\") return \"number\"\n if (fieldType === \"date\") return \"date\"\n return \"text\"\n}\n\nfunction getInputPlaceholder(fieldType: ConditionFieldDef[\"type\"]): string {\n if (fieldType === \"currency\") return \"Amount\"\n if (fieldType === \"number\") return \"Enter number...\"\n if (fieldType === \"date\") return \"\"\n return \"Enter value...\"\n}\n\ninterface ConditionValueInputProps {\n condition: ConditionFilterValue\n fieldDef: ConditionFieldDef\n onValueChange: (event: React.ChangeEvent<HTMLInputElement>) => void\n onSelectValueChange: (value: string) => void\n onMultiSelectValueToggle: (value: string) => void\n onCommit: () => void\n}\n\nfunction shouldShowOptionSearch(\n fieldDef: ConditionFieldDef,\n optionCount: number,\n): boolean {\n if (fieldDef.searchable === true) return true\n if (fieldDef.searchable === false) return false\n if (typeof fieldDef.searchable === \"object\") {\n return optionCount >= (fieldDef.searchable.threshold ?? 8)\n }\n return false\n}\n\nfunction SelectConditionValueInput({\n condition,\n fieldDef,\n onSelectValueChange,\n}: Pick<ConditionValueInputProps, \"condition\" | \"fieldDef\" | \"onSelectValueChange\">) {\n const [query, setQuery] = React.useState(\"\")\n const options = normalizeFieldOptions(fieldDef)\n const normalizedQuery = query.trim().toLowerCase()\n const filteredOptions = normalizedQuery\n ? options.filter((option) => option.label.toLowerCase().includes(normalizedQuery))\n : options\n const showSearch = shouldShowOptionSearch(fieldDef, options.length)\n\n return (\n <Select\n value={typeof condition.value === \"string\" ? condition.value : \"\"}\n onValueChange={onSelectValueChange}\n >\n <SelectTrigger className=\"h-8 w-full\" size=\"sm\">\n <SelectValue placeholder=\"Select value...\" />\n </SelectTrigger>\n <SelectContent>\n {showSearch ? (\n <div className=\"sticky top-0 z-10 border-b border-border bg-popover p-1.5\">\n <Input\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n placeholder=\"Search options...\"\n className=\"h-7 text-xs\"\n />\n </div>\n ) : null}\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))\n ) : (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">No options</div>\n )}\n </SelectContent>\n </Select>\n )\n}\n\nfunction MultiSelectConditionValueInput({\n condition,\n fieldDef,\n onMultiSelectValueToggle,\n}: Pick<ConditionValueInputProps, \"condition\" | \"fieldDef\" | \"onMultiSelectValueToggle\">) {\n const selectedValues = Array.isArray(condition.value) ? condition.value : []\n const options = normalizeFieldOptions(fieldDef)\n\n return (\n <div className=\"max-h-28 overflow-y-auto rounded-md border border-border bg-background p-1\">\n {options.length > 0 ? (\n options.map((option) => {\n const checked = selectedValues.includes(option.value)\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"checkbox\"\n aria-checked={checked}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1 text-left text-xs hover:bg-muted\",\n checked && \"text-brand-purple\",\n )}\n onClick={(event) => {\n event.stopPropagation()\n onMultiSelectValueToggle(option.value)\n }}\n >\n <span\n className={cn(\n \"flex h-3.5 w-3.5 items-center justify-center rounded-sm border border-border\",\n checked && \"border-brand-purple bg-brand-purple text-white\",\n )}\n aria-hidden=\"true\"\n >\n {checked ? <Check className=\"h-3 w-3\" /> : null}\n </span>\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n </button>\n )\n })\n ) : (\n <div className=\"px-2 py-1 text-xs text-muted-foreground\">No options</div>\n )}\n </div>\n )\n}\n\nfunction ScalarConditionValueInput({\n condition,\n fieldDef,\n onValueChange,\n onCommit,\n}: Pick<ConditionValueInputProps, \"condition\" | \"fieldDef\" | \"onValueChange\" | \"onCommit\">) {\n return (\n <div className=\"relative flex items-center\">\n {fieldDef.type === \"currency\" ? (\n <span className=\"pointer-events-none absolute left-2 text-sm text-muted-foreground\">\n $\n </span>\n ) : null}\n <Input\n type={getInputType(fieldDef.type)}\n value={\n condition.value != null && !Array.isArray(condition.value)\n ? String(condition.value)\n : \"\"\n }\n onChange={onValueChange}\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n event.stopPropagation()\n if (event.key === \"Enter\") {\n onCommit()\n }\n }}\n placeholder={getInputPlaceholder(fieldDef.type)}\n className={cn(\"h-8\", fieldDef.type === \"currency\" && \"pl-6\")}\n />\n </div>\n )\n}\n\nfunction ConditionValueInput(props: ConditionValueInputProps) {\n if (props.fieldDef.type === \"select\") {\n return <SelectConditionValueInput {...props} />\n }\n\n if (props.fieldDef.type === \"multi_select\") {\n return <MultiSelectConditionValueInput {...props} />\n }\n\n return <ScalarConditionValueInput {...props} />\n}\n\ninterface ConditionRowProps {\n condition: ConditionFilterValue\n fields: ConditionFieldDef[]\n index: number\n onChange: (updated: ConditionFilterValue) => void\n onRemove: () => void\n onCommit: () => void\n}\n\nfunction ConditionRow({\n condition,\n fields,\n index,\n onChange,\n onRemove,\n onCommit,\n}: ConditionRowProps) {\n const fieldDef = fields.find((f) => f.id === condition.field) ?? fields[0]\n const operators = getOperators(fieldDef)\n const isUnary = isUnaryOperator(condition.operator)\n const FieldIcon = getFieldIcon(fieldDef.type)\n\n const handleFieldChange = (newFieldId: string) => {\n const newFieldDef = fields.find((f) => f.id === newFieldId) ?? fields[0]\n if (!newFieldDef) return\n onChange({\n ...condition,\n field: newFieldDef.id,\n operator: getDefaultOperator(newFieldDef),\n value: null,\n })\n }\n\n const handleOperatorChange = (newOp: ConditionOperator) => {\n onChange({\n ...condition,\n operator: newOp,\n value: normalizeConditionValue(condition.value, fieldDef, newOp),\n })\n }\n\n const handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n onChange({\n ...condition,\n value: parseConditionValue(event.target.value, fieldDef.type),\n })\n }\n\n const handleSelectValueChange = (value: string) => {\n onChange({\n ...condition,\n value,\n })\n }\n\n const handleMultiSelectValueToggle = (value: string) => {\n const currentValues = Array.isArray(condition.value) ? condition.value : []\n const nextValues = currentValues.includes(value)\n ? currentValues.filter((currentValue) => currentValue !== value)\n : [...currentValues, value]\n\n onChange({\n ...condition,\n value: nextValues,\n })\n }\n\n\n return (\n <div\n className=\"grid grid-cols-[52px_minmax(150px,1fr)_120px_minmax(140px,1fr)_auto] items-center gap-2 rounded-lg border border-border/70 bg-background p-2 shadow-sm\"\n data-slot=\"condition-row\"\n >\n <div className=\"text-xs font-medium text-muted-foreground\">\n {index === 0 ? \"Where\" : \"And\"}\n </div>\n\n <Select value={condition.field} onValueChange={handleFieldChange}>\n <SelectTrigger className=\"h-8 w-full justify-start gap-2\" size=\"sm\">\n <FieldIcon className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <SelectValue placeholder={fieldDef.label} />\n </SelectTrigger>\n <SelectContent>\n {fields.map((field) => {\n const Icon = getFieldIcon(field.type)\n return (\n <SelectItem key={field.id} value={field.id}>\n <span className=\"inline-flex items-center gap-2\">\n <Icon className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {field.label}\n </span>\n </SelectItem>\n )\n })}\n </SelectContent>\n </Select>\n\n <Select\n value={condition.operator}\n onValueChange={(value) => handleOperatorChange(value as ConditionOperator)}\n >\n <SelectTrigger className=\"h-8 w-full\" size=\"sm\">\n <SelectValue placeholder=\"Operator\" />\n </SelectTrigger>\n <SelectContent>\n {operators.map((op) => (\n <SelectItem key={op} value={op}>\n {OPERATOR_LABELS[op]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {isUnary ? (\n <div className=\"h-8 rounded-md border border-dashed border-border/70 bg-muted/30 px-3 py-1.5 text-xs text-muted-foreground\">\n No value needed\n </div>\n ) : (\n <ConditionValueInput\n condition={condition}\n fieldDef={fieldDef}\n onValueChange={handleValueChange}\n onSelectValueChange={handleSelectValueChange}\n onMultiSelectValueToggle={handleMultiSelectValueToggle}\n onCommit={onCommit}\n />\n )}\n\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-muted-foreground\"\n aria-label=\"Toggle condition visibility\"\n onClick={(event) => event.preventDefault()}\n >\n <Eye className=\"size-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-muted-foreground\"\n aria-label=\"More condition actions\"\n onClick={(event) => event.preventDefault()}\n >\n <MoreHorizontal className=\"size-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-muted-foreground hover:text-destructive\"\n onClick={onRemove}\n aria-label=\"Remove condition\"\n >\n <Trash2 className=\"size-4\" />\n </Button>\n </div>\n </div>\n )\n}\n\n// ── Main Component ─────────────────────────────────────────────\n\nfunction DataTableConditionFilter({\n fields,\n conditions,\n onConditionsChange,\n className,\n}: DataTableConditionFilterProps) {\n const [drafts, setDrafts] = React.useState<ConditionFilterValue[]>(() =>\n conditions.map((condition) => normalizeCondition(condition, fields)),\n )\n\n const fieldsSignature = React.useMemo(() => getFieldsSignature(fields), [fields])\n const conditionsSignature = React.useMemo(() => getConditionsSignature(conditions), [conditions])\n const fieldsRef = React.useRef(fields)\n\n React.useEffect(() => {\n setDrafts(conditions.map((condition) => normalizeCondition(condition, fieldsRef.current)))\n }, [conditionsSignature])\n\n React.useEffect(() => {\n if (fieldsRef.current !== fields) {\n fieldsRef.current = fields\n setDrafts((current) => current.map((condition) => normalizeCondition(condition, fields)))\n }\n // Depend on a structural signature so inline-but-equivalent field arrays do\n // not wipe in-progress drafts before Apply.\n }, [fieldsSignature, fields])\n\n const commitDrafts = React.useCallback(\n (nextDrafts: ConditionFilterValue[] = drafts) => {\n onConditionsChange(getCommittedConditions(nextDrafts, fields))\n },\n [drafts, fields, onConditionsChange],\n )\n\n const handleAdd = () => {\n const firstField = fields[0]\n if (!firstField) return\n const committedDrafts = getCommittedConditions(drafts, fields)\n const nextDrafts = [...committedDrafts, createDraftCondition(firstField)]\n setDrafts(nextDrafts)\n onConditionsChange(committedDrafts)\n }\n\n const handleUpdate = (index: number, updated: ConditionFilterValue) => {\n setDrafts((current) => {\n const next = [...current]\n next[index] = normalizeCondition(updated, fields)\n return next\n })\n }\n\n const handleRemove = (index: number) => {\n setDrafts((current) => {\n const next = current.filter((_, currentIndex) => currentIndex !== index)\n commitDrafts(next)\n return next\n })\n }\n\n const handleClear = () => {\n setDrafts([])\n onConditionsChange([])\n }\n\n const hasAppliedConditions = conditions.length > 0\n const hasDrafts = drafts.length > 0\n\n return (\n <div\n className={cn(\n \"w-[min(760px,calc(100vw-2rem))] rounded-xl border border-border bg-background p-3 text-foreground shadow-xl\",\n className,\n )}\n data-slot=\"condition-filter\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") {\n event.stopPropagation()\n }\n }}\n >\n <div className=\"mb-3 flex items-center justify-between gap-3 border-b border-border/70 pb-3\">\n <div>\n <div className=\"text-sm font-semibold\">Filter builder</div>\n <div className=\"text-xs text-muted-foreground\">\n Build field, operator, and value conditions.\n </div>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs text-destructive hover:text-destructive\"\n onClick={handleClear}\n disabled={!hasAppliedConditions && !hasDrafts}\n >\n Clear filters\n </Button>\n </div>\n\n <div className=\"flex flex-col gap-2\">\n {drafts.map((condition, index) => (\n <ConditionRow\n key={condition.id}\n condition={condition}\n fields={fields}\n index={index}\n onChange={(updated) => handleUpdate(index, updated)}\n onRemove={() => handleRemove(index)}\n onCommit={() => commitDrafts()}\n />\n ))}\n </div>\n\n {!hasDrafts ? (\n <div className=\"rounded-lg border border-dashed border-border/80 bg-muted/20 px-3 py-5 text-center text-xs text-muted-foreground\">\n No builder filters yet. Add a filter to start a condition row.\n </div>\n ) : null}\n\n <div className=\"mt-3 flex flex-wrap items-center justify-between gap-2 border-t border-border/70 pt-3\">\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs text-muted-foreground\"\n onClick={handleAdd}\n >\n <Plus className=\"mr-1 size-3.5\" />\n Add filter\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs text-muted-foreground opacity-60\"\n disabled\n aria-disabled=\"true\"\n >\n <Plus className=\"mr-1 size-3.5\" />\n Add filter group\n </Button>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-8 text-xs\"\n onClick={() => commitDrafts()}\n >\n Apply\n </Button>\n </div>\n </div>\n )\n}\n\nexport {\n DataTableConditionFilter,\n OPERATOR_LABELS,\n DEFAULT_OPERATORS,\n generateConditionId,\n getOperators,\n}\nexport type { DataTableConditionFilterProps }\n"],"mappings":"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","names":["_a"]}
|
|
@@ -120,7 +120,7 @@ function DataTableFilter({
|
|
|
120
120
|
children: [
|
|
121
121
|
/* @__PURE__ */ jsx(ListFilter, { className: "h-3.5 w-3.5" }),
|
|
122
122
|
"Filter",
|
|
123
|
-
activeCount > 0 ? /* @__PURE__ */ jsx("span", { className: "rounded bg-muted px-1.5 py-0 text-[10px] font-semibold
|
|
123
|
+
activeCount > 0 ? /* @__PURE__ */ jsx("span", { className: "rounded bg-muted px-1.5 py-0 text-[10px] font-semibold", children: activeCount }) : null
|
|
124
124
|
]
|
|
125
125
|
}
|
|
126
126
|
) }),
|