linkedunion-design-kit 1.11.9 → 1.11.11

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/dist/index.d.ts CHANGED
@@ -40,3 +40,4 @@ export { TimePicker } from "./src/components/TimePicker/TimePicker";
40
40
  export * from "./src/components/Sheet";
41
41
  export * from "./src/components/Separator";
42
42
  export { SweetAlert, SweetAlertTrigger, SweetAlertContent, SweetAlertFooter, SweetAlertTitle, SweetAlertDescription, SweetAlertAction, SweetAlertCancel, SweetAlertIcon, } from "./src/components/SweetAlert/SweetAlert";
43
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, } from "./src/components/Popover/popover";
package/dist/index.js CHANGED
@@ -39,3 +39,4 @@ export { TimePicker } from "./src/components/TimePicker/TimePicker";
39
39
  export * from "./src/components/Sheet";
40
40
  export * from "./src/components/Separator";
41
41
  export { SweetAlert, SweetAlertTrigger, SweetAlertContent, SweetAlertFooter, SweetAlertTitle, SweetAlertDescription, SweetAlertAction, SweetAlertCancel, SweetAlertIcon, } from "./src/components/SweetAlert/SweetAlert";
42
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, } from "./src/components/Popover/popover";
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Alert, AlertAction, AlertCancel, AlertHeader, AlertTitle, AlertDescription, AlertFooter, colorOptions, sizeOptions, shadowOptions, variantOptions, getIconForColor, getContentForColor, } from "../AlertDialog/index";
2
+ import { Alert, AlertAction, AlertCancel, AlertHeader, AlertTitle, AlertDescription, AlertFooter, } from "./alert";
3
+ import { colorOptions, sizeOptions, shadowOptions, variantOptions, getIconForColor, getContentForColor, } from "../AlertDialog/index";
3
4
  import LUIcon from "../../Icons/LUIcon";
4
5
  import { Button } from "../../Button/Button/Button";
5
6
  import { Heading } from "../../Typography/Heading/heading";
@@ -1,5 +1,4 @@
1
1
  export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, alertDialogVariants, } from "./alert-dialog";
2
- export { Alert, AlertAction, AlertCancel, AlertHeader, AlertTitle, AlertDescription, AlertFooter, } from "../Alert/alert";
3
2
  import { alertDialogVariants } from "./alert-dialog";
4
3
  export declare const colorOptions: Array<keyof typeof alertDialogVariants.color>;
5
4
  export declare const sizeOptions: Array<keyof typeof alertDialogVariants.size>;
@@ -1,7 +1,5 @@
1
1
  // Export the main AlertDialog components
2
2
  export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, alertDialogVariants, } from "./alert-dialog";
3
- // Export the Alert components (non-modal version)
4
- export { Alert, AlertAction, AlertCancel, AlertHeader, AlertTitle, AlertDescription, AlertFooter, } from "../Alert/alert";
5
3
  // Utility imports
6
4
  import { alertDialogVariants } from "./alert-dialog";
7
5
  // Extract options dynamically from the component with proper typing
@@ -18,7 +18,7 @@ export var buttonStyles = {
18
18
  },
19
19
  size: {
20
20
  xl: "h-13 !py-3.5 !px-6 !text-base !font-normal !leading-normal",
21
- lg: "h-12 !py-3 !px-5 !text-base !font-normal !leading-normal",
21
+ lg: "h-12 !py-3 !px-5 !text-base font-normal !leading-normal",
22
22
  md: "h-10 !py-2.5 !px-5 !text-sm !font-normal !leading-5",
23
23
  sm: "h-9 !py-2 !px-3 !text-sm !font-normal !leading-5",
24
24
  },
@@ -25,7 +25,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
25
25
  import { format } from "date-fns";
26
26
  import { cn } from "../../lib/utils";
27
27
  import { Calendar } from "../ui/calendar";
28
- import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
28
+ import { Popover, PopoverContent, PopoverTrigger } from "../Popover/popover";
29
29
  import LUIcon from "../Icons/LUIcon";
30
30
  import { getIconSize, getPadding, getIconPosition } from "../Input";
31
31
  import { inputVariantConfig, inputVariants } from "../Input/input";
@@ -34,7 +34,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
34
34
  import { format, startOfDay } from "date-fns";
35
35
  import { cn } from "../../lib/utils";
36
36
  import { Calendar } from "../ui/calendar";
37
- import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
37
+ import { Popover, PopoverContent, PopoverTrigger } from "../Popover/popover";
38
38
  import LUIcon from "../Icons/LUIcon";
39
39
  import { getIconSize, getPadding, getIconPosition } from "../Input";
40
40
  import { inputVariantConfig, inputVariants } from "../Input/input";
@@ -14,7 +14,7 @@ import { cn } from "../../../lib/utils";
14
14
  import { Badge } from "../../../components/Badge/Badge";
15
15
  import { renderBadge } from "./utils/renderBadge";
16
16
  import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "../../../components/ui/command";
17
- import { Popover, PopoverContent, PopoverTrigger, } from "../../../components/ui/popover";
17
+ import { Popover, PopoverContent, PopoverTrigger, } from "../../../components/Popover/popover";
18
18
  import { Button } from "../../../components/Button/Button/Button";
19
19
  import LUIcon from "../../../components/Icons/LUIcon";
20
20
  import { Checkbox } from "../../../components/Checkbox/checkbox";
