@rovula/ui 0.1.21 → 0.1.22

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.
Files changed (80) hide show
  1. package/dist/cjs/bundle.css +175 -26
  2. package/dist/cjs/bundle.js +675 -675
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Badge/Badge.d.ts +40 -0
  5. package/dist/cjs/types/components/Badge/Badge.stories.d.ts +295 -0
  6. package/dist/cjs/types/components/Badge/Badge.styles.d.ts +7 -0
  7. package/dist/cjs/types/components/Badge/index.d.ts +2 -0
  8. package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +4 -8
  9. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +1 -6
  10. package/dist/cjs/types/components/DropdownMenu/DropdownMenu.d.ts +5 -1
  11. package/dist/cjs/types/components/DropdownMenu/DropdownMenu.stories.d.ts +16 -0
  12. package/dist/cjs/types/index.d.ts +3 -1
  13. package/dist/cjs/types/patterns/menu/Menu.d.ts +70 -0
  14. package/dist/cjs/types/{components/Menu → patterns/menu}/Menu.stories.d.ts +17 -10
  15. package/dist/cjs/types/utils/mergeRefs.d.ts +20 -0
  16. package/dist/components/Avatar/Avatar.styles.js +2 -2
  17. package/dist/components/Badge/Badge.js +36 -0
  18. package/dist/components/Badge/Badge.stories.js +51 -0
  19. package/dist/components/Badge/Badge.styles.js +62 -0
  20. package/dist/components/Badge/index.js +2 -0
  21. package/dist/components/Dropdown/Dropdown.js +54 -163
  22. package/dist/components/Dropdown/Dropdown.stories.js +29 -0
  23. package/dist/components/DropdownMenu/DropdownMenu.js +22 -9
  24. package/dist/components/DropdownMenu/DropdownMenu.stories.js +54 -10
  25. package/dist/components/TextInput/TextInput.js +6 -3
  26. package/dist/esm/bundle.css +175 -26
  27. package/dist/esm/bundle.js +1545 -1545
  28. package/dist/esm/bundle.js.map +1 -1
  29. package/dist/esm/types/components/Badge/Badge.d.ts +40 -0
  30. package/dist/esm/types/components/Badge/Badge.stories.d.ts +295 -0
  31. package/dist/esm/types/components/Badge/Badge.styles.d.ts +7 -0
  32. package/dist/esm/types/components/Badge/index.d.ts +2 -0
  33. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +4 -8
  34. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +1 -6
  35. package/dist/esm/types/components/DropdownMenu/DropdownMenu.d.ts +5 -1
  36. package/dist/esm/types/components/DropdownMenu/DropdownMenu.stories.d.ts +16 -0
  37. package/dist/esm/types/index.d.ts +3 -1
  38. package/dist/esm/types/patterns/menu/Menu.d.ts +70 -0
  39. package/dist/esm/types/{components/Menu → patterns/menu}/Menu.stories.d.ts +17 -10
  40. package/dist/esm/types/utils/mergeRefs.d.ts +20 -0
  41. package/dist/index.d.ts +116 -73
  42. package/dist/index.js +2 -1
  43. package/dist/patterns/menu/Menu.js +95 -0
  44. package/dist/patterns/menu/Menu.stories.js +611 -0
  45. package/dist/src/theme/global.css +289 -37
  46. package/dist/utils/mergeRefs.js +42 -0
  47. package/package.json +1 -1
  48. package/src/components/Avatar/Avatar.styles.ts +2 -2
  49. package/src/components/Badge/Badge.stories.tsx +128 -0
  50. package/src/components/Badge/Badge.styles.ts +70 -0
  51. package/src/components/Badge/Badge.tsx +103 -0
  52. package/src/components/Badge/index.ts +3 -0
  53. package/src/components/Dropdown/Dropdown.stories.tsx +170 -1
  54. package/src/components/Dropdown/Dropdown.tsx +186 -276
  55. package/src/components/DropdownMenu/DropdownMenu.stories.tsx +1050 -113
  56. package/src/components/DropdownMenu/DropdownMenu.tsx +116 -52
  57. package/src/components/TextInput/TextInput.tsx +6 -3
  58. package/src/index.ts +3 -1
  59. package/src/patterns/menu/Menu.stories.tsx +1100 -0
  60. package/src/patterns/menu/Menu.tsx +282 -0
  61. package/src/theme/themes/xspector/baseline.css +0 -1
  62. package/src/theme/tokens/baseline.css +2 -1
  63. package/src/theme/tokens/components/badge.css +54 -0
  64. package/src/theme/tokens/components/dropdown-menu.css +15 -4
  65. package/src/utils/mergeRefs.ts +46 -0
  66. package/dist/cjs/types/components/Menu/Menu.d.ts +0 -65
  67. package/dist/cjs/types/components/Menu/helpers.d.ts +0 -19
  68. package/dist/cjs/types/components/Menu/index.d.ts +0 -4
  69. package/dist/components/Menu/Menu.js +0 -64
  70. package/dist/components/Menu/Menu.stories.js +0 -406
  71. package/dist/components/Menu/helpers.js +0 -28
  72. package/dist/components/Menu/index.js +0 -3
  73. package/dist/esm/types/components/Menu/Menu.d.ts +0 -65
  74. package/dist/esm/types/components/Menu/helpers.d.ts +0 -19
  75. package/dist/esm/types/components/Menu/index.d.ts +0 -4
  76. package/src/components/Menu/Menu.stories.tsx +0 -586
  77. package/src/components/Menu/Menu.tsx +0 -235
  78. package/src/components/Menu/helpers.ts +0 -45
  79. package/src/components/Menu/index.ts +0 -7
  80. package/src/theme/themes/xspector/components/dropdown-menu.css +0 -28
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ /**
3
+ * Merges multiple refs into a single callback ref.
4
+ * NOTE: This creates a new function on every call — do NOT use inline in render.
5
+ * Use `useStableMergedRef` instead when you need a stable ref identity.
6
+ */
7
+ export declare function mergeRefs<T>(...refs: (React.Ref<T> | undefined | null)[]): React.RefCallback<T>;
8
+ /**
9
+ * Returns a **stable** callback ref (never changes identity) that forwards the
10
+ * node to all given refs. Safe to use inline in JSX — will not cause
11
+ * detach/re-attach loops in libraries like Headless UI that watch refs.
12
+ *
13
+ * @example
14
+ * const MyInput = forwardRef((props, ref) => {
15
+ * const internalRef = useRef(null);
16
+ * const stableRef = useStableMergedRef(ref, internalRef);
17
+ * return <input ref={stableRef} />;
18
+ * });
19
+ */
20
+ export declare function useStableMergedRef<T>(...refs: (React.Ref<T> | undefined | null)[]): React.RefCallback<T>;
@@ -1,10 +1,10 @@
1
1
  import { cva } from "class-variance-authority";
