hazo_ui 1.1.0 → 2.0.1

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 CHANGED
@@ -10,17 +10,25 @@ npm install hazo_ui
10
10
 
11
11
  ## Components
12
12
 
13
- ### MultiFilterDialog
13
+ ### Component Overview
14
+
15
+ - **[MultiFilterDialog](#multifilterdialog)** - A powerful dialog component for multi-field filtering with support for text, number, combobox, boolean, and date fields. Includes operator support, validation, and visual feedback.
16
+
17
+ - **[MultiSortDialog](#multisortdialog)** - A flexible dialog component for multi-field sorting with drag-and-drop reordering. Allows users to set sort priority and direction (ascending/descending) for multiple fields.
18
+
19
+ ---
20
+
21
+ ## MultiFilterDialog
14
22
 
15
23
  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
24
 
17
- ![MultiFilterDialog - Dialog with Multiple Filters](https://github.com/pub12/hazo_ui/raw/main/docs/Screenshot%202025-11-06%20at%202.51.24%E2%80%AFPM.png)
25
+ ![MultiFilterDialog - Filter Button with Active Filters Tooltip](https://github.com/pub12/hazo_ui/raw/main/docs/multifilterdialog/filter-button-tooltip.png)
18
26
 
19
- ![MultiFilterDialog - Filter Button with Active Filters Tooltip](https://github.com/pub12/hazo_ui/raw/main/docs/Screenshot%202025-11-06%20at%202.51.34%E2%80%AFPM.png)
27
+ ![MultiFilterDialog - Dialog with Multiple Filters](https://github.com/pub12/hazo_ui/raw/main/docs/multifilterdialog/filter-dialog.png)
20
28
 
21
- ![MultiFilterDialog - Calendar Date Picker](https://github.com/pub12/hazo_ui/raw/main/docs/Screenshot%202025-11-06%20at%202.51.37%E2%80%AFPM.png)
29
+ ![MultiFilterDialog - Calendar Date Picker](https://github.com/pub12/hazo_ui/raw/main/docs/multifilterdialog/filter-dialog-calendar.png)
22
30
 
23
- ![MultiFilterDialog - Filter Output Example](https://github.com/pub12/hazo_ui/raw/main/docs/Screenshot%202025-11-06%20at%202.51.53%E2%80%AFPM.png)
31
+ ![MultiFilterDialog - Filter Output Example](https://github.com/pub12/hazo_ui/raw/main/docs/multifilterdialog/filter-output.png)
24
32
 
25
33
  #### Features
26
34
 
@@ -29,6 +37,7 @@ A powerful, flexible dialog component for multi-field filtering with support for
29
37
  - **Dynamic Field Addition**: Users can add and remove filter fields dynamically
30
38
  - **Field Validation**: Built-in validation for text length, number ranges, and decimal precision
31
39
  - **Visual Feedback**: Tooltip shows active filters when hovering over the filter button
40
+ - **Clear All Button**: Quickly clear all filters at once
32
41
  - **Responsive Design**: Works seamlessly on mobile and desktop devices
33
42
  - **TypeScript Support**: Fully typed with TypeScript interfaces
34
43
  - **Accessible**: Built with accessibility in mind using Radix UI primitives
@@ -226,40 +235,218 @@ When users apply filters, the `onFilterChange` callback receives an array of `Fi
226
235
  ]
227
236
  ```
228
237
 
238
+ ---
239
+
240
+ ## MultiSortDialog
241
+
242
+ A powerful dialog component for multi-field sorting with drag-and-drop reordering. Allows users to select multiple fields for sorting, reorder them by priority, and set ascending/descending direction for each field.
243
+
244
+ ![MultiSortDialog - Sort Button with Active Sorts Tooltip](https://github.com/pub12/hazo_ui/raw/main/docs/multisortdialog/sort-button-tooltip.png)
245
+
246
+ ![MultiSortDialog - Dialog with Multiple Sort Fields](https://github.com/pub12/hazo_ui/raw/main/docs/multisortdialog/sort-dialog.png)
247
+
248
+ ![MultiSortDialog - Drag and Drop Reordering](https://github.com/pub12/hazo_ui/raw/main/docs/multisortdialog/sort-drag-drop.png)
249
+
250
+ ![MultiSortDialog - Sort Output Example](https://github.com/pub12/hazo_ui/raw/main/docs/multisortdialog/sort-output.png)
251
+
252
+ #### Features
253
+
254
+ - **Drag-and-Drop Reordering**: Intuitively reorder sort fields by dragging them
255
+ - **Multiple Sort Fields**: Add multiple fields to sort by with priority ordering
256
+ - **Direction Toggle**: Switch between ascending and descending for each field
257
+ - **Visual Feedback**: Drag handle with grip icon, opacity changes during drag
258
+ - **Clear All Button**: Quickly clear all sort fields at once
259
+ - **Tooltip Display**: Shows active sort configuration when hovering over the sort button
260
+ - **Keyboard Accessible**: Full keyboard navigation support for drag and drop
261
+ - **Responsive Design**: Works seamlessly on mobile and desktop devices
262
+ - **TypeScript Support**: Fully typed with TypeScript interfaces
263
+ - **Accessible**: Built with accessibility in mind using Radix UI primitives
264
+
265
+ #### How It Works
266
+
267
+ 1. **Adding Sort Fields**: Click the "Add field" button to select from available fields
268
+ 2. **Reordering**: Drag fields using the grip icon (⋮⋮) to change their priority
269
+ 3. **Changing Direction**: Toggle the switch next to each field to change between ascending (A→Z, 0→9) and descending (Z→A, 9→0)
270
+ 4. **Removing Fields**: Click the trash icon to remove a field from sorting
271
+ 5. **Applying Sorts**: Click "Apply" to save the sort configuration
272
+ 6. **Clearing All**: Click "Clear All" to remove all sort fields at once
273
+
274
+ The component returns an array of sort configurations in priority order, where the first item is the primary sort field, second is secondary, and so on.
275
+
276
+ #### Usage
277
+
278
+ ```tsx
279
+ import { MultiSortDialog, type SortField, type SortConfig } from 'hazo_ui';
280
+ import { useState } from 'react';
281
+
282
+ function DataTable() {
283
+ const [sorts, setSorts] = useState<SortConfig[]>([]);
284
+
285
+ // Define available sort fields
286
+ const availableFields: SortField[] = [
287
+ {
288
+ value: "name",
289
+ label: "Name",
290
+ },
291
+ {
292
+ value: "age",
293
+ label: "Age",
294
+ },
295
+ {
296
+ value: "price",
297
+ label: "Price",
298
+ },
299
+ {
300
+ value: "status",
301
+ label: "Status",
302
+ },
303
+ {
304
+ value: "created_date",
305
+ label: "Created Date",
306
+ },
307
+ ];
308
+
309
+ // Handle sort changes
310
+ const handleSortChange = (sortConfig: SortConfig[]) => {
311
+ setSorts(sortConfig);
312
+ // Apply sorts to your data
313
+ console.log('Applied sorts:', sortConfig);
314
+ // Sort your data based on the configuration
315
+ // First item is primary sort, second is secondary, etc.
316
+ };
317
+
318
+ return (
319
+ <div>
320
+ <MultiSortDialog
321
+ availableFields={availableFields}
322
+ onSortChange={handleSortChange}
323
+ initialSortFields={sorts}
324
+ />
325
+ {/* Your table/grid component */}
326
+ </div>
327
+ );
328
+ }
329
+ ```
330
+
331
+ #### Example Input
332
+
333
+ ```tsx
334
+ // Available sort fields configuration
335
+ const availableFields: SortField[] = [
336
+ {
337
+ value: "name",
338
+ label: "Name",
339
+ },
340
+ {
341
+ value: "price",
342
+ label: "Price",
343
+ },
344
+ {
345
+ value: "created_date",
346
+ label: "Created Date",
347
+ },
348
+ ];
349
+
350
+ // Initial sort fields (optional)
351
+ const initialSortFields: SortConfig[] = [
352
+ {
353
+ field: "name",
354
+ direction: "asc",
355
+ },
356
+ {
357
+ field: "price",
358
+ direction: "desc",
359
+ },
360
+ ];
361
+ ```
362
+
363
+ #### Expected Output
364
+
365
+ When users apply sorts, the `onSortChange` callback receives an array of `SortConfig` objects in priority order:
366
+
367
+ ```typescript
368
+ // Example output when user applies sorts:
369
+ [
370
+ {
371
+ field: "name",
372
+ direction: "asc" // Primary sort: Name ascending
373
+ },
374
+ {
375
+ field: "price",
376
+ direction: "desc" // Secondary sort: Price descending
377
+ },
378
+ {
379
+ field: "created_date",
380
+ direction: "desc" // Tertiary sort: Created Date descending
381
+ }
382
+ ]
383
+ ```
384
+
385
+ **Important**: The order of the array matters! The first item is the primary sort field, the second is secondary, and so on. This allows for multi-level sorting (e.g., sort by name first, then by price for items with the same name).
386
+
229
387
  #### TypeScript Interfaces
230
388
 
231
389
  ```typescript
232
- interface FilterField {
233
- value: string; // Unique identifier for the field
234
- label: string; // Display label
235
- type: 'text' | 'number' | 'combobox' | 'boolean' | 'date';
236
- textConfig?: {
237
- minLength?: number;
238
- maxLength?: number;
239
- };
240
- numberConfig?: {
241
- min?: number;
242
- max?: number;
243
- allowDecimal?: boolean;
244
- decimalLength?: number;
245
- };
246
- comboboxOptions?: Array<{ label: string; value: string }>;
247
- booleanLabels?: {
248
- trueLabel?: string;
249
- falseLabel?: string;
250
- };
390
+ interface SortField {
391
+ value: string; // Unique identifier for the field
392
+ label: string; // Display label
251
393
  }
252
394
 
253
- interface FilterConfig {
254
- field: string; // Field identifier
255
- operator?: string; // For number/date: 'equals', 'not_equals', 'greater_than', 'less_than', 'greater_equal', 'less_equal'
256
- value: any; // Filter value (string, number, boolean, or Date)
395
+ interface SortConfig {
396
+ field: string; // Field identifier
397
+ direction: 'asc' | 'desc'; // Sort direction: 'asc' for ascending, 'desc' for descending
257
398
  }
258
399
  ```
259
400
 
260
- #### Styling
401
+ #### Implementing the Sort Logic
402
+
403
+ Here's an example of how to apply the sort configuration to your data:
404
+
405
+ ```typescript
406
+ function applySorts(data: any[], sortConfigs: SortConfig[]): any[] {
407
+ if (sortConfigs.length === 0) return data;
408
+
409
+ return [...data].sort((a, b) => {
410
+ for (const sortConfig of sortConfigs) {
411
+ const aValue = a[sortConfig.field];
412
+ const bValue = b[sortConfig.field];
413
+
414
+ let comparison = 0;
415
+
416
+ // Handle different value types
417
+ if (typeof aValue === 'string' && typeof bValue === 'string') {
418
+ comparison = aValue.localeCompare(bValue);
419
+ } else if (aValue instanceof Date && bValue instanceof Date) {
420
+ comparison = aValue.getTime() - bValue.getTime();
421
+ } else {
422
+ comparison = (aValue ?? 0) - (bValue ?? 0);
423
+ }
424
+
425
+ // Apply direction
426
+ if (sortConfig.direction === 'desc') {
427
+ comparison = -comparison;
428
+ }
429
+
430
+ // If values are different, return the comparison
431
+ // Otherwise, continue to next sort field
432
+ if (comparison !== 0) {
433
+ return comparison;
434
+ }
435
+ }
436
+
437
+ return 0; // All sort fields are equal
438
+ });
439
+ }
440
+
441
+ // Usage
442
+ const sortedData = applySorts(originalData, sorts);
443
+ ```
444
+
445
+ ---
446
+
447
+ ## Styling
261
448
 
262
- The component uses Tailwind CSS and follows shadcn/ui design patterns. Make sure your project has Tailwind CSS configured with the following CSS variables:
449
+ Both components use Tailwind CSS and follow shadcn/ui design patterns. Make sure your project has Tailwind CSS configured with the following CSS variables:
263
450
 
264
451
  ```css
265
452
  :root {
@@ -267,7 +454,18 @@ The component uses Tailwind CSS and follows shadcn/ui design patterns. Make sure
267
454
  --foreground: 222.2 84% 4.9%;
268
455
  --primary: 222.2 47.4% 11.2%;
269
456
  --primary-foreground: 210 40% 98%;
270
- /* ... other CSS variables */
457
+ --secondary: 210 40% 96.1%;
458
+ --secondary-foreground: 222.2 47.4% 11.2%;
459
+ --muted: 210 40% 96.1%;
460
+ --muted-foreground: 215.4 16.3% 46.9%;
461
+ --accent: 210 40% 96.1%;
462
+ --accent-foreground: 222.2 47.4% 11.2%;
463
+ --destructive: 0 84.2% 60.2%;
464
+ --destructive-foreground: 210 40% 98%;
465
+ --border: 214.3 31.8% 91.4%;
466
+ --input: 214.3 31.8% 91.4%;
467
+ --ring: 222.2 84% 4.9%;
468
+ --radius: 0.5rem;
271
469
  }
272
470
  ```
273
471