hazo_ui 2.0.0 → 2.1.0

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
@@ -16,6 +16,8 @@ npm install hazo_ui
16
16
 
17
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
18
 
19
+ - **[MultiStateRadio](#multistateradio)** - 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
+
19
21
  ---
20
22
 
21
23
  ## MultiFilterDialog
@@ -444,6 +446,227 @@ const sortedData = applySorts(originalData, sorts);
444
446
 
445
447
  ---
446
448
 
449
+ ## MultiStateRadio
450
+
451
+ 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.
452
+
453
+ #### Features
454
+
455
+ - **Single & Multi-Selection**: Support for both single selection (radio) and multi-selection (checkbox) modes
456
+ - **Layout Options**: Horizontal (default) or vertical arrangement of options
457
+ - **Style Variants**: Radio button style or icon-only button style
458
+ - **Icon Support**: Integration with react-icons library (supports fa, md, hi, bi, ai, bs, fi, io, ri, tb icon sets)
459
+ - **Label Control**: Option to show or hide labels
460
+ - **Tooltips**: Hover tooltips with 1-second delay showing option labels
461
+ - **Responsive Design**: Adaptive spacing and sizing for different screen sizes
462
+ - **Controlled Component**: Fully controlled component with value/onChange pattern
463
+ - **TypeScript Support**: Fully typed with TypeScript interfaces
464
+ - **Accessible**: Built with accessibility in mind using Radix UI primitives
465
+
466
+ #### Props
467
+
468
+ ```typescript
469
+ interface MultiStateRadioItem {
470
+ label: string; // Display label for the option
471
+ value: string; // Unique value identifier
472
+ icon_selected?: string; // Icon name when selected (e.g., "FaHome")
473
+ icon_unselected?: string; // Icon name when unselected (e.g., "FaRegHome")
474
+ }
475
+
476
+ interface MultiStateRadioProps {
477
+ layout?: 'horizontal' | 'vertical'; // Layout direction (default: 'horizontal')
478
+ style?: 'radio' | 'icons'; // Display style (default: 'radio')
479
+ display_label?: boolean; // Show/hide labels (default: true)
480
+ icon_set?: string; // Icon set package name (e.g., 'fa', 'md')
481
+ data: MultiStateRadioItem[]; // Array of options
482
+ selection: 'single' | 'multi'; // Selection mode
483
+ value: string | string[]; // Controlled value (string for single, array for multi)
484
+ onChange: (value: string | string[]) => void; // Change handler
485
+ className?: string; // Additional CSS classes
486
+ }
487
+ ```
488
+
489
+ #### Usage
490
+
491
+ **Basic Single Selection (Radio Style)**
492
+
493
+ ```tsx
494
+ import { MultiStateRadio, type MultiStateRadioItem } from 'hazo_ui';
495
+ import { useState } from 'react';
496
+
497
+ function SettingsPanel() {
498
+ const [selectedOption, setSelectedOption] = useState<string>('option1');
499
+
500
+ const options: MultiStateRadioItem[] = [
501
+ { label: 'Option 1', value: 'option1' },
502
+ { label: 'Option 2', value: 'option2' },
503
+ { label: 'Option 3', value: 'option3' },
504
+ { label: 'Option 4', value: 'option4' },
505
+ ];
506
+
507
+ return (
508
+ <MultiStateRadio
509
+ data={options}
510
+ value={selectedOption}
511
+ onChange={setSelectedOption}
512
+ selection="single"
513
+ layout="horizontal"
514
+ style="radio"
515
+ display_label={true}
516
+ />
517
+ );
518
+ }
519
+ ```
520
+
521
+ **Icon Style with React Icons**
522
+
523
+ ```tsx
524
+ import { MultiStateRadio, type MultiStateRadioItem } from 'hazo_ui';
525
+ import { useState } from 'react';
526
+
527
+ function IconSelector() {
528
+ const [selectedIcon, setSelectedIcon] = useState<string>('home');
529
+
530
+ const iconOptions: MultiStateRadioItem[] = [
531
+ {
532
+ label: 'Home',
533
+ value: 'home',
534
+ icon_selected: 'FaHome',
535
+ icon_unselected: 'FaRegHome',
536
+ },
537
+ {
538
+ label: 'User',
539
+ value: 'user',
540
+ icon_selected: 'FaUser',
541
+ icon_unselected: 'FaRegUser',
542
+ },
543
+ {
544
+ label: 'Settings',
545
+ value: 'settings',
546
+ icon_selected: 'FaCog',
547
+ icon_unselected: 'FaRegCog',
548
+ },
549
+ ];
550
+
551
+ return (
552
+ <MultiStateRadio
553
+ data={iconOptions}
554
+ value={selectedIcon}
555
+ onChange={setSelectedIcon}
556
+ selection="single"
557
+ layout="horizontal"
558
+ style="icons"
559
+ display_label={true}
560
+ icon_set="fa" // FontAwesome icons
561
+ />
562
+ );
563
+ }
564
+ ```
565
+
566
+ **Multi-Selection Mode**
567
+
568
+ ```tsx
569
+ import { MultiStateRadio, type MultiStateRadioItem } from 'hazo_ui';
570
+ import { useState } from 'react';
571
+
572
+ function MultiSelectExample() {
573
+ const [selectedOptions, setSelectedOptions] = useState<string[]>(['option1', 'option3']);
574
+
575
+ const options: MultiStateRadioItem[] = [
576
+ { label: 'Option 1', value: 'option1' },
577
+ { label: 'Option 2', value: 'option2' },
578
+ { label: 'Option 3', value: 'option3' },
579
+ { label: 'Option 4', value: 'option4' },
580
+ ];
581
+
582
+ return (
583
+ <MultiStateRadio
584
+ data={options}
585
+ value={selectedOptions}
586
+ onChange={setSelectedOptions}
587
+ selection="multi"
588
+ layout="horizontal"
589
+ style="radio"
590
+ display_label={true}
591
+ />
592
+ );
593
+ }
594
+ ```
595
+
596
+ **Vertical Layout with Icons Only (No Labels)**
597
+
598
+ ```tsx
599
+ import { MultiStateRadio, type MultiStateRadioItem } from 'hazo_ui';
600
+ import { useState } from 'react';
601
+
602
+ function VerticalIconSelector() {
603
+ const [selected, setSelected] = useState<string>('favorite');
604
+
605
+ const options: MultiStateRadioItem[] = [
606
+ {
607
+ label: 'Favorite',
608
+ value: 'favorite',
609
+ icon_selected: 'MdFavorite',
610
+ icon_unselected: 'MdFavoriteBorder',
611
+ },
612
+ {
613
+ label: 'Star',
614
+ value: 'star',
615
+ icon_selected: 'MdStar',
616
+ icon_unselected: 'MdStarBorder',
617
+ },
618
+ ];
619
+
620
+ return (
621
+ <MultiStateRadio
622
+ data={options}
623
+ value={selected}
624
+ onChange={setSelected}
625
+ selection="single"
626
+ layout="vertical"
627
+ style="icons"
628
+ display_label={false} // Hide labels, show only icons
629
+ icon_set="md" // Material Design icons
630
+ />
631
+ );
632
+ }
633
+ ```
634
+
635
+ #### Supported Icon Sets
636
+
637
+ The component supports the following react-icons packages:
638
+
639
+ - `fa` - FontAwesome (react-icons/fa)
640
+ - `md` - Material Design (react-icons/md)
641
+ - `hi` - Heroicons (react-icons/hi)
642
+ - `bi` - Bootstrap Icons (react-icons/bi)
643
+ - `ai` - Ant Design Icons (react-icons/ai)
644
+ - `bs` - Bootstrap Icons (react-icons/bs)
645
+ - `fi` - Feather Icons (react-icons/fi)
646
+ - `io` / `io5` - Ionicons (react-icons/io5)
647
+ - `ri` - Remix Icon (react-icons/ri)
648
+ - `tb` - Tabler Icons (react-icons/tb)
649
+
650
+ #### Expected Output
651
+
652
+ **Single Selection Mode:**
653
+ ```typescript
654
+ // onChange receives a string value
655
+ 'onChange' => (value: string) => {
656
+ // value will be the selected option's value, e.g., "option1"
657
+ }
658
+ ```
659
+
660
+ **Multi-Selection Mode:**
661
+ ```typescript
662
+ // onChange receives an array of string values
663
+ 'onChange' => (value: string[]) => {
664
+ // value will be an array of selected values, e.g., ["option1", "option3"]
665
+ }
666
+ ```
667
+
668
+ ---
669
+
447
670
  ## Styling
448
671
 
449
672
  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
@@ -17,6 +17,17 @@ var SwitchPrimitives = require('@radix-ui/react-switch');
17
17
  var core = require('@dnd-kit/core');
18
18
  var sortable = require('@dnd-kit/sortable');
19
19
  var utilities = require('@dnd-kit/utilities');
20
+ var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
21
+ var FaIcons = require('react-icons/fa');
22
+ var MdIcons = require('react-icons/md');
23
+ var HiIcons = require('react-icons/hi');
24
+ var BiIcons = require('react-icons/bi');
25
+ var AiIcons = require('react-icons/ai');
26
+ var BsIcons = require('react-icons/bs');
27
+ var FiIcons = require('react-icons/fi');
28
+ var IoIcons = require('react-icons/io5');
29
+ var RiIcons = require('react-icons/ri');
30
+ var TbIcons = require('react-icons/tb');
20
31
 
21
32
  function _interopNamespace(e) {
22
33
  if (e && e.__esModule) return e;
@@ -42,6 +53,17 @@ var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitiv
42
53
  var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
43
54
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
44
55
  var SwitchPrimitives__namespace = /*#__PURE__*/_interopNamespace(SwitchPrimitives);
56
+ var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
57
+ var FaIcons__namespace = /*#__PURE__*/_interopNamespace(FaIcons);
58
+ var MdIcons__namespace = /*#__PURE__*/_interopNamespace(MdIcons);
59
+ var HiIcons__namespace = /*#__PURE__*/_interopNamespace(HiIcons);
60
+ var BiIcons__namespace = /*#__PURE__*/_interopNamespace(BiIcons);
61
+ var AiIcons__namespace = /*#__PURE__*/_interopNamespace(AiIcons);
62
+ var BsIcons__namespace = /*#__PURE__*/_interopNamespace(BsIcons);
63
+ var FiIcons__namespace = /*#__PURE__*/_interopNamespace(FiIcons);
64
+ var IoIcons__namespace = /*#__PURE__*/_interopNamespace(IoIcons);
65
+ var RiIcons__namespace = /*#__PURE__*/_interopNamespace(RiIcons);
66
+ var TbIcons__namespace = /*#__PURE__*/_interopNamespace(TbIcons);
45
67
 
46
68
  var ExampleComponent = ({ children, className = "" }) => {
47
69
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `cls_example_component ${className}`, children });
@@ -786,30 +808,27 @@ function MultiFilterDialog({
786
808
  ) }),
