hazo_ui 2.5.1 → 2.6.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 +785 -8
- package/dist/index.cjs +240 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +242 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -10
package/README.md
CHANGED
|
@@ -41,6 +41,28 @@ That's it! The components will now render correctly with proper styling.
|
|
|
41
41
|
|
|
42
42
|
> **Note**: If you already have shadcn/ui configured with CSS variables, you may skip Step 1 as the variables are compatible.
|
|
43
43
|
|
|
44
|
+
### Important: Tailwind v4 Compatibility
|
|
45
|
+
|
|
46
|
+
If you're using **Tailwind CSS v4**, you must add the `@source` directive to ensure hazo_ui's Tailwind classes are compiled:
|
|
47
|
+
|
|
48
|
+
**In your `globals.css` or main CSS file:**
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
@import "tailwindcss";
|
|
52
|
+
|
|
53
|
+
/* REQUIRED for Tailwind v4: Enable scanning of hazo_ui components */
|
|
54
|
+
@source "../node_modules/hazo_ui/dist";
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Why is this needed?**
|
|
58
|
+
|
|
59
|
+
Tailwind v4 uses JIT compilation and only generates CSS for classes found in scanned files. By default, it doesn't scan `node_modules/`. Without the `@source` directive:
|
|
60
|
+
- Hover states won't work
|
|
61
|
+
- Colors will be missing
|
|
62
|
+
- Layouts may break
|
|
63
|
+
|
|
64
|
+
**Note:** Tailwind v3 users do NOT need this directive - the `content` configuration is sufficient.
|
|
65
|
+
|
|
44
66
|
---
|
|
45
67
|
|
|
46
68
|
## Components
|
|
@@ -61,6 +83,8 @@ That's it! The components will now render correctly with proper styling.
|
|
|
61
83
|
|
|
62
84
|
- **[HazoUiTextarea](#hazouitextarea)** - A multi-line textarea component with command pill support. Similar to HazoUiTextbox but supports multi-line input with Shift+Enter for new lines and Cmd/Ctrl+Enter to submit. Features the same interactive pill editing capabilities.
|
|
63
85
|
|
|
86
|
+
- **[HazoUiDialog](#hazouidialog)** - A standardized dialog component with customizable animations, sizes, and theming. Features header/body/footer layout, color customization props, multiple size variants, and distinct animation presets (zoom, slide, fade).
|
|
87
|
+
|
|
64
88
|
---
|
|
65
89
|
|
|
66
90
|
## HazoUiMultiFilterDialog
|
|
@@ -1679,6 +1703,753 @@ function CustomHeightExample() {
|
|
|
1679
1703
|
|
|
1680
1704
|
---
|
|
1681
1705
|
|
|
1706
|
+
## HazoUiDialog
|
|
1707
|
+
|
|
1708
|
+
A flexible, standardized dialog component with customizable animations, sizes, and theming. Built on Radix UI Dialog primitives with a consistent header/body/footer layout.
|
|
1709
|
+
|
|
1710
|
+
#### Features
|
|
1711
|
+
|
|
1712
|
+
- **Flexible Sizing**: 5 size presets from small (400px) to full-width (98vw), plus custom sizing
|
|
1713
|
+
- **9 Animation Presets**: Zoom, slide (bottom/top/left/right), fade, bounce, scale-up, and flip animations
|
|
1714
|
+
- **Header Bar Option**: Full-width colored header bar for modern modal designs
|
|
1715
|
+
- **Color Customization**: Override header, body, footer, border, and accent colors via props
|
|
1716
|
+
- **Themed Variants**: Pre-built themes for success, warning, danger, and info states
|
|
1717
|
+
- **Responsive Design**: Viewport-relative sizing with maximum constraints
|
|
1718
|
+
- **Controlled Component**: Fully controlled open/close state
|
|
1719
|
+
- **Callback Support**: Separate callbacks for confirm and cancel actions
|
|
1720
|
+
- **TypeScript Support**: Fully typed with comprehensive interfaces
|
|
1721
|
+
- **Accessible**: Built with accessibility in mind using Radix UI primitives
|
|
1722
|
+
|
|
1723
|
+
#### Type Definitions
|
|
1724
|
+
|
|
1725
|
+
```typescript
|
|
1726
|
+
interface HazoUiDialogProps {
|
|
1727
|
+
// Dialog State Control
|
|
1728
|
+
open?: boolean;
|
|
1729
|
+
onOpenChange?: (open: boolean) => void;
|
|
1730
|
+
|
|
1731
|
+
// Content & Callbacks
|
|
1732
|
+
children: React.ReactNode;
|
|
1733
|
+
onConfirm?: () => void;
|
|
1734
|
+
onCancel?: () => void;
|
|
1735
|
+
|
|
1736
|
+
// Header Configuration
|
|
1737
|
+
title?: string; // default: "Action required"
|
|
1738
|
+
description?: string;
|
|
1739
|
+
|
|
1740
|
+
// Button Configuration
|
|
1741
|
+
actionButtonText?: string; // default: "Confirm"
|
|
1742
|
+
actionButtonVariant?: ButtonVariant; // default: "default"
|
|
1743
|
+
cancelButtonText?: string; // default: "Cancel"
|
|
1744
|
+
showCancelButton?: boolean; // default: true
|
|
1745
|
+
|
|
1746
|
+
// Action Button Enhancement
|
|
1747
|
+
actionButtonLoading?: boolean; // default: false - Shows spinner, disables button
|
|
1748
|
+
actionButtonDisabled?: boolean; // default: false - Disables action button
|
|
1749
|
+
actionButtonIcon?: React.ReactNode; // Icon before button text (replaced by spinner when loading)
|
|
1750
|
+
|
|
1751
|
+
// Custom Footer
|
|
1752
|
+
footerContent?: React.ReactNode; // Custom footer content (replaces default buttons)
|
|
1753
|
+
|
|
1754
|
+
// Size Configuration
|
|
1755
|
+
sizeWidth?: string; // default: "min(90vw, 600px)"
|
|
1756
|
+
sizeHeight?: string; // default: "min(80vh, 800px)"
|
|
1757
|
+
|
|
1758
|
+
// Animation Configuration
|
|
1759
|
+
openAnimation?: AnimationPreset | string; // default: "zoom"
|
|
1760
|
+
closeAnimation?: AnimationPreset | string; // default: "zoom"
|
|
1761
|
+
|
|
1762
|
+
// Color Customization
|
|
1763
|
+
headerBackgroundColor?: string;
|
|
1764
|
+
headerTextColor?: string;
|
|
1765
|
+
bodyBackgroundColor?: string;
|
|
1766
|
+
footerBackgroundColor?: string;
|
|
1767
|
+
borderColor?: string;
|
|
1768
|
+
accentColor?: string;
|
|
1769
|
+
|
|
1770
|
+
// Header Bar (full-width colored bar)
|
|
1771
|
+
headerBar?: boolean; // default: false - Enable full-width colored header bar
|
|
1772
|
+
headerBarColor?: string; // default: "#1e293b" - Color for the header bar
|
|
1773
|
+
|
|
1774
|
+
// Styling Customization
|
|
1775
|
+
className?: string;
|
|
1776
|
+
contentClassName?: string;
|
|
1777
|
+
overlayClassName?: string;
|
|
1778
|
+
headerClassName?: string;
|
|
1779
|
+
footerClassName?: string;
|
|
1780
|
+
showCloseButton?: boolean; // default: true
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
type AnimationPreset = 'zoom' | 'slide' | 'fade' | 'bounce' | 'scale-up' | 'flip' | 'slide-left' | 'slide-right' | 'slide-top' | 'none';
|
|
1784
|
+
type ButtonVariant = "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
|
|
1785
|
+
```
|
|
1786
|
+
|
|
1787
|
+
#### Basic Usage
|
|
1788
|
+
|
|
1789
|
+
```tsx
|
|
1790
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
1791
|
+
import { useState } from 'react';
|
|
1792
|
+
|
|
1793
|
+
function ConfirmDialog() {
|
|
1794
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1795
|
+
|
|
1796
|
+
return (
|
|
1797
|
+
<>
|
|
1798
|
+
<button onClick={() => setIsOpen(true)}>
|
|
1799
|
+
Open Dialog
|
|
1800
|
+
</button>
|
|
1801
|
+
|
|
1802
|
+
<HazoUiDialog
|
|
1803
|
+
open={isOpen}
|
|
1804
|
+
onOpenChange={setIsOpen}
|
|
1805
|
+
title="Confirm Action"
|
|
1806
|
+
description="Are you sure you want to proceed?"
|
|
1807
|
+
onConfirm={() => {
|
|
1808
|
+
console.log('Confirmed');
|
|
1809
|
+
setIsOpen(false);
|
|
1810
|
+
}}
|
|
1811
|
+
onCancel={() => {
|
|
1812
|
+
console.log('Cancelled');
|
|
1813
|
+
}}
|
|
1814
|
+
>
|
|
1815
|
+
<p>This action cannot be undone.</p>
|
|
1816
|
+
</HazoUiDialog>
|
|
1817
|
+
</>
|
|
1818
|
+
);
|
|
1819
|
+
}
|
|
1820
|
+
```
|
|
1821
|
+
|
|
1822
|
+
#### Action Button States and Custom Footers
|
|
1823
|
+
|
|
1824
|
+
The dialog supports enhanced action buttons with loading states, icons, and fully custom footers for complex UX scenarios.
|
|
1825
|
+
|
|
1826
|
+
##### 1. Form Dialog with Loading State
|
|
1827
|
+
|
|
1828
|
+
```tsx
|
|
1829
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
1830
|
+
import { useState } from 'react';
|
|
1831
|
+
|
|
1832
|
+
function SaveFormDialog() {
|
|
1833
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1834
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
1835
|
+
|
|
1836
|
+
const handleSave = async () => {
|
|
1837
|
+
setIsSaving(true);
|
|
1838
|
+
try {
|
|
1839
|
+
await saveFormData();
|
|
1840
|
+
setIsOpen(false);
|
|
1841
|
+
} catch (error) {
|
|
1842
|
+
console.error('Save failed:', error);
|
|
1843
|
+
} finally {
|
|
1844
|
+
setIsSaving(false);
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
|
|
1848
|
+
return (
|
|
1849
|
+
<HazoUiDialog
|
|
1850
|
+
open={isOpen}
|
|
1851
|
+
onOpenChange={setIsOpen}
|
|
1852
|
+
title="Save Changes"
|
|
1853
|
+
description="Your changes will be saved to the server."
|
|
1854
|
+
actionButtonText={isSaving ? "Saving..." : "Save"}
|
|
1855
|
+
actionButtonLoading={isSaving}
|
|
1856
|
+
onConfirm={handleSave}
|
|
1857
|
+
>
|
|
1858
|
+
<p>Click Save to see the loading spinner and disabled button.</p>
|
|
1859
|
+
</HazoUiDialog>
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
```
|
|
1863
|
+
|
|
1864
|
+
##### 2. Confirmation Dialog with Icon
|
|
1865
|
+
|
|
1866
|
+
```tsx
|
|
1867
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
1868
|
+
import { Send } from 'lucide-react';
|
|
1869
|
+
import { useState } from 'react';
|
|
1870
|
+
|
|
1871
|
+
function SendEmailDialog() {
|
|
1872
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1873
|
+
|
|
1874
|
+
return (
|
|
1875
|
+
<HazoUiDialog
|
|
1876
|
+
open={isOpen}
|
|
1877
|
+
onOpenChange={setIsOpen}
|
|
1878
|
+
title="Send Email"
|
|
1879
|
+
description="This will send the email to all recipients."
|
|
1880
|
+
actionButtonText="Send Email"
|
|
1881
|
+
actionButtonIcon={<Send className="h-4 w-4" />}
|
|
1882
|
+
onConfirm={() => {
|
|
1883
|
+
sendEmail();
|
|
1884
|
+
setIsOpen(false);
|
|
1885
|
+
}}
|
|
1886
|
+
>
|
|
1887
|
+
<p>The Send icon appears before the button text.</p>
|
|
1888
|
+
</HazoUiDialog>
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
```
|
|
1892
|
+
|
|
1893
|
+
##### 3. Destructive Action with Loading
|
|
1894
|
+
|
|
1895
|
+
```tsx
|
|
1896
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
1897
|
+
import { Lock } from 'lucide-react';
|
|
1898
|
+
import { useState } from 'react';
|
|
1899
|
+
|
|
1900
|
+
function CloseAccountDialog() {
|
|
1901
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1902
|
+
const [isClosing, setIsClosing] = useState(false);
|
|
1903
|
+
|
|
1904
|
+
const handleClose = async () => {
|
|
1905
|
+
setIsClosing(true);
|
|
1906
|
+
try {
|
|
1907
|
+
await closeAccount();
|
|
1908
|
+
setIsOpen(false);
|
|
1909
|
+
} catch (error) {
|
|
1910
|
+
console.error('Close failed:', error);
|
|
1911
|
+
} finally {
|
|
1912
|
+
setIsClosing(false);
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
|
|
1916
|
+
return (
|
|
1917
|
+
<HazoUiDialog
|
|
1918
|
+
open={isOpen}
|
|
1919
|
+
onOpenChange={setIsOpen}
|
|
1920
|
+
title="Close Account"
|
|
1921
|
+
description="This will permanently close your account."
|
|
1922
|
+
actionButtonText={isClosing ? "Closing..." : "Close"}
|
|
1923
|
+
actionButtonIcon={<Lock className="h-4 w-4" />}
|
|
1924
|
+
actionButtonLoading={isClosing}
|
|
1925
|
+
onConfirm={handleClose}
|
|
1926
|
+
>
|
|
1927
|
+
<p>Lock icon is replaced by spinner when loading.</p>
|
|
1928
|
+
</HazoUiDialog>
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1931
|
+
```
|
|
1932
|
+
|
|
1933
|
+
##### 4. Complex Footer with Stats
|
|
1934
|
+
|
|
1935
|
+
```tsx
|
|
1936
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
1937
|
+
import { useState } from 'react';
|
|
1938
|
+
|
|
1939
|
+
function ReviewItemsDialog() {
|
|
1940
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1941
|
+
const [stats, setStats] = useState({ keep: 0, accept: 0, skip: 0 });
|
|
1942
|
+
|
|
1943
|
+
return (
|
|
1944
|
+
<HazoUiDialog
|
|
1945
|
+
open={isOpen}
|
|
1946
|
+
onOpenChange={setIsOpen}
|
|
1947
|
+
title="Review Items"
|
|
1948
|
+
description="Review and process the items below."
|
|
1949
|
+
footerContent={
|
|
1950
|
+
<div className="flex items-center justify-between w-full">
|
|
1951
|
+
<div className="text-sm text-muted-foreground">
|
|
1952
|
+
Keep: {stats.keep} | Accept: {stats.accept} | Skip: {stats.skip}
|
|
1953
|
+
</div>
|
|
1954
|
+
<div className="flex gap-2">
|
|
1955
|
+
<button
|
|
1956
|
+
onClick={() => setStats({ ...stats, skip: stats.skip + 1 })}
|
|
1957
|
+
className="px-3 py-1.5 text-sm border rounded-md hover:bg-muted"
|
|
1958
|
+
>
|
|
1959
|
+
Skip
|
|
1960
|
+
</button>
|
|
1961
|
+
<button
|
|
1962
|
+
onClick={() => setStats({ ...stats, keep: stats.keep + 1 })}
|
|
1963
|
+
className="px-3 py-1.5 text-sm bg-blue-500 text-white rounded-md"
|
|
1964
|
+
>
|
|
1965
|
+
Keep
|
|
1966
|
+
</button>
|
|
1967
|
+
<button
|
|
1968
|
+
onClick={() => {
|
|
1969
|
+
setStats({ ...stats, accept: stats.accept + 1 });
|
|
1970
|
+
setIsOpen(false);
|
|
1971
|
+
}}
|
|
1972
|
+
className="px-3 py-1.5 text-sm bg-green-500 text-white rounded-md"
|
|
1973
|
+
>
|
|
1974
|
+
Accept
|
|
1975
|
+
</button>
|
|
1976
|
+
</div>
|
|
1977
|
+
</div>
|
|
1978
|
+
}
|
|
1979
|
+
>
|
|
1980
|
+
<p>Custom footer shows stats and multiple action buttons.</p>
|
|
1981
|
+
</HazoUiDialog>
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
```
|
|
1985
|
+
|
|
1986
|
+
##### 5. Progress Dialog with No Footer
|
|
1987
|
+
|
|
1988
|
+
```tsx
|
|
1989
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
1990
|
+
import { useState, useEffect } from 'react';
|
|
1991
|
+
|
|
1992
|
+
function ProgressDialog() {
|
|
1993
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1994
|
+
const [progress, setProgress] = useState(0);
|
|
1995
|
+
|
|
1996
|
+
useEffect(() => {
|
|
1997
|
+
if (isOpen) {
|
|
1998
|
+
const interval = setInterval(() => {
|
|
1999
|
+
setProgress((prev) => {
|
|
2000
|
+
const next = prev + 10;
|
|
2001
|
+
if (next >= 100) {
|
|
2002
|
+
clearInterval(interval);
|
|
2003
|
+
setTimeout(() => setIsOpen(false), 500);
|
|
2004
|
+
return 100;
|
|
2005
|
+
}
|
|
2006
|
+
return next;
|
|
2007
|
+
});
|
|
2008
|
+
}, 300);
|
|
2009
|
+
return () => clearInterval(interval);
|
|
2010
|
+
}
|
|
2011
|
+
}, [isOpen]);
|
|
2012
|
+
|
|
2013
|
+
return (
|
|
2014
|
+
<HazoUiDialog
|
|
2015
|
+
open={isOpen}
|
|
2016
|
+
onOpenChange={setIsOpen}
|
|
2017
|
+
title="Processing..."
|
|
2018
|
+
description="Please wait while we process your request."
|
|
2019
|
+
showCloseButton={false}
|
|
2020
|
+
footerContent={<div />}
|
|
2021
|
+
>
|
|
2022
|
+
<div className="space-y-4">
|
|
2023
|
+
<div className="w-full bg-muted rounded-full h-2">
|
|
2024
|
+
<div
|
|
2025
|
+
className="bg-primary h-2 rounded-full transition-all"
|
|
2026
|
+
style={{ width: `${progress}%` }}
|
|
2027
|
+
/>
|
|
2028
|
+
</div>
|
|
2029
|
+
<p className="text-sm text-center">{progress}% complete</p>
|
|
2030
|
+
</div>
|
|
2031
|
+
</HazoUiDialog>
|
|
2032
|
+
);
|
|
2033
|
+
}
|
|
2034
|
+
```
|
|
2035
|
+
|
|
2036
|
+
#### Size Variants
|
|
2037
|
+
|
|
2038
|
+
```tsx
|
|
2039
|
+
// Small - 400px
|
|
2040
|
+
<HazoUiDialog
|
|
2041
|
+
sizeWidth="min(90vw, 400px)"
|
|
2042
|
+
sizeHeight="min(70vh, 300px)"
|
|
2043
|
+
{...props}
|
|
2044
|
+
/>
|
|
2045
|
+
|
|
2046
|
+
// Medium (default) - 600px
|
|
2047
|
+
<HazoUiDialog
|
|
2048
|
+
sizeWidth="min(90vw, 600px)"
|
|
2049
|
+
sizeHeight="min(80vh, 600px)"
|
|
2050
|
+
{...props}
|
|
2051
|
+
/>
|
|
2052
|
+
|
|
2053
|
+
// Large - 1000px
|
|
2054
|
+
<HazoUiDialog
|
|
2055
|
+
sizeWidth="min(95vw, 1000px)"
|
|
2056
|
+
sizeHeight="min(85vh, 800px)"
|
|
2057
|
+
{...props}
|
|
2058
|
+
/>
|
|
2059
|
+
|
|
2060
|
+
// Extra-Large - 1400px
|
|
2061
|
+
<HazoUiDialog
|
|
2062
|
+
sizeWidth="min(95vw, 1400px)"
|
|
2063
|
+
sizeHeight="min(90vh, 900px)"
|
|
2064
|
+
{...props}
|
|
2065
|
+
/>
|
|
2066
|
+
|
|
2067
|
+
// Full Width - 98vw
|
|
2068
|
+
<HazoUiDialog
|
|
2069
|
+
sizeWidth="98vw"
|
|
2070
|
+
sizeHeight="min(90vh, 1000px)"
|
|
2071
|
+
{...props}
|
|
2072
|
+
/>
|
|
2073
|
+
```
|
|
2074
|
+
|
|
2075
|
+
#### Animation Variants
|
|
2076
|
+
|
|
2077
|
+
```tsx
|
|
2078
|
+
// Zoom - Scales from 50% size with dramatic effect
|
|
2079
|
+
<HazoUiDialog
|
|
2080
|
+
openAnimation="zoom"
|
|
2081
|
+
closeAnimation="zoom"
|
|
2082
|
+
{...props}
|
|
2083
|
+
/>
|
|
2084
|
+
|
|
2085
|
+
// Slide Bottom - Slides from bottom of screen
|
|
2086
|
+
<HazoUiDialog
|
|
2087
|
+
openAnimation="slide"
|
|
2088
|
+
closeAnimation="slide"
|
|
2089
|
+
{...props}
|
|
2090
|
+
/>
|
|
2091
|
+
|
|
2092
|
+
// Slide Top - Slides from top of screen
|
|
2093
|
+
<HazoUiDialog
|
|
2094
|
+
openAnimation="slide-top"
|
|
2095
|
+
closeAnimation="slide-top"
|
|
2096
|
+
{...props}
|
|
2097
|
+
/>
|
|
2098
|
+
|
|
2099
|
+
// Slide Left - Slides from left side
|
|
2100
|
+
<HazoUiDialog
|
|
2101
|
+
openAnimation="slide-left"
|
|
2102
|
+
closeAnimation="slide-left"
|
|
2103
|
+
{...props}
|
|
2104
|
+
/>
|
|
2105
|
+
|
|
2106
|
+
// Slide Right - Slides from right side
|
|
2107
|
+
<HazoUiDialog
|
|
2108
|
+
openAnimation="slide-right"
|
|
2109
|
+
closeAnimation="slide-right"
|
|
2110
|
+
{...props}
|
|
2111
|
+
/>
|
|
2112
|
+
|
|
2113
|
+
// Fade - Pure opacity fade with no movement
|
|
2114
|
+
<HazoUiDialog
|
|
2115
|
+
openAnimation="fade"
|
|
2116
|
+
closeAnimation="fade"
|
|
2117
|
+
{...props}
|
|
2118
|
+
/>
|
|
2119
|
+
|
|
2120
|
+
// Bounce - Gentle bounce/spring animation
|
|
2121
|
+
<HazoUiDialog
|
|
2122
|
+
openAnimation="bounce"
|
|
2123
|
+
closeAnimation="bounce"
|
|
2124
|
+
{...props}
|
|
2125
|
+
/>
|
|
2126
|
+
|
|
2127
|
+
// Scale Up - Scales from 0% to full size
|
|
2128
|
+
<HazoUiDialog
|
|
2129
|
+
openAnimation="scale-up"
|
|
2130
|
+
closeAnimation="scale-up"
|
|
2131
|
+
{...props}
|
|
2132
|
+
/>
|
|
2133
|
+
|
|
2134
|
+
// Flip - Flip/rotate animation effect
|
|
2135
|
+
<HazoUiDialog
|
|
2136
|
+
openAnimation="flip"
|
|
2137
|
+
closeAnimation="flip"
|
|
2138
|
+
{...props}
|
|
2139
|
+
/>
|
|
2140
|
+
|
|
2141
|
+
// None - No animation
|
|
2142
|
+
<HazoUiDialog
|
|
2143
|
+
openAnimation="none"
|
|
2144
|
+
closeAnimation="none"
|
|
2145
|
+
{...props}
|
|
2146
|
+
/>
|
|
2147
|
+
```
|
|
2148
|
+
|
|
2149
|
+
#### Themed Dialogs
|
|
2150
|
+
|
|
2151
|
+
**Success Theme**
|
|
2152
|
+
```tsx
|
|
2153
|
+
<HazoUiDialog
|
|
2154
|
+
title="✓ Success"
|
|
2155
|
+
description="Operation completed successfully"
|
|
2156
|
+
actionButtonText="Done"
|
|
2157
|
+
showCancelButton={false}
|
|
2158
|
+
borderColor="rgb(34, 197, 94)"
|
|
2159
|
+
headerBackgroundColor="rgb(220, 252, 231)"
|
|
2160
|
+
headerTextColor="rgb(22, 101, 52)"
|
|
2161
|
+
accentColor="rgb(34, 197, 94)"
|
|
2162
|
+
overlayClassName="bg-green-950/50"
|
|
2163
|
+
{...props}
|
|
2164
|
+
>
|
|
2165
|
+
<p>Your changes have been saved.</p>
|
|
2166
|
+
</HazoUiDialog>
|
|
2167
|
+
```
|
|
2168
|
+
|
|
2169
|
+
**Warning Theme**
|
|
2170
|
+
```tsx
|
|
2171
|
+
<HazoUiDialog
|
|
2172
|
+
title="⚠ Warning"
|
|
2173
|
+
description="Please review before proceeding"
|
|
2174
|
+
actionButtonText="I Understand"
|
|
2175
|
+
borderColor="rgb(234, 179, 8)"
|
|
2176
|
+
headerBackgroundColor="rgb(254, 249, 195)"
|
|
2177
|
+
headerTextColor="rgb(113, 63, 18)"
|
|
2178
|
+
accentColor="rgb(234, 179, 8)"
|
|
2179
|
+
overlayClassName="bg-yellow-950/50"
|
|
2180
|
+
{...props}
|
|
2181
|
+
>
|
|
2182
|
+
<p>You have unsaved changes that will be lost.</p>
|
|
2183
|
+
</HazoUiDialog>
|
|
2184
|
+
```
|
|
2185
|
+
|
|
2186
|
+
**Danger Theme**
|
|
2187
|
+
```tsx
|
|
2188
|
+
<HazoUiDialog
|
|
2189
|
+
title="⛔ Destructive Action"
|
|
2190
|
+
description="This cannot be undone"
|
|
2191
|
+
actionButtonText="Delete Permanently"
|
|
2192
|
+
actionButtonVariant="destructive"
|
|
2193
|
+
borderColor="rgb(239, 68, 68)"
|
|
2194
|
+
headerBackgroundColor="rgb(254, 226, 226)"
|
|
2195
|
+
headerTextColor="rgb(127, 29, 29)"
|
|
2196
|
+
overlayClassName="bg-red-950/50"
|
|
2197
|
+
{...props}
|
|
2198
|
+
>
|
|
2199
|
+
<p>All data will be permanently deleted.</p>
|
|
2200
|
+
</HazoUiDialog>
|
|
2201
|
+
```
|
|
2202
|
+
|
|
2203
|
+
**Info Theme**
|
|
2204
|
+
```tsx
|
|
2205
|
+
<HazoUiDialog
|
|
2206
|
+
title="ℹ Information"
|
|
2207
|
+
description="Learn more about this feature"
|
|
2208
|
+
actionButtonText="Got It"
|
|
2209
|
+
showCancelButton={false}
|
|
2210
|
+
borderColor="rgb(59, 130, 246)"
|
|
2211
|
+
headerBackgroundColor="rgb(219, 234, 254)"
|
|
2212
|
+
headerTextColor="rgb(30, 58, 138)"
|
|
2213
|
+
accentColor="rgb(59, 130, 246)"
|
|
2214
|
+
overlayClassName="bg-blue-950/50"
|
|
2215
|
+
{...props}
|
|
2216
|
+
>
|
|
2217
|
+
<p>New features are now available.</p>
|
|
2218
|
+
</HazoUiDialog>
|
|
2219
|
+
```
|
|
2220
|
+
|
|
2221
|
+
#### Header Bar Style
|
|
2222
|
+
|
|
2223
|
+
The header bar feature creates a full-width colored bar at the top of the dialog, similar to common modal designs in modern applications. When enabled, the header text automatically becomes white for better contrast.
|
|
2224
|
+
|
|
2225
|
+
```tsx
|
|
2226
|
+
// Dark Header Bar (slate)
|
|
2227
|
+
<HazoUiDialog
|
|
2228
|
+
title="Invite Team Members"
|
|
2229
|
+
description="Add people to your workspace"
|
|
2230
|
+
headerBar={true}
|
|
2231
|
+
headerBarColor="#1e293b"
|
|
2232
|
+
actionButtonText="Send Invites"
|
|
2233
|
+
{...props}
|
|
2234
|
+
>
|
|
2235
|
+
<div className="space-y-4">
|
|
2236
|
+
<input
|
|
2237
|
+
type="text"
|
|
2238
|
+
placeholder="email@example.com"
|
|
2239
|
+
className="w-full px-3 py-2 border rounded-md"
|
|
2240
|
+
/>
|
|
2241
|
+
<select className="w-full px-3 py-2 border rounded-md">
|
|
2242
|
+
<option>Admin</option>
|
|
2243
|
+
<option>Editor</option>
|
|
2244
|
+
<option>Viewer</option>
|
|
2245
|
+
</select>
|
|
2246
|
+
</div>
|
|
2247
|
+
</HazoUiDialog>
|
|
2248
|
+
|
|
2249
|
+
// Blue Header Bar
|
|
2250
|
+
<HazoUiDialog
|
|
2251
|
+
title="Create New Project"
|
|
2252
|
+
description="Set up a new project workspace"
|
|
2253
|
+
headerBar={true}
|
|
2254
|
+
headerBarColor="#2563eb"
|
|
2255
|
+
actionButtonText="Create"
|
|
2256
|
+
{...props}
|
|
2257
|
+
>
|
|
2258
|
+
{/* Form content */}
|
|
2259
|
+
</HazoUiDialog>
|
|
2260
|
+
|
|
2261
|
+
// Purple Header Bar
|
|
2262
|
+
<HazoUiDialog
|
|
2263
|
+
title="Upload Document"
|
|
2264
|
+
description="Upload a file to process"
|
|
2265
|
+
headerBar={true}
|
|
2266
|
+
headerBarColor="#9333ea"
|
|
2267
|
+
actionButtonText="Upload"
|
|
2268
|
+
{...props}
|
|
2269
|
+
>
|
|
2270
|
+
{/* Upload UI */}
|
|
2271
|
+
</HazoUiDialog>
|
|
2272
|
+
```
|
|
2273
|
+
|
|
2274
|
+
**Key Features:**
|
|
2275
|
+
- Full-width colored bar extends to dialog edges
|
|
2276
|
+
- Header text automatically becomes white for contrast
|
|
2277
|
+
- Description text becomes semi-transparent white (80% opacity)
|
|
2278
|
+
- Close button color adapts to white for visibility
|
|
2279
|
+
- Compatible with all animation presets and size variants
|
|
2280
|
+
|
|
2281
|
+
#### Complex Form Dialog
|
|
2282
|
+
|
|
2283
|
+
```tsx
|
|
2284
|
+
import { HazoUiDialog } from 'hazo_ui';
|
|
2285
|
+
import { useState } from 'react';
|
|
2286
|
+
|
|
2287
|
+
function FormDialog() {
|
|
2288
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
2289
|
+
const [formData, setFormData] = useState({
|
|
2290
|
+
name: '',
|
|
2291
|
+
email: '',
|
|
2292
|
+
role: '',
|
|
2293
|
+
});
|
|
2294
|
+
|
|
2295
|
+
const handleSubmit = () => {
|
|
2296
|
+
console.log('Form data:', formData);
|
|
2297
|
+
setIsOpen(false);
|
|
2298
|
+
};
|
|
2299
|
+
|
|
2300
|
+
return (
|
|
2301
|
+
<HazoUiDialog
|
|
2302
|
+
open={isOpen}
|
|
2303
|
+
onOpenChange={setIsOpen}
|
|
2304
|
+
title="New Employee Registration"
|
|
2305
|
+
description="Fill out the required fields"
|
|
2306
|
+
actionButtonText="Register"
|
|
2307
|
+
onConfirm={handleSubmit}
|
|
2308
|
+
sizeWidth="min(90vw, 700px)"
|
|
2309
|
+
sizeHeight="min(85vh, 900px)"
|
|
2310
|
+
>
|
|
2311
|
+
<div className="space-y-4">
|
|
2312
|
+
<div>
|
|
2313
|
+
<label className="text-sm font-medium">Full Name *</label>
|
|
2314
|
+
<input
|
|
2315
|
+
type="text"
|
|
2316
|
+
value={formData.name}
|
|
2317
|
+
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
2318
|
+
className="w-full px-3 py-2 border rounded-md"
|
|
2319
|
+
/>
|
|
2320
|
+
</div>
|
|
2321
|
+
|
|
2322
|
+
<div>
|
|
2323
|
+
<label className="text-sm font-medium">Email *</label>
|
|
2324
|
+
<input
|
|
2325
|
+
type="email"
|
|
2326
|
+
value={formData.email}
|
|
2327
|
+
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
|
2328
|
+
className="w-full px-3 py-2 border rounded-md"
|
|
2329
|
+
/>
|
|
2330
|
+
</div>
|
|
2331
|
+
|
|
2332
|
+
<div>
|
|
2333
|
+
<label className="text-sm font-medium">Role *</label>
|
|
2334
|
+
<select
|
|
2335
|
+
value={formData.role}
|
|
2336
|
+
onChange={(e) => setFormData({ ...formData, role: e.target.value })}
|
|
2337
|
+
className="w-full px-3 py-2 border rounded-md"
|
|
2338
|
+
>
|
|
2339
|
+
<option value="">Select a role</option>
|
|
2340
|
+
<option value="engineer">Software Engineer</option>
|
|
2341
|
+
<option value="designer">UI/UX Designer</option>
|
|
2342
|
+
<option value="manager">Product Manager</option>
|
|
2343
|
+
</select>
|
|
2344
|
+
</div>
|
|
2345
|
+
</div>
|
|
2346
|
+
</HazoUiDialog>
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
```
|
|
2350
|
+
|
|
2351
|
+
#### Props Reference
|
|
2352
|
+
|
|
2353
|
+
| Prop | Type | Default | Description |
|
|
2354
|
+
|------|------|---------|-------------|
|
|
2355
|
+
| `open` | `boolean` | - | Controlled open state |
|
|
2356
|
+
| `onOpenChange` | `(open: boolean) => void` | - | Called when open state changes |
|
|
2357
|
+
| `children` | `React.ReactNode` | **Required** | Dialog body content |
|
|
2358
|
+
| `onConfirm` | `() => void` | - | Called when action button clicked |
|
|
2359
|
+
| `onCancel` | `() => void` | - | Called when cancel button clicked |
|
|
2360
|
+
| `title` | `string` | `"Action required"` | Dialog title |
|
|
2361
|
+
| `description` | `string` | - | Dialog description |
|
|
2362
|
+
| `actionButtonText` | `string` | `"Confirm"` | Action button label |
|
|
2363
|
+
| `actionButtonVariant` | `ButtonVariant` | `"default"` | Action button style |
|
|
2364
|
+
| `cancelButtonText` | `string` | `"Cancel"` | Cancel button label |
|
|
2365
|
+
| `showCancelButton` | `boolean` | `true` | Show cancel button |
|
|
2366
|
+
| `actionButtonLoading` | `boolean` | `false` | Shows loading spinner and disables action button |
|
|
2367
|
+
| `actionButtonDisabled` | `boolean` | `false` | Disables the action button |
|
|
2368
|
+
| `actionButtonIcon` | `React.ReactNode` | - | Icon element rendered before action button text |
|
|
2369
|
+
| `footerContent` | `React.ReactNode` | - | Custom footer content that replaces default buttons |
|
|
2370
|
+
| `sizeWidth` | `string` | `"min(90vw, 600px)"` | Dialog width |
|
|
2371
|
+
| `sizeHeight` | `string` | `"min(80vh, 800px)"` | Dialog max height |
|
|
2372
|
+
| `openAnimation` | `AnimationPreset \| string` | `"zoom"` | Open animation |
|
|
2373
|
+
| `closeAnimation` | `AnimationPreset \| string` | `"zoom"` | Close animation |
|
|
2374
|
+
| `headerBackgroundColor` | `string` | - | Header background color |
|
|
2375
|
+
| `headerTextColor` | `string` | - | Header text color |
|
|
2376
|
+
| `bodyBackgroundColor` | `string` | - | Body background color |
|
|
2377
|
+
| `footerBackgroundColor` | `string` | - | Footer background color |
|
|
2378
|
+
| `borderColor` | `string` | - | Dialog border color |
|
|
2379
|
+
| `accentColor` | `string` | - | Action button background color |
|
|
2380
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
2381
|
+
| `contentClassName` | `string` | - | Body CSS classes |
|
|
2382
|
+
| `overlayClassName` | `string` | - | Overlay CSS classes |
|
|
2383
|
+
| `headerClassName` | `string` | - | Header CSS classes |
|
|
2384
|
+
| `footerClassName` | `string` | - | Footer CSS classes |
|
|
2385
|
+
| `showCloseButton` | `boolean` | `true` | Show X close button |
|
|
2386
|
+
|
|
2387
|
+
---
|
|
2388
|
+
|
|
2389
|
+
## Troubleshooting
|
|
2390
|
+
|
|
2391
|
+
### Styles not applying (Tailwind v4)
|
|
2392
|
+
|
|
2393
|
+
If you're using Tailwind CSS v4 and components appear unstyled:
|
|
2394
|
+
|
|
2395
|
+
1. Add the `@source` directive to your globals.css:
|
|
2396
|
+
```css
|
|
2397
|
+
@import "tailwindcss";
|
|
2398
|
+
@source "../node_modules/hazo_ui/dist";
|
|
2399
|
+
```
|
|
2400
|
+
|
|
2401
|
+
2. Ensure you've imported the CSS variables:
|
|
2402
|
+
```tsx
|
|
2403
|
+
import 'hazo_ui/styles.css';
|
|
2404
|
+
```
|
|
2405
|
+
|
|
2406
|
+
### Missing hover states or colors
|
|
2407
|
+
|
|
2408
|
+
If hover states are transparent or colors don't appear:
|
|
2409
|
+
|
|
2410
|
+
- **Tailwind v4 users**: Add the `@source` directive (see above)
|
|
2411
|
+
- **Tailwind v3 users**: Verify `./node_modules/hazo_ui/dist/**/*.js` is in your `content` array
|
|
2412
|
+
|
|
2413
|
+
### Missing CSS variables
|
|
2414
|
+
|
|
2415
|
+
If you see errors about missing CSS variables, ensure you've either:
|
|
2416
|
+
- Imported `hazo_ui/styles.css` in your app entry point
|
|
2417
|
+
- Or configured your own CSS variables following the shadcn/ui pattern
|
|
2418
|
+
|
|
2419
|
+
### TypeScript errors
|
|
2420
|
+
|
|
2421
|
+
Ensure your tsconfig.json includes:
|
|
2422
|
+
```json
|
|
2423
|
+
{
|
|
2424
|
+
"compilerOptions": {
|
|
2425
|
+
"moduleResolution": "bundler"
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
```
|
|
2429
|
+
|
|
2430
|
+
### Select dropdowns clipped in dialogs
|
|
2431
|
+
|
|
2432
|
+
If Select dropdown options are cut off when used inside a Dialog:
|
|
2433
|
+
```css
|
|
2434
|
+
/* Add to your globals.css */
|
|
2435
|
+
[data-slot="dialog-content"]:has([data-slot="select-content"]),
|
|
2436
|
+
[data-slot="dialog-content"]:has([data-state="open"][data-slot="select-trigger"]) {
|
|
2437
|
+
overflow: visible !important;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
[data-slot="select-content"] {
|
|
2441
|
+
z-index: 9999 !important;
|
|
2442
|
+
}
|
|
2443
|
+
```
|
|
2444
|
+
|
|
2445
|
+
### Command pills not appearing (HazoUiTextbox/HazoUiTextarea)
|
|
2446
|
+
|
|
2447
|
+
1. Ensure `prefixes` prop is properly configured with `char` and `commands` arrays
|
|
2448
|
+
2. Verify you're typing the correct prefix character (e.g., @, #, /)
|
|
2449
|
+
3. Check that `@tiptap/react` and related extensions are installed
|
|
2450
|
+
|
|
2451
|
+
---
|
|
2452
|
+
|
|
1682
2453
|
## Styling
|
|
1683
2454
|
|
|
1684
2455
|
Both components use Tailwind CSS and follow shadcn/ui design patterns. Make sure your project has Tailwind CSS configured with the following CSS variables:
|
|
@@ -1714,23 +2485,29 @@ See the component library's Tailwind config for the complete set of CSS variable
|
|
|
1714
2485
|
npm run build
|
|
1715
2486
|
```
|
|
1716
2487
|
|
|
1717
|
-
### Run Storybook
|
|
1718
|
-
|
|
1719
|
-
```bash
|
|
1720
|
-
npm run storybook
|
|
1721
|
-
```
|
|
1722
|
-
|
|
1723
2488
|
### Run dev app
|
|
1724
2489
|
|
|
2490
|
+
The dev-app provides a comprehensive testing environment with dedicated pages for each component:
|
|
2491
|
+
|
|
1725
2492
|
```bash
|
|
1726
2493
|
npm run dev:app
|
|
1727
2494
|
```
|
|
1728
2495
|
|
|
2496
|
+
Navigate to `http://localhost:3000` to access:
|
|
2497
|
+
- **Home** - Library overview and quick start guide
|
|
2498
|
+
- **Component pages** - Individual test pages with multiple test cases for each component
|
|
2499
|
+
- **Sidebar navigation** - Easy navigation between all component tests
|
|
2500
|
+
|
|
2501
|
+
Each component page includes:
|
|
2502
|
+
- Multiple test sections covering different configurations
|
|
2503
|
+
- Real-time state display
|
|
2504
|
+
- Interactive examples
|
|
2505
|
+
|
|
1729
2506
|
### Test before publishing
|
|
1730
2507
|
|
|
1731
2508
|
```bash
|
|
1732
|
-
npm run test:build
|
|
1733
|
-
npm run test:dev
|
|
2509
|
+
npm run test:build # Build library + build dev-app
|
|
2510
|
+
npm run test:dev # Build library + run dev-app
|
|
1734
2511
|
```
|
|
1735
2512
|
|
|
1736
2513
|
## License
|