@@ -32,7 +32,19 @@ var Combobox = function (props) {
32
32
  var _l = useState([]), multiValue = _l[0], setMultiValue = _l[1];
33
33
  var buttonRef = useRef(null);
34
34
  var _m = useState(), popoverWidth = _m[0], setPopoverWidth = _m[1];
35
- var maxVisibleBadges = useResponsiveBadges();
35
+ var selectedOptions = useMemo(function () {
36
+ if (!isMulti || !options || !multiValue.length)
37
+ return [];
38
+ return options.filter(function (option) {
39
+ return typeof option === "string"
40
+ ? multiValue.includes(option)
41
+ : multiValue.includes(option.value);
42
+ });
43
+ }, [isMulti, options, multiValue]);
44
+ var selectedLabels = useMemo(function () {
45
+ return selectedOptions.map(function (opt) { return (typeof opt === "string" ? opt : opt.key); });
46
+ }, [selectedOptions]);
47
+ var maxVisibleBadges = useResponsiveBadges(buttonRef, selectedLabels);
36
48
  useEffect(function () {
37
49
  if (isMulti && Array.isArray(defaultValue)) {
38
50
  setMultiValue(defaultValue);
@@ -74,47 +86,36 @@ var Combobox = function (props) {
74
86
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(newValues);
75
87
  };
76
88
  var getDisplay = useMemo(function () {
77
- var handleRemove = function (value) {
78
- if (isMulti) {
79
- var newValues = multiValue.filter(function (val) { return val !== value; });
80
- setMultiValue(newValues);
81
- onSelect === null || onSelect === void 0 ? void 0 : onSelect(newValues);
82
- }
83
- else {
84
- setSingleValue("");
85
- onSelect === null || onSelect === void 0 ? void 0 : onSelect("");
86
- }
87
- };
88
89
  if (!options)
89
90
  return placeholder;
90
91
  if (isMulti) {
91
- if (!multiValue.length)
92
+ var handleRemove_1 = function (value) {
93
+ var newValues = multiValue.filter(function (val) { return val !== value; });
94
+ setMultiValue(newValues);
95
+ onSelect === null || onSelect === void 0 ? void 0 : onSelect(newValues);
96
+ };
97
+ if (!selectedOptions.length)
92
98
  return placeholder;
93
- var selectedOptions = options.filter(function (option) {
94
- return typeof option === "string"
95
- ? multiValue.includes(option)
96
- : multiValue.includes(option.value);
97
- });
98
99
  if (selectedOptions.length <= maxVisibleBadges) {
99
- return (_jsx("div", { className: "flex flex-wrap gap-1", children: selectedOptions.map(function (option) {
100
+ return (_jsx("div", { className: "flex flex-nowrap gap-1 overflow-hidden", children: selectedOptions.map(function (option) {
100
101
  return renderBadge(typeof option === "string"
101
102
  ? { key: option, value: option }
102
- : option, handleRemove);
103
+ : option, handleRemove_1);
103
104
  }) }));
104
105
  }
105
106
  var remainingCount = selectedOptions.length - maxVisibleBadges;
106
107
  var remainingOptions = selectedOptions.slice(maxVisibleBadges);
107
- return (_jsxs("div", { className: "flex flex-wrap gap-1", children: [selectedOptions
108
+ return (_jsxs("div", { className: "flex flex-nowrap gap-1 overflow-hidden", children: [selectedOptions
108
109
  .slice(0, maxVisibleBadges)
109
110
  .map(function (option) {
110
111
  return renderBadge(typeof option === "string"
111
112
  ? { key: option, value: option }
112
- : option, handleRemove);
113
+ : option, handleRemove_1);
113
114
  }), _jsx(Tooltip, { title: remainingOptions
114
115
  .map(function (option) {
115
116
  return typeof option === "string" ? option : option.key;
116
117
  })
117
- .join(", "), children: _jsxs(Badge, { color: "light-blue", className: "cursor-help", children: ["+", remainingCount] }) })] }));
118
+ .join(", "), children: _jsxs(Badge, { color: "light-blue", children: ["+", remainingCount] }) })] }));
118
119
  }
119
120
  else {
120
121
  if (!singleValue)
@@ -126,7 +127,9 @@ var Combobox = function (props) {
126
127
  };
127
128
  var found = options.find(isMatch);
128
129
  return found
129
- ? renderBadge(typeof found === "string" ? { key: found, value: found } : found, handleRemove)
130
+ ? typeof found === "string"
131
+ ? found
132
+ : found.key
130
133
  : placeholder;
131
134
  }
132
135
  }, [
@@ -135,16 +138,17 @@ var Combobox = function (props) {
135
138
  isMulti,
136
139
  multiValue,
137
140
  singleValue,
141
+ selectedOptions,
138
142
  maxVisibleBadges,
139
143
  onSelect,
140
144
  setMultiValue,
141
145
  setSingleValue,
142
146
  ]);
143
147
  var normalizedOptions = useMemo(function () { return (Array.isArray(options) ? options : []); }, [options]);
144
- return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ref: buttonRef, variant: "outline", role: "combobox", color: "light-gray", "aria-expanded": open, className: cn("w-full justify-between !py-3 !px-4 font-normal !leading-normal hover:!bg-transparent active:!bg-transparent", comboboxSizes[size], comboboxSelectType[variant], comboboxColor[variant][color], open && comboboxColor[variant]["blue"], disabled && [
148
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ref: buttonRef, role: "combobox", "aria-expanded": open, className: cn("w-full justify-between border py-3! px-4! font-normal leading-normal! hover:bg-transparent active:bg-transparent text-gray-900!", comboboxSizes[size], comboboxSelectType[variant], comboboxColor[variant][color], open && comboboxColor[variant]["blue"], disabled && [
145
149
  variant === "fill" && "bg-gray-100",
146
150
  "border border-gray-300 cursor-not-allowed pointer-events-none",
147
- ], "min-h-[42px]"), shape: comboboxShapes[shape], disabled: disabled, tabIndex: disabled ? -1 : 0, children: [_jsx("div", { className: "flex-grow flex items-center", children: getDisplay }), _jsx(LUIcon, { icon: "angle-down", size: iconSizeMap[size], color: "light-gray" })] }) }), _jsx(PopoverContent, { className: "p-0", style: popoverWidth ? { width: popoverWidth } : {}, children: _jsxs(Command, { children: [isSearch && (_jsx(CommandInput, { placeholder: "Search", className: comboboxSizes[size] })), isMulti && normalizedOptions.length > 0 && (_jsxs("div", { className: "flex flex-col gap-1 !px-4 !py-3 rounded-sm bg-gray-50 text-gray-800", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { id: "select-all", checked: multiValue.length === normalizedOptions.length, onCheckedChange: handleSelectAll, size: size }), _jsx(Label, { variant: getLabelVariant(size), children: "Select All" })] }), _jsxs(Caption, { variant: "sm", className: "text-gray-500", children: ["Selected (", multiValue.length, ")"] })] })), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: empty_message }), _jsx(CommandGroup, { children: normalizedOptions.map(function (option) {
151
+ ], "min-h-[42px]"), shape: comboboxShapes[shape], disabled: disabled, tabIndex: disabled ? -1 : 0, children: [_jsx("div", { className: "flex min-w-0 grow items-center overflow-hidden", children: getDisplay }), _jsx(LUIcon, { icon: "angle-down", size: iconSizeMap[size], color: "light-gray", className: "shrink-0" })] }) }), _jsx(PopoverContent, { className: "p-0", style: popoverWidth ? { width: popoverWidth } : {}, children: _jsxs(Command, { children: [isSearch && (_jsx(CommandInput, { placeholder: "Search", className: comboboxSizes[size] })), isMulti && normalizedOptions.length > 0 && (_jsxs("div", { className: "flex flex-col gap-1 px-4! py-3! rounded-sm bg-gray-50 text-gray-800", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { id: "select-all", checked: multiValue.length === normalizedOptions.length, onCheckedChange: handleSelectAll, size: size }), _jsx(Label, { variant: getLabelVariant(size), children: "Select All" })] }), _jsxs(Caption, { variant: "sm", className: "text-gray-500", children: ["Selected (", multiValue.length, ")"] })] })), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: empty_message }), _jsx(CommandGroup, { children: normalizedOptions.map(function (option) {
148
152
  var normalizedOption = typeof option === "string"
149
153
  ? { key: option, value: option }
150
154
  : option;
@@ -10,4 +10,5 @@ export declare const ComboboxWithCheckbox: () => import("react/jsx-runtime").JSX
10
10
  export declare const ComboboxWithUserIcon: () => import("react/jsx-runtime").JSX.Element;
11
11
  export declare const ComboboxWithDefaultValue: () => import("react/jsx-runtime").JSX.Element;
12
12
  export declare const ListOfArray: () => import("react/jsx-runtime").JSX.Element;
13
+ export declare const MultiSelect: () => import("react/jsx-runtime").JSX.Element;
13
14
  export declare const ComboboxValidation: () => import("react/jsx-runtime").JSX.Element;
@@ -29,6 +29,26 @@ import { Caption } from "../../../components/Typography/Caption/caption";
29
29
  import { Button } from "../../../components/Button/Button/Button";
30
30
  import { Checkbox } from "../../../components/Checkbox/checkbox";
31
31
  import { Badge } from "../../../components/Badge/Badge";
32
+ import { Avatar, AvatarFallback } from "../../../components/Avatar/Avatar/Avatar";
33
+ var keyValueOptions = [
34
+ { key: "next.js", value: "Next.js" },
35
+ { key: "sveltekit", value: "SvelteKit" },
36
+ { key: "nest.js", value: "Nest.js" },
37
+ { key: "remix", value: "Remix" },
38
+ { key: "astro", value: "Astro" },
39
+ { key: "react", value: "React" },
40
+ { key: "nest", value: "Nest" },
41
+ { key: "python", value: "Python" },
42
+ { key: "ai", value: "AI" },
43
+ ];
44
+ var stringOptions = ["React", "Vue", "Angular", "Nest", "Next"];
45
+ var iconOptions = [
46
+ { key: "next.js", value: "Next.js", icon: "plus" },
47
+ { key: "sveltekit", value: "SvelteKit", icon: "star" },
48
+ { key: "nest.js", value: "Nest.js", icon: "check" },
49
+ { key: "remix", value: "Remix", icon: "minus" },
50
+ { key: "astro", value: "Astro", icon: "plus" },
51
+ ];
32
52
  export default {
33
53
  title: "Components/Dropdown/Combobox",
34
54
  component: Combobox,
@@ -139,52 +159,23 @@ Default.args = {
139
159
  size: "md",
140
160
  placeholder: "Select Options",
141
161
  shape: "rectangular",
142
- options: [
143
- { key: "next.js", value: "Next.js" },
144
- { key: "sveltekit", value: "SvelteKit" },
145
- { key: "nest.js", value: "Nest.js" },
146
- { key: "remix", value: "Remix" },
147
- { key: "astro", value: "Astro" },
148
- { key: "react", value: "React" },
149
- { key: "nest", value: "Nest" },
150
- { key: "python", value: "Python" },
151
- { key: "ai", value: "AI" },
152
- ],
162
+ options: keyValueOptions,
153
163
  isSearch: true,
154
164
  isMulti: true,
155
165
  renderOption: function (option) { return (_jsxs(_Fragment, { children: [option.icon && _jsx(LUIcon, { icon: option.icon, size: "md" }), _jsx("span", { children: option.key })] })); },
156
166
  onSelect: function (value) { return console.log(value); },
157
167
  };
158
- export var Basic = function () { return (_jsx(Combobox, { options: [
159
- { key: "React", value: "react" },
160
- { key: "Vue", value: "vue" },
161
- ], onSelect: function (value) { return console.log(value); } })); };
162
- export var ComboboxSize = function () { return (_jsxs("div", { className: "space-y-4", children: [_jsx(Combobox, { size: "sm", options: [
163
- { key: "React", value: "react" },
164
- { key: "Vue", value: "vue" },
165
- ], onSelect: function (value) { return console.log(value); } }), _jsx(Combobox, { size: "md", options: [
166
- { key: "React", value: "react" },
167
- { key: "Vue", value: "vue" },
168
- ], onSelect: function (value) { return console.log(value); } }), _jsx(Combobox, { size: "lg", options: [
169
- { key: "React", value: "react" },
170
- { key: "Vue", value: "vue" },
171
- ], onSelect: function (value) { return console.log(value); } })] })); };
172
- export var ComboboxType = function () { return (_jsxs("div", { className: "space-y-4", children: [_jsx(Label, { variant: "label-sm", children: "Text" }), _jsx(Combobox, { isMulti: true, options: ["React", "Vue", "Angular"], renderOption: function (option) { return _jsx("span", { children: option.value }); } }), _jsx(Label, { variant: "label-sm", children: "Text With Right Icon" }), _jsx(Combobox, { isMulti: true, options: ["React", "Vue", "Angular"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center justify-between w-full", children: [_jsx("span", { children: option.value }), _jsx(LUIcon, { icon: "plus" })] })); } }), _jsx(Label, { variant: "label-sm", children: "Text With Left Icon" }), _jsx(Combobox, { isMulti: true, options: [
173
- { key: "next.js", value: "Next.js", icon: "plus" },
174
- { key: "sveltekit", value: "SvelteKit", icon: "star" },
175
- { key: "nest.js", value: "Nest.js", icon: "check" },
176
- { key: "remix", value: "Remix", icon: "minus" },
177
- { key: "astro", value: "Astro", icon: "plus" },
178
- ], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: option.icon }), _jsx("span", { children: option.value })] })); } }), _jsx(Label, { variant: "label-sm", children: "Badge" }), _jsx(Combobox, { isMulti: true, options: ["React", "Vue", "Angular"], renderOption: function (option) { return (_jsx(Badge, { startIcon: "star", color: "light-blue", children: option.value })); } }), _jsx(Label, { variant: "label-sm", children: "Text+Counter" }), _jsx(Combobox, { isMulti: true, options: ["React", "Vue", "Angular"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center justify-between w-full", children: [_jsx("span", { children: option.value }), _jsx(Badge, { color: "light-blue", children: +3 })] })); } })] })); };
168
+ export var Basic = function () { return (_jsx(Combobox, { options: keyValueOptions.slice(0, 2), onSelect: function (value) { return console.log(value); } })); };
169
+ export var ComboboxSize = function () { return (_jsxs("div", { className: "space-y-4", children: [_jsx(Combobox, { size: "sm", options: keyValueOptions.slice(0, 2), onSelect: function (value) { return console.log(value); } }), _jsx(Combobox, { size: "md", options: keyValueOptions.slice(0, 2), onSelect: function (value) { return console.log(value); } }), _jsx(Combobox, { size: "lg", options: keyValueOptions.slice(0, 2), onSelect: function (value) { return console.log(value); } })] })); };
170
+ export var ComboboxType = function () { return (_jsxs("div", { className: "space-y-4", children: [_jsx(Label, { variant: "label-sm", children: "Text" }), _jsx(Combobox, { isMulti: true, options: stringOptions.slice(0, 3), renderOption: function (option) { return _jsx("span", { children: option.value }); } }), _jsx(Label, { variant: "label-sm", children: "Text With Right Icon" }), _jsx(Combobox, { isMulti: true, options: stringOptions.slice(0, 3), renderOption: function (option) { return (_jsxs("div", { className: "flex items-center justify-between w-full", children: [_jsx("span", { children: option.value }), _jsx(LUIcon, { icon: "plus" })] })); } }), _jsx(Label, { variant: "label-sm", children: "Text With Left Icon" }), _jsx(Combobox, { isMulti: true, options: iconOptions, renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: option.icon }), _jsx("span", { children: option.value })] })); } }), _jsx(Label, { variant: "label-sm", children: "Badge" }), _jsx(Combobox, { isMulti: true, options: stringOptions.slice(0, 3), renderOption: function (option) { return (_jsx(Badge, { startIcon: "star", color: "light-blue", children: option.value })); } }), _jsx(Label, { variant: "label-sm", children: "Text+Counter" }), _jsx(Combobox, { isMulti: true, options: stringOptions.slice(0, 3), renderOption: function (option) { return (_jsxs("div", { className: "flex items-center justify-between w-full", children: [_jsx("span", { children: option.value }), _jsx(Badge, { color: "light-blue", children: +3 })] })); } })] })); };
179
171
  export var ComboboxWithCheckbox = function () {
180
172
  var _a = useState([]), selected = _a[0], setSelected = _a[1];
181
- var options = ["React", "Vue", "Angular"];
182
173
  var onCheckChange = function (value) {
183
174
  setSelected(function (prev) {
184
175
  return prev.includes(value) ? prev.filter(function (v) { return v !== value; }) : __spreadArray(__spreadArray([], prev, true), [value], false);
185
176
  });
186
177
  };
187
- return (_jsx(Combobox, { isMulti: true, options: options, onSelect: function (value) {
178
+ return (_jsx(Combobox, { isMulti: true, options: stringOptions.slice(0, 3), onSelect: function (value) {
188
179
  if (Array.isArray(value)) {
189
180
  setSelected(value);
190
181
  }
@@ -192,9 +183,10 @@ export var ComboboxWithCheckbox = function () {
192
183
  onCheckChange(option.value);
193
184
  } }), _jsx("span", { children: option.value })] })); } }));