787
809
  /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "cls_combobox_popover w-full p-0", children: /* @__PURE__ */ jsxRuntime.jsxs(Command, { children: [
788
810
  /* @__PURE__ */ jsxRuntime.jsx(CommandInput, { placeholder: "Search fields...", className: "cls_command_input" }),
789
- /* @__PURE__ */ jsxRuntime.jsxs(CommandList, { children: [
790
- /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No fields found." }),
791
- /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: availableFieldsToAdd.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
792
- CommandItem,
793
- {
794
- value: field.value,
795
- onSelect: () => handleAddField(field.value),
796
- className: "cls_command_item",
797
- children: [
798
- /* @__PURE__ */ jsxRuntime.jsx(
799
- lucideReact.Check,
800
- {
801
- className: cn(
802
- "cls_check_icon mr-2 h-4 w-4",
803
- "opacity-0"
804
- )
805
- }
806
- ),
807
- field.label
808
- ]
809
- },
810
- field.value
811
- )) })
812
- ] })
811
+ /* @__PURE__ */ jsxRuntime.jsx(CommandList, { children: availableFieldsToAdd.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No fields found." }) : /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: availableFieldsToAdd.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
812
+ CommandItem,
813
+ {
814
+ value: field.label,
815
+ onSelect: () => handleAddField(field.value),
816
+ className: "cls_command_item",
817
+ children: [
818
+ /* @__PURE__ */ jsxRuntime.jsx(
819
+ lucideReact.Check,
820
+ {
821
+ className: cn(
822
+ "cls_check_icon mr-2 h-4 w-4",
823
+ "opacity-0"
824
+ )
825
+ }
826
+ ),
827
+ field.label
828
+ ]
829
+ },
830
+ field.value
831
+ )) }) })
813
832
  ] }) })
