hazo_ui 2.7.1 → 2.7.3

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
@@ -49,11 +49,23 @@ If you're using **Tailwind CSS v4**, you must add the `@source` directive to ens
49
49
 
50
50
  ```css
51
51
  @import "tailwindcss";
52
+ @import "tw-animate-css";
52
53
 
53
54
  /* REQUIRED for Tailwind v4: Enable scanning of hazo_ui components */
54
55
  @source "../node_modules/hazo_ui/dist";
55
56
  ```
56
57
 
58
+ **PostCSS** (Tailwind v4):
59
+
60
+ ```js
61
+ // postcss.config.js
62
+ module.exports = {
63
+ plugins: {
64
+ "@tailwindcss/postcss": {},
65
+ },
66
+ };
67
+ ```
68
+
57
69
  **Why is this needed?**
58
70
 
59
71
  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:
@@ -61,7 +73,9 @@ Tailwind v4 uses JIT compilation and only generates CSS for classes found in sca
61
73
  - Colors will be missing
62
74
  - Layouts may break
63
75
 
64
- **Note:** Tailwind v3 users do NOT need this directive - the `content` configuration is sufficient.
76
+ The `tw-animate-css` import replaces the legacy `tailwindcss-animate` plugin (used by hazo_ui's accordion/collapse animations) for Tailwind v4 consumers.
77
+
78
+ **Note:** Tailwind v3 users do NOT need this directive — the `content` configuration plus `tailwindcss-animate@^1.0.7` is sufficient.
65
79
 
66
80
  ---
67
81
 
@@ -174,6 +188,8 @@ The following components support both global config and prop-level color overrid
174
188
 
175
189
  - **[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.
176
190
 
191
+ - **[HazoUiPillRadio](#hazouipillradio)** - Pill-shaped radio selection buttons with optional icons, customizable accent colors, size variants, and equal-width support. Ideal for action choices, status selection, and compact option groups.
192
+
177
193
  - **[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.
178
194
 
179
195
  - **[HazoUiRte](#hazouirte)** - A comprehensive rich text editor for email template generation with variable insertion support, file attachments, and full formatting controls. Built on Tiptap with support for tables, lists, images, and multiple view modes (HTML, Plain Text, Raw HTML).
@@ -884,6 +900,122 @@ The component supports the following react-icons packages:
884
900
 
885
901
  ---
886
902
 
903
+ ## HazoUiPillRadio
904
+
905
+ Pill-shaped radio selection buttons with optional icons, customizable accent colors per pill, size variants, and equal-width support. Ideal for action choices, status selection, and compact option groups.
906
+
907
+ #### Features
908
+
909
+ - **Pill Design**: Rounded-full pill buttons with border, selected state shows accent color tint
910
+ - **Icon Support**: Integration with react-icons library (same icon sets as HazoUiFlexRadio)
911
+ - **Custom Colors**: Each pill can have its own accent color for the selected state
912
+ - **Size Variants**: Three sizes — `sm`, `md` (default), `lg`
913
+ - **Layout Options**: Horizontal (default) or vertical arrangement
914
+ - **Equal Width**: Optional `equal_width` prop makes all pills the same width
915
+ - **Auto-fit Vertical**: Vertical layout auto-fits to the widest pill instead of stretching full-width
916
+ - **Tooltips**: Hover tooltips with 1-second delay
917
+ - **Accessible**: Uses `role="radiogroup"` and `role="radio"` with `aria-checked`
918
+
919
+ #### Props
920
+
921
+ ```typescript
922
+ interface HazoUiPillRadioItem {
923
+ label: string; // Text displayed in the pill
924
+ value: string; // Unique value identifier
925
+ icon?: string; // react-icons icon name (e.g., "FaFolder")
926
+ color?: string; // Accent color when selected (default: "#3b82f6" blue)
927
+ }
928
+
929
+ interface HazoUiPillRadioProps {
930
+ layout?: 'horizontal' | 'vertical'; // Layout direction (default: 'horizontal')
931
+ icon_set?: string; // Icon set package name (default: 'fa')
932
+ data: HazoUiPillRadioItem[]; // Array of pill options
933
+ value: string; // Controlled selected value
934
+ onChange: (value: string) => void; // Change handler
935
+ className?: string; // Additional CSS classes
936
+ pill_size?: 'sm' | 'md' | 'lg'; // Pill size variant (default: 'md')
937
+ equal_width?: boolean; // Make all pills equal width (default: false)
938
+ }
939
+ ```
940
+
941
+ #### Usage
942
+
943
+ **Basic Horizontal Pills**
944
+
945
+ ```tsx
946
+ import { HazoUiPillRadio, type HazoUiPillRadioItem } from 'hazo_ui';
947
+ import { useState } from 'react';
948
+
949
+ function ResponseSelector() {
950
+ const [selected, setSelected] = useState<string>('');
951
+
952
+ const options: HazoUiPillRadioItem[] = [
953
+ { value: 'upload', label: 'Upload corrected document', icon: 'FaFolder' },
954
+ { value: 'comment', label: 'Provide comment', icon: 'FaComment' },
955
+ ];
956
+
957
+ return (
958
+ <HazoUiPillRadio
959
+ data={options}
960
+ value={selected}
961
+ onChange={setSelected}
962
+ />
963
+ );
964
+ }
965
+ ```
966
+
967
+ **Vertical Layout**
968
+
969
+ ```tsx
970
+ <HazoUiPillRadio
971
+ data={options}
972
+ value={selected}
973
+ onChange={setSelected}
974
+ layout="vertical"
975
+ />
976
+ ```
977
+
978
+ **Custom Colors per Pill**
979
+
980
+ ```tsx
981
+ const priority_options: HazoUiPillRadioItem[] = [
982
+ { value: 'low', label: 'Low', icon: 'FaArrowDown', color: '#22c55e' },
983
+ { value: 'medium', label: 'Medium', icon: 'FaMinus', color: '#f59e0b' },
984
+ { value: 'high', label: 'High', icon: 'FaArrowUp', color: '#ef4444' },
985
+ ];
986
+
987
+ <HazoUiPillRadio
988
+ data={priority_options}
989
+ value={selected}
990
+ onChange={setSelected}
991
+ />
992
+ ```
993
+
994
+ **Equal Width Pills**
995
+
996
+ ```tsx
997
+ <HazoUiPillRadio
998
+ data={options}
999
+ value={selected}
1000
+ onChange={setSelected}
1001
+ equal_width
1002
+ />
1003
+ ```
1004
+
1005
+ **Different Icon Set and Size**
1006
+
1007
+ ```tsx
1008
+ <HazoUiPillRadio
1009
+ data={options}
1010
+ value={selected}
1011
+ onChange={setSelected}
1012
+ icon_set="md"
1013
+ pill_size="lg"
1014
+ />
1015
+ ```
1016
+
1017
+ ---
1018
+
887
1019
  ## HazoUiFlexInput
888
1020
 
889
1021
  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.
@@ -2841,9 +2973,10 @@ function FormDialog() {
2841
2973
 
2842
2974
  If you're using Tailwind CSS v4 and components appear unstyled:
2843
2975
 
2844
- 1. Add the `@source` directive to your globals.css:
2976
+ 1. Add the `@source` directive (and `tw-animate-css`) to your globals.css:
2845
2977
  ```css
2846
2978
  @import "tailwindcss";
2979
+ @import "tw-animate-css";
2847
2980
  @source "../node_modules/hazo_ui/dist";
2848
2981
  ```
2849
2982
 
package/dist/index.cjs CHANGED
@@ -152,7 +152,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
152
152
 
153
153
  // ../node_modules/@babel/runtime/helpers/extends.js
154
154
  var require_extends = __commonJS({
155
- "../node_modules/@babel/runtime/helpers/extends.js"(exports$1, module) {
155
+ "../node_modules/@babel/runtime/helpers/extends.js"(exports, module) {
156
156
  function _extends11() {
157
157
  return module.exports = _extends11 = Object.assign ? Object.assign.bind() : function(n) {
158
158
  for (var e = 1; e < arguments.length; e++) {
@@ -168,7 +168,7 @@ var require_extends = __commonJS({
168
168
 
169
169
  // ../node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js
170
170
  var require_objectWithoutPropertiesLoose = __commonJS({
171
- "../node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js"(exports$1, module) {
171
+ "../node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js"(exports, module) {
172
172
  function _objectWithoutPropertiesLoose10(r, e) {
173
173
  if (null == r) return {};
174
174
  var t = {};
@@ -1739,6 +1739,109 @@ function HazoUiFlexRadio({
1739
1739
  }
1740
1740
  }
1741
1741
  }
1742
+ var icon_set_map = {
1743
+ fa: FaIcons__namespace,
1744
+ md: MdIcons__namespace,
1745
+ hi: HiIcons__namespace,
1746
+ bi: BiIcons__namespace,
1747
+ ai: AiIcons__namespace,
1748
+ bs: BsIcons__namespace,
1749
+ fi: FiIcons__namespace,
1750
+ io: IoIcons__namespace,
1751
+ io5: IoIcons__namespace,
1752
+ ri: RiIcons__namespace,
1753
+ tb: TbIcons__namespace,
1754
+ ci: CiIcons__namespace
1755
+ };
1756
+ function get_icon_component(icon_set, icon_name) {
1757
+ if (!icon_set || !icon_name) return null;
1758
+ const library = icon_set_map[icon_set.toLowerCase()];
1759
+ if (!library) return null;
1760
+ return library[icon_name] || null;
1761
+ }
1762
+ var DEFAULT_COLOR = "#3b82f6";
1763
+ function color_with_opacity(color2, opacity) {
1764
+ if (color2.startsWith("#")) {
1765
+ const hex = color2.replace("#", "");
1766
+ const r = parseInt(hex.substring(0, 2), 16);
1767
+ const g = parseInt(hex.substring(2, 4), 16);
1768
+ const b = parseInt(hex.substring(4, 6), 16);
1769
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
1770
+ }
1771
+ return color2;
1772
+ }
1773
+ var size_classes = {
1774
+ sm: "px-3 py-1.5 text-xs gap-1.5",
1775
+ md: "px-4 py-2 text-sm gap-2",
1776
+ lg: "px-5 py-2.5 text-base gap-2.5"
1777
+ };
1778
+ var icon_size_classes = {
1779
+ sm: "h-3.5 w-3.5",
1780
+ md: "h-4 w-4",
1781
+ lg: "h-5 w-5"
1782
+ };
1783
+ function HazoUiPillRadio({
1784
+ layout = "horizontal",
1785
+ icon_set = "fa",
1786
+ data,
1787
+ value,
1788
+ onChange,
1789
+ className,
1790
+ pill_size = "md",
1791
+ equal_width = false
1792
+ }) {
1793
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 1e3, children: /* @__PURE__ */ jsxRuntime.jsx(
1794
+ "div",
1795
+ {
1796
+ className: cn(
1797
+ "cls_hazo_ui_pill_radio",
1798
+ layout === "horizontal" ? "flex flex-row flex-wrap gap-3" : "inline-flex flex-col gap-3",
1799
+ className
1800
+ ),
1801
+ role: "radiogroup",
1802
+ children: data.map((item) => {
1803
+ const is_selected = value === item.value;
1804
+ const accent = item.color || DEFAULT_COLOR;
1805
+ const IconComponent = get_icon_component(icon_set, item.icon);
1806
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { delayDuration: 1e3, children: [
1807
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1808
+ "button",
1809
+ {
1810
+ type: "button",
1811
+ role: "radio",
1812
+ "aria-checked": is_selected,
1813
+ onClick: () => onChange(item.value),
1814
+ className: cn(
1815
+ "cls_pill_radio_item",
1816
+ "inline-flex items-center rounded-full border cursor-pointer",
1817
+ "transition-all duration-200 font-medium whitespace-nowrap",
1818
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1819
+ size_classes[pill_size],
1820
+ equal_width && "justify-center flex-1",
1821
+ !is_selected && "border-border bg-card text-muted-foreground hover:bg-accent/50"
1822
+ ),
1823
+ style: is_selected ? {
1824
+ borderColor: accent,
1825
+ backgroundColor: color_with_opacity(accent, 0.08),
1826
+ color: accent
1827
+ } : void 0,
1828
+ children: [
1829
+ IconComponent && /* @__PURE__ */ jsxRuntime.jsx(
1830
+ IconComponent,
1831
+ {
1832
+ className: cn("cls_pill_radio_icon shrink-0", icon_size_classes[pill_size])
1833
+ }
1834
+ ),
1835
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_pill_radio_label", children: item.label })
1836
+ ]
1837
+ }
1838
+ ) }),
1839
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cls_tooltip_text", children: item.label }) })
1840
+ ] }, item.value);
1841
+ })
1842
+ }
1843
+ ) });
1844
+ }
1742
1845
  function validateInput(value, input_type, text_len_min, text_len_max, num_min, num_max, regex, num_decimals) {
1743
1846
  if (value === "") {
1744
1847
  return { isValid: true };
@@ -6937,6 +7040,7 @@ exports.HazoUiFlexInput = HazoUiFlexInput;
6937
7040
  exports.HazoUiFlexRadio = HazoUiFlexRadio;
6938
7041
  exports.HazoUiMultiFilterDialog = HazoUiMultiFilterDialog;
6939
7042
  exports.HazoUiMultiSortDialog = HazoUiMultiSortDialog;
7043
+ exports.HazoUiPillRadio = HazoUiPillRadio;
6940
7044
  exports.HazoUiRte = HazoUiRte;
6941
7045
  exports.HazoUiTextarea = HazoUiTextarea;
6942
7046
  exports.HazoUiTextbox = HazoUiTextbox;