2
2
  export const avatarVariants = cva([
3
- "flex items-center justify-center bg-grey2-700 text-common-black typography-subtitle2 truncate",
3
+ "flex items-center justify-center bg-grey2-900 text-text-white typography-subtitle6 truncate",
4
4
  ], {
5
5
  variants: {
6
6
  size: {
7
- xxs: "w-[24px] h-[24px] typography-subtitle3",
7
+ xxs: "w-[24px] h-[24px] typography-small3",
8
8
  xs: "w-[32px] h-[32px]",
9
9
  sm: "w-[40px] h-[40px]",
10
10
  md: "w-[48px] h-[48px]",
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
+ import * as React from "react";
15
+ import { ChevronDownIcon } from "@heroicons/react/16/solid";
16
+ import { cn } from "@/utils/cn";
17
+ import { badgeVariants, severityBadgeVariants } from "./Badge.styles";
18
+ const Badge = React.forwardRef((_a, ref) => {
19
+ var { label, color = "default", clickable = false, percent, className } = _a, props = __rest(_a, ["label", "color", "clickable", "percent", "className"]);
20
+ const hasPercent = percent !== undefined;
21
+ return (_jsxs("span", Object.assign({ ref: ref, className: cn(badgeVariants({ color, clickable }), hasPercent && "flex-col gap-0.5", clickable && "cursor-pointer gap-1", className) }, props, { children: [_jsxs("span", { className: "flex items-center gap-1", children: [label, clickable && (_jsx(ChevronDownIcon, { className: "size-4 shrink-0", "aria-hidden": true }))] }), hasPercent && (_jsxs("span", { className: "tabular-nums", children: [percent, "%"] }))] })));
22
+ });
23
+ Badge.displayName = "Badge";
24
+ const SEVERITY_LABELS = {
25
+ highest: "Highest",
26
+ high: "High",
27
+ medium: "Medium",
28
+ low: "Low",
29
+ lowest: "Lowest",
30
+ };
31
+ const SeverityBadge = React.forwardRef((_a, ref) => {
32
+ var { severity, className } = _a, props = __rest(_a, ["severity", "className"]);
33
+ return (_jsx("span", Object.assign({ ref: ref, className: cn(severityBadgeVariants({ severity }), className) }, props, { children: SEVERITY_LABELS[severity] })));
34
+ });
35
+ SeverityBadge.displayName = "SeverityBadge";
36
+ export { Badge, SeverityBadge };
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Badge, SeverityBadge } from "./Badge";
3
+ const meta = {
4
+ title: "Components/Badge",
5
+ component: Badge,
6
+ tags: ["autodocs"],
7
+ parameters: {
8
+ layout: "fullscreen",
9
+ },
10
+ decorators: [
11
+ (Story) => (_jsx("div", { className: "p-8 bg-bg-bg1", children: _jsx(Story, {}) })),
12
+ ],
13
+ };
14
+ export default meta;
15
+ // ---------------------------------------------------------------------------
16
+ // Default — single badge with controls
17
+ // ---------------------------------------------------------------------------
18
+ export const Default = {
19
+ args: {
20
+ label: "To do",
21
+ color: "default",
22
+ clickable: false,
23
+ },
24
+ };
25
+ // ---------------------------------------------------------------------------
26
+ // Status Badges — all colors × clickable / static
27
+ // ---------------------------------------------------------------------------
28
+ const COLORS = ["default", "warning", "info", "error", "success"];
29
+ const COLOR_LABELS = {
30
+ default: "To do",
31
+ warning: "In Progress",
32
+ info: "Ready to review",
33
+ error: "In review",
34
+ success: "Completed",
35
+ };
36
+ export const StatusBadges = {
37
+ render: () => (_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small1 text-text-g-contrast-low mb-3", children: "Clickable" }), _jsx("div", { className: "flex flex-wrap gap-3", children: COLORS.map((color) => (_jsx(Badge, { color: color, label: COLOR_LABELS[color], clickable: true }, color))) })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small1 text-text-g-contrast-low mb-3", children: "Static" }), _jsx("div", { className: "flex flex-wrap gap-3", children: COLORS.map((color) => (_jsx(Badge, { color: color, label: COLOR_LABELS[color] }, color))) })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small1 text-text-g-contrast-low mb-3", children: "With percentage" }), _jsx("div", { className: "flex flex-wrap gap-3", children: COLORS.map((color, i) => (_jsx(Badge, { color: color, label: COLOR_LABELS[color], percent: i === 0 ? 0 : i === 4 ? 100 : 50 }, color))) })] })] })),
38
+ };
39
+ // ---------------------------------------------------------------------------
40
+ // Severity Badges
41
+ // ---------------------------------------------------------------------------
42
+ const SEVERITIES = [
43
+ "highest",
44
+ "high",
45
+ "medium",
46
+ "low",
47
+ "lowest",
48
+ ];
49
+ export const SeverityBadges = {
50
+ render: () => (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("p", { className: "typography-small1 text-text-g-contrast-low mb-1", children: "Severity levels" }), _jsx("div", { className: "flex flex-wrap gap-3", children: SEVERITIES.map((severity) => (_jsx(SeverityBadge, { severity: severity }, severity))) })] })),
51
+ };
@@ -0,0 +1,62 @@
1
+ import { cva } from "class-variance-authority";
2
+ export const badgeVariants = cva([
3
+ "inline-flex items-center justify-center rounded-lg px-3 py-1",
4
+ "typography-body3",
5
+ ], {
6
+ variants: {
7
+ color: {
8
+ default: [
9
+ "bg-[var(--badge-default-bg)]",
10
+ "text-[var(--badge-default-text)]",
11
+ ],
12
+ success: [
13
+ "bg-[var(--badge-success-bg)]",
14
+ "text-[var(--badge-success-text)]",
15
+ ],
16
+ warning: [
17
+ "bg-[var(--badge-warning-bg)]",
18
+ "text-[var(--badge-warning-text)]",
19
+ ],
20
+ info: [
21
+ "bg-[var(--badge-info-bg)]",
22
+ "text-[var(--badge-info-text)]",
23
+ ],
24
+ error: [
25
+ "bg-[var(--badge-error-bg)]",
26
+ "text-[var(--badge-error-text)]",
27
+ ],
28
+ },
29
+ clickable: {
30
+ true: "border border-solid",
31
+ false: "",
32
+ },
33
+ },
34
+ compoundVariants: [
35
+ { color: "default", clickable: true, className: "border-[var(--badge-default-border)]" },
36
+ { color: "success", clickable: true, className: "border-[var(--badge-success-border)]" },
37
+ { color: "warning", clickable: true, className: "border-[var(--badge-warning-border)]" },
38
+ { color: "info", clickable: true, className: "border-[var(--badge-info-border)]" },
39
+ { color: "error", clickable: true, className: "border-[var(--badge-error-border)]" },
40
+ ],
41
+ defaultVariants: {
42
+ color: "default",
43
+ clickable: false,
44
+ },
45
+ });
46
+ export const severityBadgeVariants = cva([
47
+ "inline-flex items-center justify-center rounded px-1 py-0.5",
48
+ "typography-small6 text-[var(--badge-severity-text)]",
49
+ ], {
50
+ variants: {
51
+ severity: {
52
+ highest: "bg-[var(--badge-severity-highest-bg)]",
53
+ high: "bg-[var(--badge-severity-high-bg)]",
54
+ medium: "bg-[var(--badge-severity-medium-bg)]",
55
+ low: "bg-[var(--badge-severity-low-bg)]",
56
+ lowest: "bg-[var(--badge-severity-lowest-bg)]",
57
+ },
58
+ },
59
+ defaultVariants: {
60
+ severity: "medium",
61
+ },
62
+ });
@@ -0,0 +1,2 @@
1
+ import { Badge, SeverityBadge } from "./Badge";
2
+ export { Badge, SeverityBadge };
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  var __rest = (this && this.__rest) || function (s, e) {
2
3
  var t = {};
3
4
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -9,190 +10,80 @@ var __rest = (this && this.__rest) || function (s, e) {
9
10
  }
10
11
  return t;
11
12
  };