814
833
  ] }) }),
815
834
  filterFields.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_filter_fields_list space-y-2", children: filterFields.map((filterConfig) => {
@@ -1091,30 +1110,27 @@ function MultiSortDialog({
1091
1110
  ) }),
1092
1111
  /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "cls_combobox_popover w-full p-0", children: /* @__PURE__ */ jsxRuntime.jsxs(Command, { children: [
1093
1112
  /* @__PURE__ */ jsxRuntime.jsx(CommandInput, { placeholder: "Search fields...", className: "cls_command_input" }),
1094
- /* @__PURE__ */ jsxRuntime.jsxs(CommandList, { children: [
1095
- /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No fields found." }),
1096
- /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: availableFieldsToAdd.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
1097
- CommandItem,
1098
- {
1099
- value: field.value,
1100
- onSelect: () => handleAddField(field.value),
1101
- className: "cls_command_item",
1102
- children: [
1103
- /* @__PURE__ */ jsxRuntime.jsx(
1104
- lucideReact.Check,
1105
- {
1106
- className: cn(
1107
- "cls_check_icon mr-2 h-4 w-4",
1108
- "opacity-0"
1109
- )
1110
- }
1111
- ),
1112
- field.label
1113
- ]
1114
- },
1115
- field.value
1116
- )) })
1117
- ] })
1113
+ /* @__PURE__ */ jsxRuntime.jsx(CommandList, { children: availableFieldsToAdd.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No fields found." }) : /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: availableFieldsToAdd.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
1114
+ CommandItem,
1115
+ {
1116
+ value: field.label,
1117
+ onSelect: () => handleAddField(field.value),
1118
+ className: "cls_command_item",
1119
+ children: [
1120
+ /* @__PURE__ */ jsxRuntime.jsx(
1121
+ lucideReact.Check,
1122
+ {
1123
+ className: cn(
1124
+ "cls_check_icon mr-2 h-4 w-4",
1125
+ "opacity-0"
1126
+ )
1127
+ }
1128
+ ),
1129
+ field.label
1130
+ ]
1131
+ },
1132
+ field.value
1133
+ )) }) })
1118
1134
  ] }) })