194
185
  };
195
- export var ComboboxWithUserIcon = function () { return (_jsx(Combobox, { isMulti: true, options: ["React", "Vue", "Angular", "Nest", "Next"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "user", variant: "padded" }), _jsx("span", { children: option.value })] })); } })); };
196
- export var ComboboxWithDefaultValue = function () { return (_jsxs("div", { className: "space-y-4", children: [_jsx(Label, { variant: "label-sm", children: "Multiple Default Values in Multiple Select" }), _jsx(Combobox, { isMulti: true, isSearch: true, options: ["React", "Vue", "Angular", "Nest", "Next"], defaultValue: ["React", "Vue"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } }), _jsx(Label, { variant: "label-sm", children: "Single Default Value in Multiple Select" }), _jsx(Combobox, { isMulti: true, isSearch: true, options: ["React", "Vue", "Angular", "Nest", "Next"], defaultValue: ["React"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } }), _jsx(Label, { variant: "label-sm", children: "Single Default Value in Single Select" }), _jsx(Combobox, { isSearch: true, options: ["React", "Vue", "Angular", "Nest", "Next"], defaultValue: "React", renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } })] })); };
186
+ export var ComboboxWithUserIcon = function () { return (_jsx(Combobox, { isMulti: true, options: stringOptions, renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(Avatar, { size: "xs", children: _jsx(AvatarFallback, { children: option.value.charAt(0) }) }), _jsx("span", { children: option.value })] })); } })); };
187
+ export var ComboboxWithDefaultValue = function () { return (_jsxs("div", { className: "space-y-4", children: [_jsx(Label, { variant: "label-sm", children: "Multiple Default Values in Multiple Select" }), _jsx(Combobox, { isMulti: true, isSearch: true, options: stringOptions, defaultValue: ["React", "Vue"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } }), _jsx(Label, { variant: "label-sm", children: "Single Default Value in Multiple Select" }), _jsx(Combobox, { isMulti: true, isSearch: true, options: stringOptions, defaultValue: ["React"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } }), _jsx(Label, { variant: "label-sm", children: "Single Default Value in Single Select" }), _jsx(Combobox, { isSearch: true, options: stringOptions, defaultValue: "React", renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } })] })); };
197
188
  export var ListOfArray = function () { return (_jsx(Combobox, { isMulti: true, isSearch: true, options: ["React", "Vue", "Angular", "Nest", "Next"], renderOption: function (option) { return (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx(LUIcon, { icon: "plus" }), _jsx("span", { children: option.value })] })); } })); };