12
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
13
14
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, Fragment, } from "react";
14
- import * as Portal from "@radix-ui/react-portal";
15
+ import { Combobox, ComboboxInput, ComboboxOptions, ComboboxOption, } from "@headlessui/react";
15
16
  import TextInput from "../TextInput/TextInput";
16
17
  import { customInputVariant, dropdownIconVariant } from "./Dropdown.styles";
17
- import { Menu } from "../Menu/Menu";
18
- import { ChevronDownIcon } from "@heroicons/react/16/solid";
19
18
  import { cn } from "@/utils/cn";
19
+ import Icon from "../Icon/Icon";
20
+ import { ChevronDownIcon } from "@heroicons/react/16/solid";
21
+ // ---------------------------------------------------------------------------
22
+ // Shared menu item styles (used by Dropdown items + renderOptions consumers)
23
+ // ---------------------------------------------------------------------------
24
+ export const menuItemBaseStyles = cn("relative flex gap-1 cursor-pointer select-none box-border items-center py-4 pl-4 pr-8 typography-subtitle4 outline-none transition-colors", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "hover:bg-[var(--dropdown-menu-hover-bg)] hover:text-[var(--dropdown-menu-hover-text)]");
25
+ // ---------------------------------------------------------------------------
26
+ // Dropdown
27
+ // ---------------------------------------------------------------------------
20
28
  const Dropdown = forwardRef((_a, ref) => {
21
- var { id, options = [], value, label, size = "md", rounded = "normal", variant = "outline", defaultMenuItemType = "checkbox", helperText, errorMessage, fullwidth = true, disabled = false, error = false, filterMode = false, required = true, modal = false, onChangeText, onSelect, renderOptions: customRenderOptions, optionContainerClassName, optionItemClassName, optionNotFoundItemClassName, segmentedInput = true } = _a, props = __rest(_a, ["id", "options", "value", "label", "size", "rounded", "variant", "defaultMenuItemType", "helperText", "errorMessage", "fullwidth", "disabled", "error", "filterMode", "required", "modal", "onChangeText", "onSelect", "renderOptions", "optionContainerClassName", "optionItemClassName", "optionNotFoundItemClassName", "segmentedInput"]);
29
+ var { id, options = [], value, label, size = "md", rounded = "normal", variant = "outline", helperText, errorMessage, fullwidth = true, disabled = false, error = false, filterMode = false, required = true, modal: _modal, onChangeText, onSelect, renderOptions: customRenderOptions, optionContainerClassName, optionItemClassName, optionNotFoundItemClassName, segmentedInput = true } = _a, props = __rest(_a, ["id", "options", "value", "label", "size", "rounded", "variant", "helperText", "errorMessage", "fullwidth", "disabled", "error", "filterMode", "required", "modal", "onChangeText", "onSelect", "renderOptions", "optionContainerClassName", "optionItemClassName", "optionNotFoundItemClassName", "segmentedInput"]);
22
30
  const _id = id || `${label}-select`;
23
- const [isFocused, setIsFocused] = useState(false);
24
31
  const [selectedOption, setSelectedOption] = useState(null);
25
- const [textValue, setTextValue] = useState("");
26
- const keyCode = useRef("");
27
- const dropdownRef = useRef(null);
32
+ const [query, setQuery] = useState("");
28
33
  const inputRef = useRef(null);
29
- const [dropdownStyles, setDropdownStyles] = useState({});
30
- const [isAbove, setIsAbove] = useState(false);
31
- const [isInsideDialog, setIsInsideDialog] = useState(false);
32
- useImperativeHandle(ref, () => inputRef === null || inputRef === void 0 ? void 0 : inputRef.current);
34
+ // Expose the inner <input> element via forwardRef
35
+ useImperativeHandle(ref, () => inputRef.current, []);
36
+ // Sync external value prop
33
37
  useEffect(() => {
34
- var _a;
35
- setSelectedOption(value);
36
- setTextValue((_a = value === null || value === void 0 ? void 0 : value.label) !== null && _a !== void 0 ? _a : "");
38
+ setSelectedOption(value !== null && value !== void 0 ? value : null);
37
39
  }, [value]);
38
- /** ✅ Auto-detect if inside a Dialog */
39
- useEffect(() => {
40
- let node = inputRef.current;
41
- while (node) {
42
- if (node.getAttribute("role") === "dialog") {
43
- setIsInsideDialog(true);
44
- return;
45
- }
46
- node = node.parentElement;
47
- }
48
- setIsInsideDialog(false);
49
- }, []);
50
- const handleOnChangeText = useCallback((event) => {
51
- onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(event);
52
- setTextValue(event.target.value);
53
- if (!event.target.value) {
54
- clearMismatchValue(event);
55
- }
56
- }, [onChangeText]);
57
- const handleOptionClick = useCallback((option) => {
58
- setSelectedOption(option);
59
- setTextValue(option.label);
60
- onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
61
- setIsFocused(false);
62
- }, [onSelect]);
63
40
  const optionsFiltered = useMemo(() => {
64
- return options.filter((option) => {
65
- var _a;
66
- return !filterMode ||
67
- ((_a = option.label) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(textValue === null || textValue === void 0 ? void 0 : textValue.toLowerCase()));
68
- });
69
- }, [options, filterMode, textValue]);
70
- const usePortal = isInsideDialog ? false : modal;
71
- const updateDropdownPosition = useCallback(() => {
72
- if (inputRef.current && dropdownRef.current) {
73
- const rect = inputRef.current.getBoundingClientRect();
74
- const dropdownHeight = dropdownRef.current.offsetHeight;
75
- const spaceBelow = window.innerHeight - rect.bottom;
76
- const spaceAbove = rect.top;
77
- const shouldOpenAbove = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;
78
- setIsAbove(shouldOpenAbove);
79
- if (usePortal) {
80
- setDropdownStyles({
81
- position: "absolute",
82
- top: shouldOpenAbove
83
- ? `${rect.top - dropdownHeight}px`
84
- : `${rect.bottom}px`,
85
- left: `${rect.left}px`,
86
- width: `${rect.width}px`,
87
- zIndex: 9999,
88
- });
89
- }
90
- else {
91
- setDropdownStyles({
92
- position: "absolute",
93
- top: shouldOpenAbove ? `-${dropdownHeight}px` : "100%",
94
- left: "0",
95
- width: "100%",
96
- zIndex: 9999,
97
- });
98
- }
99
- }
100
- }, [modal, isInsideDialog, usePortal]);
101
- useEffect(() => {
102
- if (isFocused) {
103
- updateDropdownPosition();
104
- window.addEventListener("resize", updateDropdownPosition);
41
+ if (!filterMode || !query)
42
+ return options;
43
+ return options.filter((opt) => opt.label.toLowerCase().includes(query.toLowerCase()));
44
+ }, [options, filterMode, query]);
45
+ const handleSelect = useCallback((option) => {
46
+ setSelectedOption(option);
47
+ setQuery("");
48
+ if (option) {
49
+ onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
50
+ // After selection Headless UI keeps focus on the input (via rAF refocus).
51
+ // Blur after that rAF so the next click triggers onFocus → immediate open.
52
+ setTimeout(() => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur(); }, 0);
105
53
  }
106
- return () => {
107
- window.removeEventListener("resize", updateDropdownPosition);
108
- };
109
- }, [isFocused, updateDropdownPosition]);
110
- const renderOptions = () => {
54
+ }, [onSelect]);
55
+ const handleInputChange = useCallback((e) => {
56
+ if (filterMode)
57
+ setQuery(e.target.value);
58
+ onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(e);
59
+ }, [filterMode, onChangeText]);
60
+ const renderOptionList = () => {
111
61
  if (customRenderOptions) {
112
62
  return customRenderOptions({
113
63
  optionsFiltered,
114
64
  selectedOption,
115
- onClick: handleOptionClick,
116
- style: dropdownStyles,
117
- dropdownRef,
65
+ onClick: handleSelect,
118
66
  });
119
67
  }
120
- // Convert options to MenuItemType
121
- let finalMenuItems;
122
- finalMenuItems = optionsFiltered.map((option) => {
68
+ if (optionsFiltered.length === 0) {
69
+ return (_jsx("div", { className: cn("px-4 py-14 text-center text-input-text", optionNotFoundItemClassName), children: "Not found" }));
70
+ }
71
+ return optionsFiltered.map((option) => {
123
72
  if (option.renderLabel) {
124
- return {
125
- type: "custom",
126
- render: () => (_jsx(Fragment, { children: option.renderLabel({
127
- value: option.value,
128
- label: option.label,
129
- handleOnClick: () => handleOptionClick(option),
130
- className: cn("relative flex gap-3 cursor-pointer select-none box-border items-center py-4 pl-9 pr-4 typography-subtitle4 outline-none transition-colors", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "hover:bg-[var(--dropdown-menu-hover-bg)] hover:text-[var(--dropdown-menu-hover-text)]", {
131
- "bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)] typography-subtitle5": (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) === option.value,
132
- }, optionItemClassName),
133
- }) }, option.value)),
134
- };
73
+ return (_jsx(Fragment, { children: option.renderLabel({
74
+ value: option.value,
75
+ label: option.label,
76
+ handleOnClick: () => handleSelect(option),
77
+ className: cn(menuItemBaseStyles, (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) === option.value &&
78
+ "bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)]", optionItemClassName),
79
+ }) }, option.value));
135
80
  }
136
- return {
137
- type: "item",
138
- item: {
139
- type: defaultMenuItemType,
140
- value: option.value,
141
- label: option.label,
142
- },
143
- };
81
+ return (_jsx(ComboboxOption, { value: option, className: ({ focus, selected }) => cn(menuItemBaseStyles, (selected || (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) === option.value) &&
82
+ "bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)]", focus &&
83
+ "bg-[var(--dropdown-menu-hover-bg)] text-[var(--dropdown-menu-hover-text)]", optionItemClassName), children: ({ selected }) => (_jsxs(_Fragment, { children: [_jsx("span", { className: "shrink-0 size-4 flex items-center justify-center", children: (selected || (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) === option.value) && (_jsx(Icon, { type: "heroicons", name: "check", className: "size-4 text-[var(--dropdown-menu-selected-text)]" })) }), option.label] })) }, option.value));
144
84
  });
145
- // Add "not found" message if no results
146
- if (finalMenuItems.length === 0) {
147
- finalMenuItems.push({
148
- type: "custom",
149
- render: () => (_jsx("div", { className: cn("px-4 py-14 text-center text-input-text", optionNotFoundItemClassName), children: "Not found" }, "not-found")),
150
- });
151
- }
152
- return (_jsx(Menu, { ref: dropdownRef, items: finalMenuItems, selectedValues: (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) ? [selectedOption.value] : [], onSelect: (value) => {
153
- const option = optionsFiltered.find((opt) => opt.value === value);
154
- if (option) {
155
- handleOptionClick(option);
156
- }
157
- }, className: cn("absolute mt-1 w-full max-h-60 overflow-y-auto", !usePortal && (isAbove ? "bottom-full mb-1" : "top-full mt-1"), optionContainerClassName), style: dropdownStyles }));
158
85
  };
159
- const handleOnFocus = useCallback((e) => {
160
- var _a;
161
- setIsFocused(true);
162
- (_a = props === null || props === void 0 ? void 0 : props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
163
- }, [props === null || props === void 0 ? void 0 : props.onFocus]);
164
- const clearMismatchValue = useCallback((e) => {
165
- const matchSelectedValue = optionsFiltered.find((opt) => { var _a, _b; return opt.value === ((_a = e.target) === null || _a === void 0 ? void 0 : _a.value) || opt.label === ((_b = e.target) === null || _b === void 0 ? void 0 : _b.value); });
166
- const isMatchSelectedValue = !!matchSelectedValue;
167
- let option = matchSelectedValue || {
168
- value: "",
169
- label: "",
170
- };
171
- if (!isMatchSelectedValue && textValue) {
172
- option = {
173
- value: "",
174
- label: "",
175
- };
176
- }
177
- if (keyCode.current === "Enter") {
178
- return;
179
- }
180
- setSelectedOption(option);
181
- setTextValue(option.label);
182
- onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
183
- }, [optionsFiltered, textValue]);
184
- const handleOnBlur = useCallback((e) => {
185
- var _a;
186
- setTimeout(() => setIsFocused(false), 200);
187
- clearMismatchValue(e);
188
- (_a = props === null || props === void 0 ? void 0 : props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
189
- }, [props === null || props === void 0 ? void 0 : props.onBlur, clearMismatchValue]);
190
- const handleOnKeyDown = useCallback((e) => {
191
- var _a;
192
- keyCode.current = e.code;
193
- (_a = props === null || props === void 0 ? void 0 : props.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(props, e);
194
- }, [props === null || props === void 0 ? void 0 : props.onKeyDown]);
195
- return (_jsxs("div", { className: `relative ${fullwidth ? "w-full" : ""}`, children: [_jsx(TextInput, Object.assign({ hasClearIcon: false, endIcon: _jsx(ChevronDownIcon, { className: dropdownIconVariant({ isFocus: isFocused }) }) }, props, { ref: inputRef, readOnly: !filterMode, value: textValue, onChange: handleOnChangeText, label: label, placeholder: " ", type: "text", autoComplete: "off", rounded: rounded, variant: variant, helperText: helperText, errorMessage: errorMessage, fullwidth: fullwidth, error: error, required: required, id: _id, disabled: disabled, size: size, className: segmentedInput ? customInputVariant({ size }) : undefined, onFocus: handleOnFocus, onBlur: handleOnBlur, onKeyDown: handleOnKeyDown })), isFocused &&
196
- (usePortal ? (_jsx(Portal.Root, { container: document.body, children: renderOptions() })) : (renderOptions()))] }));
86
+ return (_jsx(Combobox, { value: selectedOption, onChange: handleSelect, immediate: true, by: "value", disabled: disabled, children: ({ open }) => (_jsxs("div", { className: cn("relative", fullwidth && "w-full"), children: [_jsx(ComboboxInput, Object.assign({ as: TextInput, ref: inputRef, hasClearIcon: false, endIcon: _jsx(ChevronDownIcon, { className: dropdownIconVariant({ isFocus: open }) }), label: label, placeholder: " ", autoComplete: "off", rounded: rounded, variant: variant, helperText: helperText, errorMessage: errorMessage, fullwidth: fullwidth, error: error, required: required, id: _id, disabled: disabled, size: size, className: segmentedInput ? customInputVariant({ size }) : undefined, displayValue: (opt) => { var _a; return (_a = opt === null || opt === void 0 ? void 0 : opt.label) !== null && _a !== void 0 ? _a : ""; }, readOnly: !filterMode, onChange: handleInputChange }, props)), _jsx(ComboboxOptions, { className: cn("absolute top-full left-0 w-full mt-1 z-[51]", "min-w-[154px] max-h-60 overflow-y-auto", "rounded-lg bg-modal-surface text-text-g-contrast-high", optionContainerClassName), style: { boxShadow: "var(--dropdown-menu-shadow)" }, children: renderOptionList() })] })) }));
197
87
  });
88
+ Dropdown.displayName = "Dropdown";
198
89
  export default Dropdown;
@@ -3,6 +3,7 @@ import { useRef, useState } from "react";
3
3
  import Dropdown from "./Dropdown";
4
4
  import Button from "../Button/Button";
5
5
  import { cn } from "@/utils/cn";
6
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogBody, DialogFooter, DialogTrigger, DialogClose, } from "../Dialog/Dialog";
6
7
  // More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
7
8
  const meta = {
8
9
  title: "Components/Dropdown",
@@ -113,3 +114,31 @@ export const WithIcons = {
113
114
  return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Dropdown, { id: "with-icons", size: "lg", label: "Select Food", fullwidth: true, options: optionsWithIcons, value: selectedValue, onSelect: (option) => setSelectedValue(option) }) }));
114
115
  },