1119
1135
  ] }) }),
1120
1136
  sortFields.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_sort_fields_list space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -1177,9 +1193,250 @@ function MultiSortDialog({
1177
1193
  ] })
1178
1194
  ] });
1179
1195
  }
1196
+ var RadioGroup = React6__namespace.forwardRef(({ className, ...props }, ref) => {
1197
+ return /* @__PURE__ */ jsxRuntime.jsx(
1198
+ RadioGroupPrimitive__namespace.Root,
1199
+ {
1200
+ className: cn("grid gap-2", className),
1201
+ ...props,
1202
+ ref
1203
+ }
1204
+ );
1205
+ });
1206
+ RadioGroup.displayName = RadioGroupPrimitive__namespace.Root.displayName;
1207
+ var RadioGroupItem = React6__namespace.forwardRef(({ className, ...props }, ref) => {
1208
+ return /* @__PURE__ */ jsxRuntime.jsx(
1209
+ RadioGroupPrimitive__namespace.Item,
1210
+ {
1211
+ ref,
1212
+ className: cn(
1213
+ "aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1214
+ className
1215
+ ),
1216
+ ...props,
1217
+ children: /* @__PURE__ */ jsxRuntime.jsx(RadioGroupPrimitive__namespace.Indicator, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "h-2.5 w-2.5 fill-current text-current" }) })
1218
+ }
1219
+ );
1220
+ });
1221
+ RadioGroupItem.displayName = RadioGroupPrimitive__namespace.Item.displayName;
1222
+ var iconSetMap = {
1223
+ fa: FaIcons__namespace,
1224
+ md: MdIcons__namespace,
1225
+ hi: HiIcons__namespace,
1226
+ bi: BiIcons__namespace,
1227
+ ai: AiIcons__namespace,
1228
+ bs: BsIcons__namespace,
1229
+ fi: FiIcons__namespace,
1230
+ io: IoIcons__namespace,
1231
+ io5: IoIcons__namespace,
1232
+ ri: RiIcons__namespace,
1233
+ tb: TbIcons__namespace
1234
+ };
1235
+ function getIconLibrary(iconSet) {
1236
+ if (!iconSet) return null;
1237
+ const normalizedSet = iconSet.toLowerCase();
1238
+ return iconSetMap[normalizedSet] || null;
1239
+ }
1240
+ function getIconComponent(iconSet, iconName) {
1241
+ if (!iconSet || !iconName) return null;
1242
+ const iconLibrary = getIconLibrary(iconSet);
1243
+ if (!iconLibrary) return null;
1244
+ const IconComponent = iconLibrary[iconName];
1245
+ return IconComponent || null;
1246
+ }
1247
+ function MultiStateRadio({
1248
+ layout = "horizontal",
1249
+ style = "radio",
1250
+ display_label = true,
1251
+ icon_set,
1252
+ data,
1253
+ selection = "single",
1254
+ value,
1255
+ onChange,
1256
+ className
1257
+ }) {
1258
+ const handleSingleSelection = (selectedValue) => {
1259
+ onChange(selectedValue);
1260
+ };
1261
+ const handleMultiSelection = (selectedValue) => {
1262
+ const currentValues = Array.isArray(value) ? value : [];
1263
+ const isSelected2 = currentValues.includes(selectedValue);
1264
+ if (isSelected2) {
1265
+ onChange(currentValues.filter((v) => v !== selectedValue));
1266
+ } else {
1267
+ onChange([...currentValues, selectedValue]);
1268
+ }
1269
+ };
1270
+ const isSelected = (itemValue) => {
1271
+ if (selection === "single") {
1272
+ return value === itemValue;
1273
+ } else {
1274
+ const currentValues = Array.isArray(value) ? value : [];
1275
+ return currentValues.includes(itemValue);
1276
+ }
1277
+ };
1278
+ const renderRadioOption = (item) => {
1279
+ const selected = isSelected(item.value);
1280
+ if (selection === "single") {
1281
+ const optionContent = /* @__PURE__ */ jsxRuntime.jsxs(
1282
+ "div",
1283
+ {
1284
+ className: cn(
1285
+ "cls_radio_option flex items-center gap-2",
1286
+ layout === "horizontal" ? "flex-row" : "flex-col",
1287
+ "p-2 rounded-md hover:bg-accent transition-colors",
1288
+ selected && "bg-accent"
1289
+ ),
1290
+ children: [
1291
+ /* @__PURE__ */ jsxRuntime.jsx(
1292
+ RadioGroupItem,
1293
+ {
1294
+ value: item.value,
1295
+ id: `radio-${item.value}`,
1296
+ className: "cls_radio_item shrink-0"
1297
+ }
1298
+ ),
1299
+ display_label && /* @__PURE__ */ jsxRuntime.jsx(
1300
+ "label",
1301
+ {
1302
+ htmlFor: `radio-${item.value}`,
1303
+ className: "cls_radio_label text-sm font-medium cursor-pointer flex-1",
1304
+ children: item.label
1305
+ }
1306
+ )
1307
+ ]
1308
+ }
1309
+ );
1310
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { delayDuration: 1e3, children: [
1311
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: optionContent }),
1312
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cls_tooltip_text", children: item.label }) })
1313
+ ] }, item.value);
1314
+ } else {
1315
+ const optionContent = /* @__PURE__ */ jsxRuntime.jsxs(
1316
+ "div",
1317
+ {
1318
+ className: cn(
1319
+ "cls_radio_option flex items-center gap-2 cursor-pointer",
1320
+ layout === "horizontal" ? "flex-row" : "flex-col",
1321
+ "p-2 rounded-md hover:bg-accent transition-colors",
1322
+ selected && "bg-accent"
1323
+ ),
1324
+ onClick: () => handleMultiSelection(item.value),
1325
+ role: "button",
1326
+ tabIndex: 0,
1327
+ onKeyDown: (e) => {
1328
+ if (e.key === "Enter" || e.key === " ") {
1329
+ e.preventDefault();
1330
+ handleMultiSelection(item.value);
1331
+ }
1332
+ },
1333
+ children: [
1334
+ /* @__PURE__ */ jsxRuntime.jsx(
1335
+ "div",
1336
+ {
1337
+ className: cn(
1338
+ "cls_checkbox_indicator h-4 w-4 rounded-sm border-2 border-primary flex items-center justify-center transition-colors shrink-0",
1339
+ selected ? "bg-primary" : "bg-background"
1340
+ ),
1341
+ children: selected && /* @__PURE__ */ jsxRuntime.jsx(
1342
+ "svg",
1343
+ {
1344
+ className: "cls_checkmark h-3 w-3 text-primary-foreground",
1345
+ fill: "none",
1346
+ viewBox: "0 0 24 24",
1347
+ stroke: "currentColor",
1348
+ strokeWidth: 3,
1349
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1350
+ "path",
1351
+ {
1352
+ strokeLinecap: "round",
1353
+ strokeLinejoin: "round",
1354
+ d: "M5 13l4 4L19 7"
1355
+ }
1356
+ )
1357
+ }
1358
+ )
1359
+ }
1360
+ ),
1361
+ display_label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_checkbox_label text-sm font-medium flex-1", children: item.label })
1362
+ ]
1363
+ }
1364
+ );
1365
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { delayDuration: 1e3, children: [
1366
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: optionContent }),
1367
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cls_tooltip_text", children: item.label }) })
1368
+ ] }, item.value);
1369
+ }
1370
+ };
1371
+ const renderIconOption = (item) => {
1372
+ const selected = isSelected(item.value);
1373
+ const SelectedIcon = icon_set && item.icon_selected ? getIconComponent(icon_set, item.icon_selected) : null;
1374
+ const UnselectedIcon = icon_set && item.icon_unselected ? getIconComponent(icon_set, item.icon_unselected) : null;
1375
+ const IconComponent = selected && SelectedIcon ? SelectedIcon : UnselectedIcon || SelectedIcon;
1376
+ const buttonContent = /* @__PURE__ */ jsxRuntime.jsxs(
1377
+ Button,
1378
+ {
1379
+ variant: selected ? "default" : "ghost",
1380
+ size: "default",
1381
+ className: cn(
1382
+ "cls_icon_option border-0",
1383
+ layout === "horizontal" ? "flex-row" : "flex-col",
1384
+ "gap-2 h-auto py-2 px-3 sm:py-3 sm:px-4",
1385
+ selected && "bg-primary text-primary-foreground",
1386
+ !selected && "hover:bg-accent"
1387
+ ),
1388
+ onClick: () => {
1389
+ if (selection === "single") {
1390
+ handleSingleSelection(item.value);
1391
+ } else {
1392
+ handleMultiSelection(item.value);
1393
+ }
1394
+ },
1395
+ "aria-label": item.label,
1396
+ "aria-pressed": selected,
1397
+ children: [
1398
+ IconComponent && /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "cls_icon h-4 w-4 sm:h-5 sm:w-5" }),
1399
+ display_label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_icon_label text-sm font-medium", children: item.label })
1400
+ ]
1401
+ }
1402
+ );
1403
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { delayDuration: 1e3, children: [
1404
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: buttonContent }),
1405
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cls_tooltip_text", children: item.label }) })
1406
+ ] }, item.value);
1407
+ };
1408
+ const containerClasses = cn(
1409
+ "cls_multi_state_radio border border-input rounded-md p-2 sm:p-3",
1410
+ layout === "horizontal" ? "flex flex-row flex-wrap gap-2 sm:gap-3" : "flex flex-col gap-2 sm:gap-3",
1411
+ className
1412
+ );
1413
+ const radioGroupClasses = cn(
1414
+ containerClasses,
1415
+ "!flex !flex-row !flex-wrap"
1416
+ // Override RadioGroup's default grid
1417
+ );
1418
+ if (style === "icons") {
1419
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 1e3, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: containerClasses, role: selection === "single" ? "radiogroup" : "group", children: data.map((item) => renderIconOption(item)) }) });
1420
+ } else {
1421
+ if (selection === "single") {
1422
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 1e3, children: /* @__PURE__ */ jsxRuntime.jsx(
1423
+ RadioGroup,
1424
+ {
1425
+ value: typeof value === "string" ? value : "",
1426
+ onValueChange: handleSingleSelection,
1427
+ className: layout === "horizontal" ? cn(radioGroupClasses, "!flex-row") : cn(radioGroupClasses, "!flex-col"),
1428
+ children: data.map((item) => renderRadioOption(item))
1429
+ }
1430
+ ) });
1431
+ } else {
1432
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 1e3, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: containerClasses, role: "group", children: data.map((item) => renderRadioOption(item)) }) });
1433
+ }
1434
+ }
1435
+ }
1180
1436
 
1181
1437
  exports.ExampleComponent = ExampleComponent;
1182
1438
  exports.MultiFilterDialog = MultiFilterDialog;
1183
1439
  exports.MultiSortDialog = MultiSortDialog;
1440
+ exports.MultiStateRadio = MultiStateRadio;
1184
1441
  //# sourceMappingURL=index.cjs.map
1185
1442
  //# sourceMappingURL=index.cjs.map