189
+ export var MultiSelect = function () { return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(Label, { variant: "label-sm", className: "mb-2", children: "Multi Select" }), _jsx(Combobox, { isMulti: true, isSearch: true, placeholder: "Select frameworks...", options: keyValueOptions, onSelect: function (value) { return console.log("Multi:", value); } })] }), _jsxs("div", { children: [_jsx(Label, { variant: "label-sm", className: "mb-2", children: "Single Select" }), _jsx(Combobox, { isSearch: true, placeholder: "Select a framework...", options: keyValueOptions, onSelect: function (value) { return console.log("Single:", value); } })] })] })); };
198
190
  export var ComboboxValidation = function () {
199
191
  var _a = useState(""), selected = _a[0], setSelected = _a[1];
200
192
  var _b = useState(false), error = _b[0], setError = _b[1];
@@ -215,11 +207,5 @@ export var ComboboxValidation = function () {
215
207
  setError(false);
216
208
  }
217
209
  };
218
- return (_jsxs("form", { className: "space-y-4", onSubmit: handleSubmit, children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx(Label, { variant: "label-sm", children: "Select Category" }), _jsx("span", { className: "text-red-600", children: "*" }), _jsx(Tooltip, { title: "Select Option", children: _jsx(LUIcon, { variant: "padded", size: "xs", shape: "rounded", icon: "question", color: "light-blue" }) })] }), _jsxs("div", { children: [_jsx(Combobox, { placeholder: "Select framework...", size: "md", options: [
219
- { key: "next.js", value: "Next.js" },
220
- { key: "sveltekit", value: "SvelteKit" },
221
- { key: "nest.js", value: "Nest.js" },
222
- { key: "remix", value: "Remix" },
223
- { key: "astro", value: "Astro" },
224
- ], isSearch: true, onSelect: handleSelect, color: error ? "red" : "default", renderOption: function (option) { return _jsx("span", { children: option.value }); } }), error && (_jsx(Caption, { variant: "md", className: "mt-1 text-red-600", children: "field is required" }))] }), _jsx(Button, { type: "submit", children: "Submit" })] }));
210
+ return (_jsxs("form", { className: "space-y-4", onSubmit: handleSubmit, children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx(Label, { variant: "label-sm", children: "Select Category" }), _jsx("span", { className: "text-red-600", children: "*" }), _jsx(Tooltip, { title: "Select Option", children: _jsx(LUIcon, { variant: "padded", size: "xs", shape: "rounded", icon: "question", color: "light-blue" }) })] }), _jsxs("div", { children: [_jsx(Combobox, { placeholder: "Select framework...", size: "md", options: keyValueOptions.slice(0, 5), isSearch: true, onSelect: handleSelect, color: error ? "red" : "default", renderOption: function (option) { return _jsx("span", { children: option.value }); } }), error && (_jsx(Caption, { variant: "md", className: "mt-1 text-red-600", children: "field is required" }))] }), _jsx(Button, { type: "submit", children: "Submit" })] }));
225
211
  };