115
116
  };
117
+ // ---------------------------------------------------------------------------
118
+ // Dropdown inside Dialog — showcases the fix for overflow:hidden bug
119
+ // ---------------------------------------------------------------------------
120
+ const dialogOptions = [
121
+ { value: "design", label: "Design" },
122
+ { value: "engineering", label: "Engineering" },
123
+ { value: "product", label: "Product" },
124
+ { value: "marketing", label: "Marketing" },
125
+ { value: "data", label: "Data & Analytics" },
126
+ { value: "ops", label: "Operations" },
127
+ ];
128
+ const filterableOptions = new Array(20).fill("").map((_, i) => ({
129
+ value: `member-${i + 1}`,
130
+ label: `Team Member ${i + 1}`,
131
+ }));
132
+ export const InsideDialog = {
133
+ name: "Inside Dialog",
134
+ render: () => {
135
+ const [department, setDepartment] = useState();
136
+ const [member, setMember] = useState();
137
+ const [role, setRole] = useState();
138
+ return (_jsxs("div", { className: "flex gap-4 flex-wrap", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Single Dropdown" }), _jsxs(Dialog, { children: [_jsx(DialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Dialog" }) }), _jsxs(DialogContent, { showCloseButton: true, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Assign to Department" }), _jsx(DialogDescription, { children: "Dropdown popup appears above the dialog overlay \u2014 not clipped by overflow." })] }), _jsx(DialogBody, { className: "gap-4 py-2", children: _jsx(Dropdown, { id: "dept", label: "Department", size: "md", fullwidth: true, options: dialogOptions, value: department, onSelect: setDepartment }) }), _jsxs(DialogFooter, { children: [_jsx(DialogClose, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Cancel" }) }), _jsx(Button, { children: "Confirm" })] })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Multiple Dropdowns" }), _jsxs(Dialog, { children: [_jsx(DialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Dialog" }) }), _jsxs(DialogContent, { showCloseButton: true, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Invite Team Member" }), _jsx(DialogDescription, { children: "Multiple dropdowns \u2014 each opens its own popup independently." })] }), _jsxs(DialogBody, { className: "gap-4 py-2", children: [_jsx(Dropdown, { id: "member", label: "Member", size: "md", fullwidth: true, options: filterableOptions, value: member, onSelect: setMember, filterMode: true }), _jsx(Dropdown, { id: "role", label: "Role", size: "md", fullwidth: true, options: [
139
+ { value: "viewer", label: "Viewer" },
140
+ { value: "editor", label: "Editor" },
141
+ { value: "admin", label: "Admin" },
142
+ ], value: role, onSelect: setRole })] }), _jsxs(DialogFooter, { children: [_jsx(DialogClose, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Cancel" }) }), _jsx(Button, { disabled: !member || !role, children: "Send Invite" })] })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Filter Mode" }), _jsxs(Dialog, { children: [_jsx(DialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Dialog" }) }), _jsxs(DialogContent, { showCloseButton: true, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Search & Select" }), _jsx(DialogDescription, { children: "filterMode=true \u2014 type to filter options, popup stays properly positioned." })] }), _jsx(DialogBody, { className: "gap-4 py-2", children: _jsx(Dropdown, { id: "member-filter", label: "Search member", size: "md", fullwidth: true, filterMode: true, options: filterableOptions, value: member, onSelect: setMember }) }), _jsxs(DialogFooter, { children: [_jsx(DialogClose, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Cancel" }) }), _jsx(Button, { disabled: !member, children: "Select" })] })] })] })] })] }));
143
+ },
144
+ };
@@ -23,7 +23,7 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
23
23
  const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
24
24
  const DropdownMenuSubTrigger = React.forwardRef((_a, ref) => {
25
25
  var { className, inset, children } = _a, props = __rest(_a, ["className", "inset", "children"]);
26
- return (_jsxs(DropdownMenuPrimitive.SubTrigger, Object.assign({ ref: ref, className: cn("relative flex gap-4 cursor-pointer select-none box-border items-center py-4 pl-9 pr-4 typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", inset && "pl-8", className) }, props, { children: [children, _jsx(Icon, { type: "heroicons", name: "chevron-right", className: "ml-auto h-4 w-4" })] })));
26
+ return (_jsxs(DropdownMenuPrimitive.SubTrigger, Object.assign({ ref: ref, className: cn("relative flex gap-4 cursor-pointer select-none box-border items-center py-4 pl-4 pr-4 typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", inset && "pl-8", className) }, props, { children: [children, _jsx(Icon, { type: "heroicons", name: "chevron-right", className: "ml-auto h-4 w-4" })] })));
27
27
  });
28
28
  DropdownMenuSubTrigger.displayName =
29
29
  DropdownMenuPrimitive.SubTrigger.displayName;
@@ -39,29 +39,42 @@ const DropdownMenuContent = React.forwardRef((_a, ref) => {
39
39
  });
40
40
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
41
41
  const DropdownMenuItem = React.forwardRef((_a, ref) => {
42
- var { className, inset } = _a, props = __rest(_a, ["className", "inset"]);
43
- return (_jsx(DropdownMenuPrimitive.Item, Object.assign({ ref: ref, className: cn("relative flex gap-4 cursor-pointer select-none box-border items-center py-4 pl-9 pr-xxl typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", inset && "pl-8", className) }, props)));
42
+ var { className, inset, selected, icon, children } = _a, props = __rest(_a, ["className", "inset", "selected", "icon", "children"]);
43
+ const hasIcon = !!icon;
44
+ return (_jsxs(DropdownMenuPrimitive.Item, Object.assign({ ref: ref, className: cn("relative flex cursor-pointer select-none box-border items-center py-4 pl-4 pr-8 typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", selected &&
45
+ "bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)] typography-subtitle5", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", inset && "pl-8", className, hasIcon ? "gap-4" : "gap-1") }, props, { children: [_jsxs("div", { className: "flex shrink-0 flex-row gap-1", children: [_jsx("span", { className: "size-4 flex items-center justify-center", children: selected && (_jsx(Icon, { type: "heroicons", name: "check", className: "size-4 text-[var(--dropdown-menu-selected-text)]" })) }), icon] }), children] })));
44
46
  });
45
47
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
46
48
  const DropdownMenuCheckboxItem = React.forwardRef((_a, ref) => {
47
- var { className, children, checked } = _a, props = __rest(_a, ["className", "children", "checked"]);
48
- return (_jsxs(DropdownMenuPrimitive.CheckboxItem, Object.assign({ ref: ref, className: cn("relative flex gap-4 cursor-pointer select-none box-border items-center py-4 pl-9 pr-xxl typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[state='checked']:bg-[var(--dropdown-menu-selected-bg)] data-[state='checked']:text-[var(--dropdown-menu-selected-text)] data-[state='checked']:typography-subtitle5", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", className), checked: checked }, props, { children: [_jsx("span", { className: "absolute left-4 flex items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Icon, { type: "heroicons", name: "check", className: "size-4" }) }) }), children] })));
49
+ var { className, children, checked, disabled } = _a, props = __rest(_a, ["className", "children", "checked", "disabled"]);
50
+ return (_jsxs(DropdownMenuPrimitive.CheckboxItem, Object.assign({ ref: ref, className: cn("relative flex gap-3 cursor-pointer select-none box-border items-center py-4 pl-4 pr-8 typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[state='checked']:bg-[var(--dropdown-menu-selected-bg)] data-[state='checked']:text-[var(--dropdown-menu-selected-text)]", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", className), checked: checked, disabled: disabled }, props, { children: [_jsx("span", { className: cn("shrink-0 size-4 rounded-[2px] border flex items-center justify-center transition-all overflow-hidden", checked &&
51
+ !disabled &&
52
+ "bg-[var(--dropdown-menu-checkbox-checked-bg)] border-[var(--dropdown-menu-checkbox-checked-bg)]", checked &&
53
+ disabled &&
54
+ "bg-[var(--dropdown-menu-checkbox-disabled-checked-bg)] border-transparent", !checked &&
55
+ disabled &&
56
+ "border-[var(--dropdown-menu-checkbox-disabled-border)]", !checked &&
57
+ !disabled &&
58
+ "border-[var(--dropdown-menu-checkbox-border)]"), children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Icon, { type: "heroicons", name: "check", className: "size-3 text-[var(--dropdown-menu-checkbox-checked-icon)]" }) }) }), children] })));
49
59
  });
