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 +223 -0
- package/dist/index.cjs +305 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +295 -50
- package/dist/index.js.map +1 -1
- package/package.json +11 -9
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.
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
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.
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
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
|