@@ -1 +1,2 @@
1
- export declare const useResponsiveBadges: () => number;
1
+ import { RefObject } from "react";
2
+ export declare const useResponsiveBadges: (containerRef: RefObject<HTMLElement | null>, labels: string[]) => number;
@@ -1,14 +1,81 @@
1
- import { useEffect, useState } from "react";
2
- export var useResponsiveBadges = function () {
3
- var _a = useState(3), maxVisibleBadges = _a[0], setMaxVisibleBadges = _a[1];
4
- useEffect(function () {
5
- var handleResize = function () {
6
- var width = window.innerWidth;
7
- setMaxVisibleBadges(width < 480 ? 1 : width < 640 ? 2 : width < 768 ? 3 : 4);
1
+ import { useEffect, useLayoutEffect, useState } from "react";
2
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
3
+ export var useResponsiveBadges = function (containerRef, labels) {
4
+ var _a = useState(1), maxVisible = _a[0], setMaxVisible = _a[1];
5
+ useIsomorphicLayoutEffect(function () {
6
+ var container = containerRef.current;
7
+ if (!container || labels.length === 0) {
8
+ setMaxVisible(labels.length || 1);
9
+ return;
10
+ }
11
+ var calculate = function () {
12
+ var _a;
13
+ var containerStyle = getComputedStyle(container);
14
+ var containerPadding = (parseFloat(containerStyle.paddingLeft) || 0) +
15
+ (parseFloat(containerStyle.paddingRight) || 0);
16
+ // Measure chevron icon from DOM (last child of button)
17
+ var chevronEl = container.querySelector(".shrink-0");
18
+ var chevronWidth = (_a = chevronEl === null || chevronEl === void 0 ? void 0 : chevronEl.offsetWidth) !== null && _a !== void 0 ? _a : 0;
19
+ // Read button's flex gap from computed style
20
+ var containerGap = parseFloat(containerStyle.gap) || 8;
21
+ var availableWidth = container.offsetWidth - containerPadding - chevronWidth - containerGap;
22
+ // Read badge gap from the flex container inside button
23
+ var badgeContainer = container.querySelector(".flex.flex-nowrap");
24
+ var badgeGap = badgeContainer
25
+ ? parseFloat(getComputedStyle(badgeContainer).gap) || 0
26
+ : 0;
27
+ // Measure text widths using canvas with actual font
28
+ var canvas = document.createElement("canvas");
29
+ var ctx = canvas.getContext("2d");
30
+ if (!ctx)
31
+ return;
32
+ ctx.font = containerStyle.font;
33
+ // Measure badge chrome (padding + close icon) from a rendered badge
34
+ var badgeChrome = 0;
35
+ var renderedBadge = container.querySelector('[data-slot="badge"]');
36
+ if (renderedBadge) {
37
+ var badgeText = renderedBadge.textContent || "";
38
+ var textWidth = ctx.measureText(badgeText.trim()).width;
39
+ badgeChrome = renderedBadge.offsetWidth - textWidth;
40
+ }
41
+ else {
42
+ // Fallback: derive from font size (covers padding + close icon + gaps)
43
+ var fontSize = parseFloat(containerStyle.fontSize) || 14;
44
+ badgeChrome = fontSize * 3;
45
+ }
46
+ // Measure counter badge width dynamically
47
+ var counterText = "+".concat(labels.length);
48
+ var counterWidth = Math.ceil(ctx.measureText(counterText).width) + badgeChrome;
49
+ var used = 0;
50
+ var count = 0;
51
+ for (var i = 0; i < labels.length; i++) {
52
+ var textWidth = Math.ceil(ctx.measureText(labels[i]).width);
53
+ var badgeWidth = textWidth + badgeChrome;
54
+ var gapWidth = i > 0 ? badgeGap : 0;
55
+ var remaining = labels.length - i - 1;
56
+ var counterSpace = remaining > 0 ? counterWidth + badgeGap : 0;
57
+ if (used + gapWidth + badgeWidth + counterSpace <= availableWidth) {
58
+ used += gapWidth + badgeWidth;
59
+ count++;
60
+ }
61
+ else {
62
+ break;
63
+ }
64
+ }
65
+ setMaxVisible(Math.max(1, count));
8
66
  };
9
- handleResize();
10
- window.addEventListener("resize", handleResize);
11
- return function () { return window.removeEventListener("resize", handleResize); };
12
- }, []);
13
- return maxVisibleBadges;
67
+ calculate();
68
+ var rafId;
69
+ var debouncedCalculate = function () {
70
+ cancelAnimationFrame(rafId);
71
+ rafId = requestAnimationFrame(calculate);
72
+ };
73
+ var observer = new ResizeObserver(debouncedCalculate);
74
+ observer.observe(container);
75
+ return function () {
76
+ cancelAnimationFrame(rafId);
77
+ observer.disconnect();
78
+ };
79
+ }, [containerRef, labels]);
80
+ return maxVisible;
14
81
  };
@@ -0,0 +1,74 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Popover } from "./popover";
3
+ declare const meta: Meta<typeof Popover>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ interface InteractiveArgs {
7
+ align: "start" | "center" | "end";
8
+ side: "top" | "right" | "bottom" | "left";
9
+ sideOffset: number;
10
+ triggerLabel: string;
11
+ title: string;
12
+ description: string;
13
+ }
14
+ /**
15
+ * Interactive playground to test different popover configurations.
16
+ * Use the Controls panel to customize alignment, side, offset, and content.
17
+ */
18
+ export declare const Interactive: StoryObj<InteractiveArgs>;
19
+ /**
20
+ * Default demo popover with a dimension settings form.
21
+ * Matches the standard shadcn/ui popover demo pattern with labeled input fields.
22
+ */
23
+ export declare const Default: Story;
24
+ /**
25
+ * Basic popover with a title and description.
26
+ * Demonstrates the simplest content structure.
27
+ */
28
+ export declare const Basic: Story;
29
+ /**
30
+ * Demonstrates the three horizontal alignment options for popover content:
31
+ * start, center, and end. Each aligns the popover differently relative
32
+ * to the trigger element.
33
+ */
34
+ export declare const Alignment: Story;
35
+ /**
36
+ * Popover containing a form with grouped input fields.
37
+ * Demonstrates the common pattern of inline editing within a popover.
38
+ */
39
+ export declare const Form: Story;
40
+ /**
41
+ * Demonstrates RTL (right-to-left) support for languages like Arabic and Hebrew.
42
+ * Uses the dir prop and side positioning for correct RTL layout.
43
+ */
44
+ export declare const RTLSupport: Story;
45
+ /**
46
+ * Demonstrates all four side positions for the popover:
47
+ * top, right, bottom, and left.
48
+ */
49
+ export declare const SidePositions: Story;
50
+ /**
51
+ * Demonstrates using PopoverAnchor to position the popover relative
52
+ * to a different element than the trigger.
53
+ */
54
+ export declare const WithAnchor: Story;
55
+ /**
56
+ * Notification popover showing a list of recent notifications.
57
+ */
58
+ export declare const NotificationList: Story;
59
+ /**
60
+ * User profile popover showing account details and actions.
61
+ */
62
+ export declare const UserProfileCard: Story;
63
+ /**
64
+ * Popover with a large amount of text content to test overflow and scrolling behavior.
65
+ */
66
+ export declare const LongContent: Story;
67
+ /**
68
+ * Popover with minimal content to verify it renders correctly with little data.
69
+ */
70
+ export declare const MinimalContent: Story;
71
+ /**
72
+ * Popover in a default open state, useful for testing and documentation screenshots.
73
+ */
74
+ export declare const DefaultOpen: Story;
@@ -0,0 +1,183 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, } from "./popover";
3
+ import { Button } from "../Button/Button/Button";
4
+ import { Input } from "../Input/input";
5
+ import { Label } from "../Label/Label";
6
+ import { Heading } from "../Typography/Heading/heading";
7
+ import { Body } from "../Typography/Body/body";
8
+ // Reusable className constants for PopoverContent styling
9
+ var POPOVER_BASE_CLASSES = "rounded-md border bg-white shadow-md";
10
+ var POPOVER_WIDE = "w-80 ".concat(POPOVER_BASE_CLASSES, " p-4"); // 320px width
11
+ var POPOVER_MEDIUM = "w-64 ".concat(POPOVER_BASE_CLASSES, " p-4"); // 256px width
12
+ var POPOVER_NARROW = "w-48 ".concat(POPOVER_BASE_CLASSES, " p-3"); // 192px width
13
+ var POPOVER_LARGE = "w-72 ".concat(POPOVER_BASE_CLASSES, " p-4"); // 288px width
14
+ var POPOVER_WIDE_NO_PADDING = "w-80 ".concat(POPOVER_BASE_CLASSES, " p-0");
15
+ var POPOVER_WIDE_SCROLLABLE = "w-80 max-h-64 overflow-y-auto ".concat(POPOVER_BASE_CLASSES, " p-4");
16
+ var POPOVER_MINIMAL = "".concat(POPOVER_BASE_CLASSES, " px-3 py-2");
17
+ var meta = {
18
+ title: "Components/Popover",
19
+ component: Popover,
20
+ tags: ["autodocs"],
21
+ parameters: {
22
+ layout: "centered",
23
+ docs: {
24
+ description: {
25
+ component: "A floating panel that appears when a trigger element is clicked. Built on Radix UI Popover primitives with animated enter/exit transitions.",
26
+ },
27
+ },
28
+ },
29
+ decorators: [
30
+ function (Story) { return (_jsx("div", { className: "flex items-center justify-center min-h-[300px]", children: _jsx(Story, {}) })); },
31
+ ],
32
+ };
33
+ export default meta;
34
+ /**
35
+ * Interactive playground to test different popover configurations.
36
+ * Use the Controls panel to customize alignment, side, offset, and content.
37
+ */
38
+ export var Interactive = {
39
+ args: {
40
+ align: "center",
41
+ side: "bottom",
42
+ sideOffset: 4,
43
+ triggerLabel: "Open Popover",
44
+ title: "Popover Title",
45
+ description: "This is a popover with customizable placement and content.",
46
+ },
47
+ argTypes: {
48
+ align: {
49
+ control: "select",
50
+ options: ["start", "center", "end"],
51
+ description: "Horizontal alignment relative to the trigger",
52
+ },
53
+ side: {
54
+ control: "select",
55
+ options: ["top", "right", "bottom", "left"],
56
+ description: "Which side of the trigger the popover appears on",
57
+ },
58
+ sideOffset: {
59
+ control: { type: "number", min: 0, max: 24 },
60
+ description: "Distance in pixels between the trigger and the popover",
61
+ },
62
+ triggerLabel: {
63
+ control: "text",
64
+ description: "Text for the trigger button",
65
+ },
66
+ title: {
67
+ control: "text",
68
+ description: "The popover title text",
69
+ },
70
+ description: {
71
+ control: "text",
72
+ description: "The popover description text",
73
+ },
74
+ },
75
+ render: function (args) { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: args.triggerLabel }) }), _jsx(PopoverContent, { align: args.align, side: args.side, sideOffset: args.sideOffset, className: POPOVER_WIDE, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: args.title }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: args.description })] }) })] })); },
76
+ };
77
+ // ============================================================================
78
+ // DEMO (DEFAULT) - Dimension form matching shadcn reference
79
+ // ============================================================================
80
+ /**
81
+ * Default demo popover with a dimension settings form.
82
+ * Matches the standard shadcn/ui popover demo pattern with labeled input fields.
83
+ */
84
+ export var Default = {
85
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Popover" }) }), _jsx(PopoverContent, { className: POPOVER_WIDE, children: _jsxs("div", { className: "grid gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Dimensions" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "Set the dimensions for the layer." })] }), _jsxs("div", { className: "grid gap-2", children: [_jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Width" }), _jsx(Input, { defaultValue: "100%", className: "col-span-2 h-8" })] }), _jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Max Width" }), _jsx(Input, { defaultValue: "300px", className: "col-span-2 h-8" })] }), _jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Height" }), _jsx(Input, { defaultValue: "25px", className: "col-span-2 h-8" })] }), _jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Max Height" }), _jsx(Input, { defaultValue: "none", className: "col-span-2 h-8" })] })] })] }) })] })); },
86
+ };
87
+ // ============================================================================
88
+ // BASIC - Simple popover with title and description
89
+ // ============================================================================
90
+ /**
91
+ * Basic popover with a title and description.
92
+ * Demonstrates the simplest content structure.
93
+ */
94
+ export var Basic = {
95
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Popover" }) }), _jsx(PopoverContent, { className: POPOVER_WIDE, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Popover Title" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "This is a basic popover with a title and description. Use it to display additional context or information." })] }) })] })); },
96
+ };
97
+ // ============================================================================
98
+ // ALIGNMENT - All three alignment variants shown together
99
+ // ============================================================================
100
+ /**
101
+ * Demonstrates the three horizontal alignment options for popover content:
102
+ * start, center, and end. Each aligns the popover differently relative
103
+ * to the trigger element.
104
+ */
105
+ export var Alignment = {
106
+ render: function () { return (_jsxs("div", { className: "flex items-end gap-8", children: [_jsx("div", { className: "flex flex-col items-center gap-2", children: _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Align Start" }) }), _jsx(PopoverContent, { align: "start", className: POPOVER_MEDIUM, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Start Aligned" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "The popover content is aligned to the start edge of the trigger." })] }) })] }) }), _jsx("div", { className: "flex flex-col items-center gap-2", children: _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Align Center" }) }), _jsx(PopoverContent, { align: "center", className: POPOVER_MEDIUM, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Center Aligned" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "The popover content is centered relative to the trigger." })] }) })] }) }), _jsx("div", { className: "flex flex-col items-center gap-2", children: _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Align End" }) }), _jsx(PopoverContent, { align: "end", className: POPOVER_MEDIUM, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "End Aligned" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "The popover content is aligned to the end edge of the trigger." })] }) })] }) })] })); },
107
+ };
108
+ // ============================================================================
109
+ // FORM - Popover with form fields
110
+ // ============================================================================
111
+ /**
112
+ * Popover containing a form with grouped input fields.
113
+ * Demonstrates the common pattern of inline editing within a popover.
114
+ */
115
+ export var Form = {
116
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Edit Profile" }) }), _jsx(PopoverContent, { className: POPOVER_WIDE, children: _jsxs("div", { className: "grid gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Edit Profile" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "Update your display name and email address." })] }), _jsxs("div", { className: "grid gap-3", children: [_jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Name" }), _jsx(Input, { defaultValue: "John Doe", className: "col-span-2 h-8" })] }), _jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Email" }), _jsx(Input, { defaultValue: "john@example.com", className: "col-span-2 h-8" })] }), _jsxs("div", { className: "grid grid-cols-3 items-center gap-4", children: [_jsx(Label, { children: "Phone" }), _jsx(Input, { defaultValue: "555-0123", className: "col-span-2 h-8" })] })] }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", children: "Cancel" }), _jsx(Button, { size: "sm", children: "Save" })] })] }) })] })); },
117
+ };
118
+ // ============================================================================
119
+ // RTL SUPPORT - Right-to-left layout
120
+ // ============================================================================
121
+ /**
122
+ * Demonstrates RTL (right-to-left) support for languages like Arabic and Hebrew.
123
+ * Uses the dir prop and side positioning for correct RTL layout.
124
+ */
125
+ export var RTLSupport = {
126
+ render: function () { return (_jsxs("div", { className: "flex gap-8", children: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "English (LTR)" }) }), _jsx(PopoverContent, { side: "bottom", align: "start", className: POPOVER_MEDIUM, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Settings" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "Manage your account settings and preferences." })] }) })] }), _jsx("div", { dir: "rtl", children: _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "RTL Layout" }) }), _jsx(PopoverContent, { side: "bottom", align: "start", className: POPOVER_MEDIUM, children: _jsxs("div", { className: "space-y-2 text-right", children: [_jsx(Heading, { variant: "h4-500", children: "Settings" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "This popover renders with right-to-left text direction and alignment." })] }) })] }) })] })); },
127
+ };
128
+ // ============================================================================
129
+ // SIDE VARIANTS
130
+ // ============================================================================
131
+ /**
132
+ * Demonstrates all four side positions for the popover:
133
+ * top, right, bottom, and left.
134
+ */
135
+ export var SidePositions = {
136
+ render: function () { return (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Top" }) }), _jsx(PopoverContent, { side: "top", className: POPOVER_NARROW, children: _jsx(Body, { variant: "body-sm", className: "text-gray-600", children: "Appears above the trigger." }) })] }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Right" }) }), _jsx(PopoverContent, { side: "right", className: POPOVER_NARROW, children: _jsx(Body, { variant: "body-sm", className: "text-gray-600", children: "Appears to the right." }) })] }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Bottom" }) }), _jsx(PopoverContent, { side: "bottom", className: POPOVER_NARROW, children: _jsx(Body, { variant: "body-sm", className: "text-gray-600", children: "Appears below the trigger." }) })] }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Left" }) }), _jsx(PopoverContent, { side: "left", className: POPOVER_NARROW, children: _jsx(Body, { variant: "body-sm", className: "text-gray-600", children: "Appears to the left." }) })] })] })); },
137
+ };
138
+ // ============================================================================
139
+ // POPOVER ANCHOR
140
+ // ============================================================================
141
+ /**
142
+ * Demonstrates using PopoverAnchor to position the popover relative
143
+ * to a different element than the trigger.
144
+ */
145
+ export var WithAnchor = {
146
+ render: function () { return (_jsxs(Popover, { children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsx(PopoverAnchor, { asChild: true, children: _jsx(Input, { placeholder: "Anchored here...", className: "w-48" }) }), _jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", size: "sm", children: "Open" }) })] }), _jsx(PopoverContent, { className: POPOVER_MEDIUM, children: _jsx(Body, { variant: "body-sm", className: "text-gray-600", children: "This popover is anchored to the input field rather than the trigger button. The content appears relative to the anchor element." }) })] })); },
147
+ };
148
+ // ============================================================================
149
+ // REAL-WORLD USE CASES
150
+ // ============================================================================
151
+ /**
152
+ * Notification popover showing a list of recent notifications.
153
+ */
154
+ export var NotificationList = {
155
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Notifications (3)" }) }), _jsxs(PopoverContent, { className: POPOVER_WIDE_NO_PADDING, children: [_jsx("div", { className: "p-4 border-b", children: _jsx(Heading, { variant: "h4-500", children: "Notifications" }) }), _jsxs("div", { className: "divide-y", children: [_jsxs("div", { className: "p-3 hover:bg-gray-50", children: [_jsx(Body, { variant: "body-sm-500", children: "Meeting Reminder" }), _jsx(Body, { variant: "body-xs", className: "text-gray-500", children: "Monthly union meeting starts in 30 minutes." }), _jsx(Body, { variant: "body-xs", className: "text-gray-400 mt-1", children: "5 min ago" })] }), _jsxs("div", { className: "p-3 hover:bg-gray-50", children: [_jsx(Body, { variant: "body-sm-500", children: "Dues Payment Received" }), _jsx(Body, { variant: "body-xs", className: "text-gray-500", children: "Your quarterly dues payment has been processed successfully." }), _jsx(Body, { variant: "body-xs", className: "text-gray-400 mt-1", children: "1 hour ago" })] }), _jsxs("div", { className: "p-3 hover:bg-gray-50", children: [_jsx(Body, { variant: "body-sm-500", children: "New Announcement" }), _jsx(Body, { variant: "body-xs", className: "text-gray-500", children: "Contract negotiations update from leadership." }), _jsx(Body, { variant: "body-xs", className: "text-gray-400 mt-1", children: "3 hours ago" })] })] }), _jsx("div", { className: "p-3 border-t text-center", children: _jsx(Button, { variant: "link", size: "sm", children: "View All Notifications" }) })] })] })); },
156
+ };
157
+ /**
158
+ * User profile popover showing account details and actions.
159
+ */
160
+ export var UserProfileCard = {
161
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "sm", children: "John Doe" }) }), _jsx(PopoverContent, { className: POPOVER_LARGE, children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Heading, { variant: "h6-600", children: "John Doe" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "john.doe@union-local-123.org" })] }), _jsxs("div", { className: "border-t pt-3 space-y-1", children: [_jsx(Body, { variant: "body-xs", className: "text-gray-400", children: "Role: Union Member" }), _jsx(Body, { variant: "body-xs", className: "text-gray-400", children: "Local: 123 - Iron Workers" }), _jsx(Body, { variant: "body-xs", className: "text-gray-400", children: "Member since: January 2022" })] }), _jsxs("div", { className: "flex gap-2 border-t pt-3", children: [_jsx(Button, { variant: "outline", size: "sm", className: "flex-1", children: "Profile" }), _jsx(Button, { variant: "outline", size: "sm", className: "flex-1", children: "Sign Out" })] })] }) })] })); },
162
+ };
163
+ // ============================================================================
164
+ // EDGE CASES
165
+ // ============================================================================
166
+ /**
167
+ * Popover with a large amount of text content to test overflow and scrolling behavior.
168
+ */
169
+ export var LongContent = {
170
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Long Content" }) }), _jsx(PopoverContent, { className: POPOVER_WIDE_SCROLLABLE, children: _jsxs("div", { className: "space-y-3", children: [_jsx(Heading, { variant: "h4-500", children: "Detailed Information" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "This popover contains a significant amount of text to demonstrate how the component handles overflow. When the content exceeds the maximum height, vertical scrolling is enabled so users can access all the information without the popover growing too large." }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "Union members can access their full benefits package details through this interface. The benefits include healthcare coverage, retirement planning resources, training program access, and legal representation services." }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "For questions about specific benefits or coverage details, members should contact their union representative directly. Representatives are available during business hours and can provide personalized guidance on all benefit-related topics." }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "Additional resources and documentation are available in the member portal. You can find frequently asked questions, downloadable forms, and contact information for each department." })] }) })] })); },
171
+ };
172
+ /**
173
+ * Popover with minimal content to verify it renders correctly with little data.
174
+ */
175
+ export var MinimalContent = {
176
+ render: function () { return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Info" }) }), _jsx(PopoverContent, { className: POPOVER_MINIMAL, children: _jsx(Body, { variant: "body-sm", children: "Done." }) })] })); },
177
+ };
178
+ /**
179
+ * Popover in a default open state, useful for testing and documentation screenshots.
180
+ */
181
+ export var DefaultOpen = {
182
+ render: function () { return (_jsxs(Popover, { defaultOpen: true, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Already Open" }) }), _jsx(PopoverContent, { className: POPOVER_WIDE, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Heading, { variant: "h4-500", children: "Open by Default" }), _jsx(Body, { variant: "body-sm", className: "text-gray-500", children: "This popover starts in the open state by default." })] }) })] })); },
183
+ };
@@ -0,0 +1 @@
1
+ export * from "./popover";
@@ -0,0 +1 @@
1
+ export * from "./popover";
@@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) {
23
23
  };
24
24
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
25
25
  import { cn } from "../../lib/utils";
26
- import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
26
+ import { Popover, PopoverContent, PopoverTrigger } from "../Popover/popover";
27
27
  import LUIcon from "../Icons/LUIcon";
28
28
  import { getIconSize, getPadding, getIconPosition } from "../Input";
29
29
  import { Button } from "../Button/Button/Button";
@@ -349,6 +349,9 @@
349
349
  .order-last {
350
350
  order: 9999;
351
351
  }
352
+ .col-span-2 {
353
+ grid-column: span 2 / span 2;
354
+ }
352
355
  .container {
353
356
  width: 100%;
354
357
  @media (width >= 480px) {
@@ -781,6 +784,9 @@
781
784
  .min-h-\[42px\] {
782
785
  min-height: 42px;
783
786
  }
787
+ .min-h-\[300px\] {
788
+ min-height: 300px;
789
+ }
784
790
  .min-h-screen {
785
791
  min-height: 100vh;
786
792
  }
@@ -883,6 +889,9 @@
883
889
  .w-64 {
884
890
  width: calc(var(--spacing) * 64);
885
891
  }
892
+ .w-72 {
893
+ width: calc(var(--spacing) * 72);
894
+ }
886
895
  .w-80 {
887
896
  width: calc(var(--spacing) * 80);
888
897
  }
@@ -1049,9 +1058,6 @@
1049
1058
  .cursor-default {
1050
1059
  cursor: default;
1051
1060
  }
1052
- .cursor-help {
1053
- cursor: help;
1054
- }
1055
1061
  .cursor-not-allowed {
1056
1062
  cursor: not-allowed;
1057
1063
  }
@@ -1100,6 +1106,9 @@
1100
1106
  .flex-row-reverse {
1101
1107
  flex-direction: row-reverse;
1102
1108
  }
1109
+ .flex-nowrap {
1110
+ flex-wrap: nowrap;
1111
+ }
1103
1112
  .flex-wrap {
1104
1113
  flex-wrap: wrap;
1105
1114
  }
@@ -1109,6 +1118,9 @@
1109
1118
  .items-center {
1110
1119
  align-items: center;
1111
1120
  }
1121
+ .items-end {
1122
+ align-items: flex-end;
1123
+ }
1112
1124
  .items-start {
1113
1125
  align-items: flex-start;
1114
1126
  }
@@ -1183,6 +1195,13 @@
1183
1195
  margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
1184
1196
  }
1185
1197
  }
1198
+ .space-y-3 {
1199
+ :where(& > :not(:last-child)) {
1200
+ --tw-space-y-reverse: 0;
1201
+ margin-block-start: calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));
1202
+ margin-block-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)));
1203
+ }
1204
+ }
1186
1205
  .space-y-4 {
1187
1206
  :where(& > :not(:last-child)) {
1188
1207
  --tw-space-y-reverse: 0;
@@ -1232,6 +1251,15 @@
1232
1251
  margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse)));
