hazo_ui 1.0.1 → 1.0.2
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/README.md +250 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,18 +8,263 @@ A set of UI components for common interaction elements in a SaaS app.
|
|
|
8
8
|
npm install hazo_ui
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Components
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### MultiFilterDialog
|
|
14
|
+
|
|
15
|
+
A powerful, flexible dialog component for multi-field filtering with support for various input types. Perfect for table headers, grid views, or any interface where users need to apply multiple filters simultaneously.
|
|
16
|
+
|
|
17
|
+
#### Features
|
|
18
|
+
|
|
19
|
+
- **Multiple Field Types**: Supports text, number, combobox (select), boolean, and date fields
|
|
20
|
+
- **Operator Support**: Number and date fields support comparison operators (equals, greater than, less than, etc.)
|
|
21
|
+
- **Dynamic Field Addition**: Users can add and remove filter fields dynamically
|
|
22
|
+
- **Field Validation**: Built-in validation for text length, number ranges, and decimal precision
|
|
23
|
+
- **Visual Feedback**: Tooltip shows active filters when hovering over the filter button
|
|
24
|
+
- **Responsive Design**: Works seamlessly on mobile and desktop devices
|
|
25
|
+
- **TypeScript Support**: Fully typed with TypeScript interfaces
|
|
26
|
+
- **Accessible**: Built with accessibility in mind using Radix UI primitives
|
|
27
|
+
|
|
28
|
+
#### Field Types
|
|
29
|
+
|
|
30
|
+
1. **Text Fields**
|
|
31
|
+
- Configurable min/max length
|
|
32
|
+
- Real-time validation
|
|
33
|
+
|
|
34
|
+
2. **Number Fields**
|
|
35
|
+
- Min/max value constraints
|
|
36
|
+
- Optional decimal support with precision control
|
|
37
|
+
- Comparison operators: equals, not equals, greater than, less than, greater or equal, less or equal
|
|
38
|
+
|
|
39
|
+
3. **Combobox Fields**
|
|
40
|
+
- Dropdown selection from predefined options
|
|
41
|
+
- Searchable field selection
|
|
42
|
+
|
|
43
|
+
4. **Boolean Fields**
|
|
44
|
+
- Custom true/false labels
|
|
45
|
+
- Simple toggle selection
|
|
46
|
+
|
|
47
|
+
5. **Date Fields**
|
|
48
|
+
- Calendar picker interface
|
|
49
|
+
- Comparison operators for date ranges
|
|
50
|
+
- Formatted display (e.g., "Nov 6, 2025")
|
|
51
|
+
|
|
52
|
+
#### Usage
|
|
14
53
|
|
|
15
54
|
```tsx
|
|
16
|
-
import {
|
|
55
|
+
import { MultiFilterDialog, type FilterField, type FilterConfig } from 'hazo_ui';
|
|
56
|
+
import { useState } from 'react';
|
|
57
|
+
|
|
58
|
+
function DataTable() {
|
|
59
|
+
const [filters, setFilters] = useState<FilterConfig[]>([]);
|
|
60
|
+
|
|
61
|
+
// Define available filter fields
|
|
62
|
+
const availableFields: FilterField[] = [
|
|
63
|
+
{
|
|
64
|
+
value: "name",
|
|
65
|
+
label: "Name",
|
|
66
|
+
type: "text",
|
|
67
|
+
textConfig: {
|
|
68
|
+
minLength: 2,
|
|
69
|
+
maxLength: 50,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
value: "age",
|
|
74
|
+
label: "Age",
|
|
75
|
+
type: "number",
|
|
76
|
+
numberConfig: {
|
|
77
|
+
min: 0,
|
|
78
|
+
max: 120,
|
|
79
|
+
allowDecimal: false,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
value: "price",
|
|
84
|
+
label: "Price",
|
|
85
|
+
type: "number",
|
|
86
|
+
numberConfig: {
|
|
87
|
+
min: 0,
|
|
88
|
+
max: 10000,
|
|
89
|
+
allowDecimal: true,
|
|
90
|
+
decimalLength: 2,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
value: "status",
|
|
95
|
+
label: "Status",
|
|
96
|
+
type: "combobox",
|
|
97
|
+
comboboxOptions: [
|
|
98
|
+
{ label: "Active", value: "active" },
|
|
99
|
+
{ label: "Inactive", value: "inactive" },
|
|
100
|
+
{ label: "Pending", value: "pending" },
|
|
101
|
+
{ label: "Completed", value: "completed" },
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: "is_verified",
|
|
106
|
+
label: "Verified",
|
|
107
|
+
type: "boolean",
|
|
108
|
+
booleanLabels: {
|
|
109
|
+
trueLabel: "Yes",
|
|
110
|
+
falseLabel: "No",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
value: "created_date",
|
|
115
|
+
label: "Created Date",
|
|
116
|
+
type: "date",
|
|
117
|
+
},
|
|
118
|
+
];
|
|
17
119
|
|
|
18
|
-
|
|
19
|
-
|
|
120
|
+
// Handle filter changes
|
|
121
|
+
const handleFilterChange = (filterConfig: FilterConfig[]) => {
|
|
122
|
+
setFilters(filterConfig);
|
|
123
|
+
// Apply filters to your data
|
|
124
|
+
console.log('Applied filters:', filterConfig);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div>
|
|
129
|
+
<MultiFilterDialog
|
|
130
|
+
availableFields={availableFields}
|
|
131
|
+
onFilterChange={handleFilterChange}
|
|
132
|
+
initialFilters={filters}
|
|
133
|
+
/>
|
|
134
|
+
{/* Your table/grid component */}
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
20
137
|
}
|
|
21
138
|
```
|
|
22
139
|
|
|
140
|
+
#### Example Input
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
// Available fields configuration
|
|
144
|
+
const availableFields: FilterField[] = [
|
|
145
|
+
{
|
|
146
|
+
value: "name",
|
|
147
|
+
label: "Name",
|
|
148
|
+
type: "text",
|
|
149
|
+
textConfig: {
|
|
150
|
+
minLength: 2,
|
|
151
|
+
maxLength: 50,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
value: "age",
|
|
156
|
+
label: "Age",
|
|
157
|
+
type: "number",
|
|
158
|
+
numberConfig: {
|
|
159
|
+
min: 0,
|
|
160
|
+
max: 120,
|
|
161
|
+
allowDecimal: false,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
value: "status",
|
|
166
|
+
label: "Status",
|
|
167
|
+
type: "combobox",
|
|
168
|
+
comboboxOptions: [
|
|
169
|
+
{ label: "Active", value: "active" },
|
|
170
|
+
{ label: "Inactive", value: "inactive" },
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
// Initial filters (optional)
|
|
176
|
+
const initialFilters: FilterConfig[] = [
|
|
177
|
+
{
|
|
178
|
+
field: "name",
|
|
179
|
+
value: "John",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
field: "age",
|
|
183
|
+
operator: "greater_than",
|
|
184
|
+
value: 25,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Expected Output
|
|
190
|
+
|
|
191
|
+
When users apply filters, the `onFilterChange` callback receives an array of `FilterConfig` objects:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Example output when user applies filters:
|
|
195
|
+
[
|
|
196
|
+
{
|
|
197
|
+
field: "name",
|
|
198
|
+
value: "John"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
field: "age",
|
|
202
|
+
operator: "greater_than",
|
|
203
|
+
value: 25
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
field: "status",
|
|
207
|
+
value: "active"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
field: "is_verified",
|
|
211
|
+
value: true
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
field: "created_date",
|
|
215
|
+
operator: "greater_equal",
|
|
216
|
+
value: Date // JavaScript Date object
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### TypeScript Interfaces
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
interface FilterField {
|
|
225
|
+
value: string; // Unique identifier for the field
|
|
226
|
+
label: string; // Display label
|
|
227
|
+
type: 'text' | 'number' | 'combobox' | 'boolean' | 'date';
|
|
228
|
+
textConfig?: {
|
|
229
|
+
minLength?: number;
|
|
230
|
+
maxLength?: number;
|
|
231
|
+
};
|
|
232
|
+
numberConfig?: {
|
|
233
|
+
min?: number;
|
|
234
|
+
max?: number;
|
|
235
|
+
allowDecimal?: boolean;
|
|
236
|
+
decimalLength?: number;
|
|
237
|
+
};
|
|
238
|
+
comboboxOptions?: Array<{ label: string; value: string }>;
|
|
239
|
+
booleanLabels?: {
|
|
240
|
+
trueLabel?: string;
|
|
241
|
+
falseLabel?: string;
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface FilterConfig {
|
|
246
|
+
field: string; // Field identifier
|
|
247
|
+
operator?: string; // For number/date: 'equals', 'not_equals', 'greater_than', 'less_than', 'greater_equal', 'less_equal'
|
|
248
|
+
value: any; // Filter value (string, number, boolean, or Date)
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Styling
|
|
253
|
+
|
|
254
|
+
The component uses Tailwind CSS and follows shadcn/ui design patterns. Make sure your project has Tailwind CSS configured with the following CSS variables:
|
|
255
|
+
|
|
256
|
+
```css
|
|
257
|
+
:root {
|
|
258
|
+
--background: 0 0% 100%;
|
|
259
|
+
--foreground: 222.2 84% 4.9%;
|
|
260
|
+
--primary: 222.2 47.4% 11.2%;
|
|
261
|
+
--primary-foreground: 210 40% 98%;
|
|
262
|
+
/* ... other CSS variables */
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
See the component library's Tailwind config for the complete set of CSS variables.
|
|
267
|
+
|
|
23
268
|
## Development
|
|
24
269
|
|
|
25
270
|
### Build the library
|
|
@@ -50,4 +295,3 @@ npm run test:dev
|
|
|
50
295
|
## License
|
|
51
296
|
|
|
52
297
|
MIT
|
|
53
|
-
|