hazo_ui 2.2.0 → 2.2.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 +277 -0
- package/dist/index.cjs +11 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@ npm install hazo_ui
|
|
|
18
18
|
|
|
19
19
|
- **[HazoUiFlexRadio](#hazouiflexradio)** - A flexible radio button/icon selection component with support for single and multi-selection modes, customizable layouts, and react-icons integration. Perfect for settings panels, preference selection, and option groups.
|
|
20
20
|
|
|
21
|
+
- **[HazoUiFlexInput](#hazouiflexinput)** - An enhanced input component with type validation, character restrictions, and error messaging. Supports numeric, alpha, email, and mixed input types with built-in validation and formatting guides.
|
|
22
|
+
|
|
21
23
|
---
|
|
22
24
|
|
|
23
25
|
## HazoUiMultiFilterDialog
|
|
@@ -149,6 +151,8 @@ function DataTable() {
|
|
|
149
151
|
availableFields={availableFields}
|
|
150
152
|
onFilterChange={handleFilterChange}
|
|
151
153
|
initialFilters={filters}
|
|
154
|
+
title="Filter Products" // Optional: customize dialog title (default: "Filter")
|
|
155
|
+
description="Filter by product attributes" // Optional: customize description
|
|
152
156
|
/>
|
|
153
157
|
{/* Your table/grid component */}
|
|
154
158
|
</div>
|
|
@@ -156,6 +160,16 @@ function DataTable() {
|
|
|
156
160
|
}
|
|
157
161
|
```
|
|
158
162
|
|
|
163
|
+
#### Props
|
|
164
|
+
|
|
165
|
+
| Prop | Type | Required | Default | Description |
|
|
166
|
+
|------|------|----------|---------|-------------|
|
|
167
|
+
| `availableFields` | `FilterField[]` | Yes | - | Array of field definitions for filtering |
|
|
168
|
+
| `onFilterChange` | `(filters: FilterConfig[]) => void` | Yes | - | Callback when filters are applied |
|
|
169
|
+
| `initialFilters` | `FilterConfig[]` | No | `[]` | Initial filter configuration |
|
|
170
|
+
| `title` | `string` | No | `"Filter"` | Dialog title text |
|
|
171
|
+
| `description` | `string` | No | `"Add multiple fields to filter by..."` | Dialog description text |
|
|
172
|
+
|
|
159
173
|
#### Example Input
|
|
160
174
|
|
|
161
175
|
```tsx
|
|
@@ -323,6 +337,8 @@ function DataTable() {
|
|
|
323
337
|
availableFields={availableFields}
|
|
324
338
|
onSortChange={handleSortChange}
|
|
325
339
|
initialSortFields={sorts}
|
|
340
|
+
title="Sort Products" // Optional: customize dialog title (default: "Sort")
|
|
341
|
+
description="Drag to reorder sort priority" // Optional: customize description
|
|
326
342
|
/>
|
|
327
343
|
{/* Your table/grid component */}
|
|
328
344
|
</div>
|
|
@@ -330,6 +346,16 @@ function DataTable() {
|
|
|
330
346
|
}
|
|
331
347
|
```
|
|
332
348
|
|
|
349
|
+
#### Props
|
|
350
|
+
|
|
351
|
+
| Prop | Type | Required | Default | Description |
|
|
352
|
+
|------|------|----------|---------|-------------|
|
|
353
|
+
| `availableFields` | `SortField[]` | Yes | - | Array of field definitions for sorting |
|
|
354
|
+
| `onSortChange` | `(sorts: SortConfig[]) => void` | Yes | - | Callback when sorts are applied |
|
|
355
|
+
| `initialSortFields` | `SortConfig[]` | No | `[]` | Initial sort configuration |
|
|
356
|
+
| `title` | `string` | No | `"Sort"` | Dialog title text |
|
|
357
|
+
| `description` | `string` | No | `"Add multiple fields to sort by..."` | Dialog description text |
|
|
358
|
+
|
|
333
359
|
#### Example Input
|
|
334
360
|
|
|
335
361
|
```tsx
|
|
@@ -667,6 +693,257 @@ The component supports the following react-icons packages:
|
|
|
667
693
|
|
|
668
694
|
---
|
|
669
695
|
|
|
696
|
+
## HazoUiFlexInput
|
|
697
|
+
|
|
698
|
+
An enhanced input component with type validation, character restrictions, and error messaging. Extends shadcn Input component with additional validation props for numeric, alpha, email, and mixed input types.
|
|
699
|
+
|
|
700
|
+
#### Features
|
|
701
|
+
|
|
702
|
+
- **Multiple Input Types**: Supports mixed (text), numeric, alpha (letters only), and email input types
|
|
703
|
+
- **Real-time Character Filtering**: Automatically prevents invalid characters from being entered (e.g., numbers in alpha fields)
|
|
704
|
+
- **Validation on Blur**: Validates input when the field loses focus and displays error messages
|
|
705
|
+
- **Numeric Constraints**: Min/max value validation and decimal precision control
|
|
706
|
+
- **Length Constraints**: Configurable minimum and maximum character lengths
|
|
707
|
+
- **Regex Validation**: Custom regex pattern support for complex validation rules
|
|
708
|
+
- **Format Guide**: Optional helper text displayed below the input
|
|
709
|
+
- **Error Messaging**: Clear error messages displayed when validation fails
|
|
710
|
+
- **Controlled & Uncontrolled**: Supports both controlled and uncontrolled usage patterns
|
|
711
|
+
- **TypeScript Support**: Fully typed with TypeScript interfaces
|
|
712
|
+
- **Accessible**: Built with accessibility in mind using shadcn/ui components
|
|
713
|
+
|
|
714
|
+
#### Input Types
|
|
715
|
+
|
|
716
|
+
1. **Mixed (text)**
|
|
717
|
+
- Allows any characters
|
|
718
|
+
- Supports length constraints (min/max)
|
|
719
|
+
- Supports regex validation
|
|
720
|
+
|
|
721
|
+
2. **Numeric**
|
|
722
|
+
- Only allows numbers, decimal point, and minus sign
|
|
723
|
+
- Supports min/max value constraints
|
|
724
|
+
- Configurable decimal precision (including integers with 0 decimals)
|
|
725
|
+
- Automatically filters out non-numeric characters
|
|
726
|
+
|
|
727
|
+
3. **Alpha**
|
|
728
|
+
- Only allows letters and spaces
|
|
729
|
+
- Automatically filters out numbers and special characters
|
|
730
|
+
- Supports length constraints
|
|
731
|
+
|
|
732
|
+
4. **Email**
|
|
733
|
+
- Validates email format on blur
|
|
734
|
+
- Uses standard email regex pattern
|
|
735
|
+
|
|
736
|
+
#### Props
|
|
737
|
+
|
|
738
|
+
```typescript
|
|
739
|
+
interface HazoUiFlexInputProps extends Omit<InputProps, "type"> {
|
|
740
|
+
input_type?: "mixed" | "numeric" | "email" | "alpha"; // Input type (default: "mixed")
|
|
741
|
+
text_len_min?: number; // Minimum character length
|
|
742
|
+
text_len_max?: number; // Maximum character length
|
|
743
|
+
num_min?: number; // Minimum numeric value
|
|
744
|
+
num_max?: number; // Maximum numeric value
|
|
745
|
+
regex?: string | RegExp; // Custom regex pattern
|
|
746
|
+
num_decimals?: number; // Number of decimal places allowed
|
|
747
|
+
format_guide?: string; // Helper text displayed below input
|
|
748
|
+
format_guide_info?: boolean; // Show format guide (default: false)
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
#### Usage
|
|
753
|
+
|
|
754
|
+
**Basic Mixed Input**
|
|
755
|
+
|
|
756
|
+
```tsx
|
|
757
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
758
|
+
import { useState } from 'react';
|
|
759
|
+
|
|
760
|
+
function BasicForm() {
|
|
761
|
+
const [value, setValue] = useState<string>("");
|
|
762
|
+
|
|
763
|
+
return (
|
|
764
|
+
<HazoUiFlexInput
|
|
765
|
+
input_type="mixed"
|
|
766
|
+
placeholder="Enter text..."
|
|
767
|
+
value={value}
|
|
768
|
+
onChange={(e) => setValue(e.target.value)}
|
|
769
|
+
/>
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
**Numeric Input with Constraints**
|
|
775
|
+
|
|
776
|
+
```tsx
|
|
777
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
778
|
+
import { useState } from 'react';
|
|
779
|
+
|
|
780
|
+
function PriceInput() {
|
|
781
|
+
const [price, setPrice] = useState<string>("");
|
|
782
|
+
|
|
783
|
+
return (
|
|
784
|
+
<HazoUiFlexInput
|
|
785
|
+
input_type="numeric"
|
|
786
|
+
placeholder="Enter price (0-100)..."
|
|
787
|
+
num_min={0}
|
|
788
|
+
num_max={100}
|
|
789
|
+
num_decimals={2}
|
|
790
|
+
format_guide="Enter a number between 0 and 100 with up to 2 decimal places"
|
|
791
|
+
format_guide_info={true}
|
|
792
|
+
value={price}
|
|
793
|
+
onChange={(e) => setPrice(e.target.value)}
|
|
794
|
+
/>
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
**Integer Input (No Decimals)**
|
|
800
|
+
|
|
801
|
+
```tsx
|
|
802
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
803
|
+
import { useState } from 'react';
|
|
804
|
+
|
|
805
|
+
function AgeInput() {
|
|
806
|
+
const [age, setAge] = useState<string>("");
|
|
807
|
+
|
|
808
|
+
return (
|
|
809
|
+
<HazoUiFlexInput
|
|
810
|
+
input_type="numeric"
|
|
811
|
+
placeholder="Enter age (1-120)..."
|
|
812
|
+
num_min={1}
|
|
813
|
+
num_max={120}
|
|
814
|
+
num_decimals={0}
|
|
815
|
+
format_guide="Enter a whole number between 1 and 120"
|
|
816
|
+
format_guide_info={true}
|
|
817
|
+
value={age}
|
|
818
|
+
onChange={(e) => setAge(e.target.value)}
|
|
819
|
+
/>
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
**Alpha Input (Letters Only)**
|
|
825
|
+
|
|
826
|
+
```tsx
|
|
827
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
828
|
+
import { useState } from 'react';
|
|
829
|
+
|
|
830
|
+
function NameInput() {
|
|
831
|
+
const [name, setName] = useState<string>("");
|
|
832
|
+
|
|
833
|
+
return (
|
|
834
|
+
<HazoUiFlexInput
|
|
835
|
+
input_type="alpha"
|
|
836
|
+
placeholder="Enter name (letters only)..."
|
|
837
|
+
format_guide="Only letters and spaces are allowed"
|
|
838
|
+
format_guide_info={true}
|
|
839
|
+
value={name}
|
|
840
|
+
onChange={(e) => setName(e.target.value)}
|
|
841
|
+
/>
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
**Email Input with Validation**
|
|
847
|
+
|
|
848
|
+
```tsx
|
|
849
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
850
|
+
import { useState } from 'react';
|
|
851
|
+
|
|
852
|
+
function EmailForm() {
|
|
853
|
+
const [email, setEmail] = useState<string>("");
|
|
854
|
+
|
|
855
|
+
return (
|
|
856
|
+
<HazoUiFlexInput
|
|
857
|
+
input_type="email"
|
|
858
|
+
placeholder="Enter email address..."
|
|
859
|
+
format_guide="Enter a valid email address (e.g., user@example.com)"
|
|
860
|
+
format_guide_info={true}
|
|
861
|
+
value={email}
|
|
862
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
863
|
+
/>
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
**Mixed Input with Length Constraints**
|
|
869
|
+
|
|
870
|
+
```tsx
|
|
871
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
872
|
+
import { useState } from 'react';
|
|
873
|
+
|
|
874
|
+
function UsernameInput() {
|
|
875
|
+
const [username, setUsername] = useState<string>("");
|
|
876
|
+
|
|
877
|
+
return (
|
|
878
|
+
<HazoUiFlexInput
|
|
879
|
+
input_type="mixed"
|
|
880
|
+
placeholder="Enter username (5-20 characters)..."
|
|
881
|
+
text_len_min={5}
|
|
882
|
+
text_len_max={20}
|
|
883
|
+
format_guide="Must be between 5 and 20 characters"
|
|
884
|
+
format_guide_info={true}
|
|
885
|
+
value={username}
|
|
886
|
+
onChange={(e) => setUsername(e.target.value)}
|
|
887
|
+
/>
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
**Input with Regex Validation**
|
|
893
|
+
|
|
894
|
+
```tsx
|
|
895
|
+
import { HazoUiFlexInput } from 'hazo_ui';
|
|
896
|
+
import { useState } from 'react';
|
|
897
|
+
|
|
898
|
+
function PhoneInput() {
|
|
899
|
+
const [phone, setPhone] = useState<string>("");
|
|
900
|
+
|
|
901
|
+
return (
|
|
902
|
+
<HazoUiFlexInput
|
|
903
|
+
input_type="mixed"
|
|
904
|
+
placeholder="Enter phone number (XXX-XXX-XXXX)..."
|
|
905
|
+
regex={/^\d{3}-\d{3}-\d{4}$/}
|
|
906
|
+
format_guide="Format: XXX-XXX-XXXX (e.g., 123-456-7890)"
|
|
907
|
+
format_guide_info={true}
|
|
908
|
+
value={phone}
|
|
909
|
+
onChange={(e) => setPhone(e.target.value)}
|
|
910
|
+
/>
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
#### Validation Behavior
|
|
916
|
+
|
|
917
|
+
- **Character Filtering**: For `numeric` and `alpha` types, invalid characters are automatically filtered out as the user types
|
|
918
|
+
- **Validation Timing**: Validation occurs when the input loses focus (onBlur event)
|
|
919
|
+
- **Error Display**: Error messages appear below the input in red text when validation fails
|
|
920
|
+
- **Format Guide**: Optional helper text can be displayed below the input (set `format_guide_info={true}`)
|
|
921
|
+
- **Error Priority**: If both an error message and format guide are present, only the error message is shown
|
|
922
|
+
|
|
923
|
+
#### Expected Output
|
|
924
|
+
|
|
925
|
+
The component behaves like a standard input element:
|
|
926
|
+
|
|
927
|
+
```typescript
|
|
928
|
+
// onChange receives a standard React.ChangeEvent<HTMLInputElement>
|
|
929
|
+
onChange={(e) => {
|
|
930
|
+
const value = e.target.value; // Current input value as string
|
|
931
|
+
// Handle value change
|
|
932
|
+
}}
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
#### Error Messages
|
|
936
|
+
|
|
937
|
+
The component provides default error messages for common validation failures:
|
|
938
|
+
|
|
939
|
+
- **Numeric**: "Must be a valid number", "Must be at least X", "Must be at most X", "Maximum X decimal places allowed"
|
|
940
|
+
- **Alpha**: "Only letters are allowed"
|
|
941
|
+
- **Email**: "Must be a valid email address"
|
|
942
|
+
- **Mixed**: "Must be at least X characters", "Must be at most X characters"
|
|
943
|
+
- **Regex**: "Invalid format" (or custom message via `format_guide`)
|
|
944
|
+
|
|
945
|
+
---
|
|
946
|
+
|
|
670
947
|
## Styling
|
|
671
948
|
|
|
672
949
|
Both components use Tailwind CSS and follow shadcn/ui design patterns. Make sure your project has Tailwind CSS configured with the following CSS variables:
|
package/dist/index.cjs
CHANGED
|
@@ -263,7 +263,7 @@ var CommandItem = React6__namespace.forwardRef(({ className, onSelect, value, ..
|
|
|
263
263
|
{
|
|
264
264
|
ref,
|
|
265
265
|
className: cn(
|
|
266
|
-
"relative flex cursor-
|
|
266
|
+
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
267
267
|
className
|
|
268
268
|
),
|
|
269
269
|
onClick: handleClick,
|
|
@@ -665,7 +665,9 @@ function FilterFieldItem({
|
|
|
665
665
|
function HazoUiMultiFilterDialog({
|
|
666
666
|
availableFields,
|
|
667
667
|
onFilterChange,
|
|
668
|
-
initialFilters = []
|
|
668
|
+
initialFilters = [],
|
|
669
|
+
title = "Filter",
|
|
670
|
+
description = "Add multiple fields to filter by. Select a field and set its filter value."
|
|
669
671
|
}) {
|
|
670
672
|
const [isOpen, setIsOpen] = React6.useState(false);
|
|
671
673
|
const [filterFields, setFilterFields] = React6.useState(initialFilters);
|
|
@@ -787,8 +789,8 @@ function HazoUiMultiFilterDialog({
|
|
|
787
789
|
] }) }),
|
|
788
790
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "cls_filter_dialog_content max-w-lg w-full max-h-[90vh] overflow-y-auto", children: [
|
|
789
791
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
790
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children:
|
|
791
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children:
|
|
792
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: title }),
|
|
793
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: description })
|
|
792
794
|
] }),
|
|
793
795
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cls_filter_dialog_body space-y-4 py-4", children: [
|
|
794
796
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_add_field_section", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isComboboxOpen, onOpenChange: setIsComboboxOpen, children: [
|
|
@@ -985,7 +987,9 @@ function SortableSortFieldItem({
|
|
|
985
987
|
function HazoUiMultiSortDialog({
|
|
986
988
|
availableFields,
|
|
987
989
|
onSortChange,
|
|
988
|
-
initialSortFields = []
|
|
990
|
+
initialSortFields = [],
|
|
991
|
+
title = "Sort",
|
|
992
|
+
description = "Add multiple fields to sort by and reorder them. Use the switch to toggle between ascending and descending."
|
|
989
993
|
}) {
|
|
990
994
|
const [isOpen, setIsOpen] = React6.useState(false);
|
|
991
995
|
const [sortFields, setSortFields] = React6.useState(initialSortFields);
|
|
@@ -1089,8 +1093,8 @@ function HazoUiMultiSortDialog({
|
|
|
1089
1093
|
] }) }),
|
|
1090
1094
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "cls_sort_dialog_content max-w-lg", children: [
|
|
1091
1095
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
1092
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children:
|
|
1093
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children:
|
|
1096
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: title }),
|
|
1097
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: description })
|
|
1094
1098
|
] }),
|
|
1095
1099
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cls_sort_dialog_body space-y-4 py-4", children: [
|
|
1096
1100
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_add_field_section", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isComboboxOpen, onOpenChange: setIsComboboxOpen, children: [
|