1233
1252
  }
1234
1253
  }
1254
+ .divide-y {
1255
+ :where(& > :not(:last-child)) {
1256
+ --tw-divide-y-reverse: 0;
1257
+ border-bottom-style: var(--tw-border-style);
1258
+ border-top-style: var(--tw-border-style);
1259
+ border-top-width: calc(1px * var(--tw-divide-y-reverse));
1260
+ border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
1261
+ }
1262
+ }
1235
1263
  .truncate {
1236
1264
  overflow: hidden;
1237
1265
  text-overflow: ellipsis;
@@ -1841,6 +1869,9 @@
1841
1869
  .px-4 {
1842
1870
  padding-inline: calc(var(--spacing) * 4);
1843
1871
  }
1872
+ .px-4\! {
1873
+ padding-inline: calc(var(--spacing) * 4) !important;
1874
+ }
1844
1875
  .px-9 {
1845
1876
  padding-inline: calc(var(--spacing) * 9);
1846
1877
  }
@@ -1886,6 +1917,9 @@
1886
1917
  .py-3 {
1887
1918
  padding-block: calc(var(--spacing) * 3);
1888
1919
  }
1920
+ .py-3\! {
1921
+ padding-block: calc(var(--spacing) * 3) !important;
1922
+ }
1889
1923
  .py-6 {
1890
1924
  padding-block: calc(var(--spacing) * 6);
1891
1925
  }
@@ -1907,6 +1941,9 @@
1907
1941
  .\!pt-4 {
1908
1942
  padding-top: calc(var(--spacing) * 4) !important;
1909
1943
  }
1944
+ .pt-3 {
1945
+ padding-top: calc(var(--spacing) * 3);
1946
+ }
1910
1947
  .\!pr-2 {
1911
1948
  padding-right: calc(var(--spacing) * 2) !important;
1912
1949
  }
@@ -1958,6 +1995,9 @@
1958
1995
  .text-left {
1959
1996
  text-align: left;
1960
1997
  }
1998
+ .text-right {
1999
+ text-align: right;
2000
+ }
1961
2001
  .text-start {
1962
2002
  text-align: start;
1963
2003
  }
@@ -2069,6 +2109,10 @@
2069
2109
  --tw-leading: var(--leading-normal);
2070
2110
  line-height: var(--leading-normal);
2071
2111
  }