50
60
  DropdownMenuCheckboxItem.displayName =
51
61
  DropdownMenuPrimitive.CheckboxItem.displayName;
52
62
  const DropdownMenuRadioItem = React.forwardRef((_a, ref) => {
53
- var { className, children } = _a, props = __rest(_a, ["className", "children"]);
54
- return (_jsxs(DropdownMenuPrimitive.RadioItem, Object.assign({ ref: ref, className: cn("relative flex gap-4 cursor-pointer select-none box-border items-center py-4 pl-9 pr-xxl typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[state='checked']:bg-[var(--dropdown-menu-selected-bg)] data-[state='checked']:text-[var(--dropdown-menu-selected-text)] data-[state='checked']:typography-subtitle5", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-disabled-text)]", className) }, props, { children: [_jsx("span", { className: "absolute left-4 flex items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Icon, { type: "heroicons", name: "circle", className: "h-2 w-2 fill-current" }) }) }), children] })));
63
+ var { className, children, disabled, icon } = _a, props = __rest(_a, ["className", "children", "disabled", "icon"]);
64
+ const hasIconSlot = !!icon;
65
+ return (_jsxs(DropdownMenuPrimitive.RadioItem, Object.assign({ ref: ref, className: cn("relative flex cursor-pointer select-none box-border items-center py-4 pl-4 pr-8 typography-subtitle4 outline-none transition-colors data-[disabled]:pointer-events-none", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "focus:!bg-[var(--dropdown-menu-hover-bg)] focus:!text-[var(--dropdown-menu-hover-text)]", "data-[state='checked']:bg-[var(--dropdown-menu-selected-bg)] data-[state='checked']:text-[var(--dropdown-menu-selected-text)]", "data-[disabled]:!bg-[var(--dropdown-menu-disabled-bg)] data-[disabled]:!text-[var(--dropdown-menu-radio-disabled-text)]", "data-[state='checked']:data-[disabled]:!text-[var(--dropdown-menu-radio-selected-disabled-text)]", className, hasIconSlot ? "gap-4" : "gap-1") }, props, { disabled: disabled, children: [_jsxs("div", { className: "flex shrink-0 flex-row gap-1", children: [_jsx("span", { className: "size-4", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { className: "shrink-0", children: _jsx(Icon, { type: "heroicons", name: "check", className: cn("size-4", disabled
66
+ ? "text-[var(--dropdown-menu-radio-selected-disabled-text)]"
67
+ : "text-[var(--dropdown-menu-selected-text)]") }) }) }), icon] }), children] })));
55
68
  });
