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 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