2112
+ .leading-normal\! {
2113
+ --tw-leading: var(--leading-normal) !important;
2114
+ line-height: var(--leading-normal) !important;
2115
+ }
2072
2116
  .\!font-normal {
2073
2117
  --tw-font-weight: var(--font-weight-normal) !important;
2074
2118
  font-weight: var(--font-weight-normal) !important;
@@ -2197,6 +2241,9 @@
2197
2241
  .text-gray-900 {
2198
2242
  color: #2B2C2E;
2199
2243
  }
2244
+ .text-gray-900\! {
2245
+ color: #2B2C2E !important;
2246
+ }
2200
2247
  .text-gray-950 {
2201
2248
  color: #18191A;
2202
2249
  }
@@ -3217,6 +3264,13 @@
3217
3264
  }
3218
3265
  }
3219
3266
  }
3267
+ .hover\:bg-transparent {
3268
+ &:hover {
3269
+ @media (hover: hover) {
3270
+ background-color: transparent;
3271
+ }
3272
+ }
3273
+ }
3220
3274
  .hover\:bg-yellow-50 {
3221
3275
  &:hover {
3222
3276
  @media (hover: hover) {
@@ -4038,6 +4092,11 @@
4038
4092
  background-color: #73030e;
4039
4093
  }
4040
4094
  }
4095
+ .active\:bg-transparent {
4096
+ &:active {
4097
+ background-color: transparent;
4098
+ }
4099
+ }
4041
4100
  .active\:bg-yellow-500 {
4042
4101
  &:active {
4043
4102
  background-color: #ffd333;
@@ -5519,6 +5578,11 @@
5519
5578
  inherits: false;
5520
5579
  initial-value: 0;
5521
5580
  }
5581
+ @property --tw-divide-y-reverse {
5582
+ syntax: "*";
5583
+ inherits: false;
5584
+ initial-value: 0;
5585
+ }
5522
5586
  @property --tw-border-style {
5523
5587
  syntax: "*";
5524
5588
  inherits: false;
@@ -5760,6 +5824,7 @@
5760
5824
  --tw-skew-y: initial;
5761
5825
  --tw-space-y-reverse: 0;
5762
5826
  --tw-space-x-reverse: 0;
5827
+ --tw-divide-y-reverse: 0;
5763
5828
  --tw-border-style: solid;
5764
5829
  --tw-gradient-position: initial;
5765
5830
  --tw-gradient-from: #0000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkedunion-design-kit",
3
- "version": "1.11.9",
3
+ "version": "1.11.11",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -122,6 +122,7 @@
122
122
  "storybook": "^8.6.15",
123
123
  "tailwindcss": "^4.1.3",
124
124
  "ts-node": "^10.9.2",
125
- "typescript": "^5"
125
+ "typescript": "^5",
126
+ "webpack": "5.99.9"
126
127
  }
127
128
  }
File without changes