56
69
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
57
70
  const DropdownMenuLabel = React.forwardRef((_a, ref) => {
58
71
  var { className, inset } = _a, props = __rest(_a, ["className", "inset"]);
59
- return (_jsx(DropdownMenuPrimitive.Label, Object.assign({ ref: ref, className: cn("px-3 pt-4 pb-2 typography-small4 text-text-g-contrast-high", inset && "pl-8", className) }, props)));
72
+ return (_jsx(DropdownMenuPrimitive.Label, Object.assign({ ref: ref, className: cn("px-3 py-2 typography-small4 text-text-g-contrast-high", inset && "pl-8", className) }, props)));
60
73
  });
61
74
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
62
75
  const DropdownMenuSeparator = React.forwardRef((_a, ref) => {
63
76
  var { className } = _a, props = __rest(_a, ["className"]);
64
- return (_jsx(DropdownMenuPrimitive.Separator, Object.assign({ ref: ref, className: cn("-mx-2 my-2 h-px bg-[var(--dropdown-menu-seperator-bg)]", className) }, props)));
77
+ return (_jsx(DropdownMenuPrimitive.Separator, Object.assign({ ref: ref, className: cn("h-px bg-[var(--dropdown-menu-seperator-bg)]", className) }, props)));
65
78
  });
66
79
  DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
67
80
  const DropdownMenuShortcut = (_a) => {