@inf-monkeys-tech/monkeys-design 1.0.56 → 1.0.60
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/{WorkbenchRadarMatrix-3f0daea32926.d.ts → WorkbenchRadarMatrix-2ec5e4970f24.d.ts} +40 -3
- package/dist/{WorkbenchRadarMatrix-3b2384181e2d.d.mts → WorkbenchRadarMatrix-b50483af5a5d.d.mts} +40 -3
- package/dist/components/dropdown/index.d.mts +89 -0
- package/dist/components/dropdown/index.d.ts +89 -0
- package/dist/components/dropdown/index.js +382 -0
- package/dist/components/dropdown/index.js.map +1 -0
- package/dist/components/dropdown/index.mjs +360 -0
- package/dist/components/dropdown/index.mjs.map +1 -0
- package/dist/components/workbench/index.d.mts +1 -1
- package/dist/components/workbench/index.d.ts +1 -1
- package/dist/components/workbench/index.js +169 -24
- package/dist/components/workbench/index.js.map +1 -1
- package/dist/components/workbench/index.mjs +169 -25
- package/dist/components/workbench/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +529 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +528 -38
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
4
|
+
var lucideReact = require('lucide-react');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var tailwindMerge = require('tailwind-merge');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
|
|
28
|
+
|
|
29
|
+
// src/components/dropdown/UnifiedDropdown.tsx
|
|
30
|
+
function cn(...parts) {
|
|
31
|
+
return tailwindMerge.twMerge(parts.filter(Boolean).join(" "));
|
|
32
|
+
}
|
|
33
|
+
var placementMap = {
|
|
34
|
+
"bottom-start": { side: "bottom", align: "start" },
|
|
35
|
+
"bottom-end": { side: "bottom", align: "end" },
|
|
36
|
+
"top-start": { side: "top", align: "start" },
|
|
37
|
+
"top-end": { side: "top", align: "end" }
|
|
38
|
+
};
|
|
39
|
+
function flattenOptions(options, depth = 0) {
|
|
40
|
+
return options.flatMap((option) => [
|
|
41
|
+
{ ...option, depth },
|
|
42
|
+
...option.children ? flattenOptions(option.children, depth + 1) : []
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
function validateOptions(options) {
|
|
46
|
+
const values = /* @__PURE__ */ new Set();
|
|
47
|
+
flattenOptions(options).forEach((option) => {
|
|
48
|
+
if (!option || typeof option !== "object") {
|
|
49
|
+
throw new TypeError("UnifiedDropdown options must contain objects.");
|
|
50
|
+
}
|
|
51
|
+
if (typeof option.value !== "string" || !option.value.trim()) {
|
|
52
|
+
throw new TypeError("UnifiedDropdown option value must be a non-empty string.");
|
|
53
|
+
}
|
|
54
|
+
if (values.has(option.value)) {
|
|
55
|
+
throw new TypeError(`UnifiedDropdown option value "${option.value}" must be unique.`);
|
|
56
|
+
}
|
|
57
|
+
values.add(option.value);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function normalizeValues(value) {
|
|
61
|
+
const values = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
62
|
+
return [...new Set(values.filter((item) => typeof item === "string"))];
|
|
63
|
+
}
|
|
64
|
+
function getOptionText(option) {
|
|
65
|
+
if (option.textValue) return option.textValue;
|
|
66
|
+
return typeof option.label === "string" ? option.label : option.value;
|
|
67
|
+
}
|
|
68
|
+
function isMultiMode(mode) {
|
|
69
|
+
return mode === "multi" || mode === "checkbox";
|
|
70
|
+
}
|
|
71
|
+
function matchesSearch(option, query) {
|
|
72
|
+
return getOptionText(option).toLocaleLowerCase().includes(query.toLocaleLowerCase());
|
|
73
|
+
}
|
|
74
|
+
function validateValueShape(mode, value, name) {
|
|
75
|
+
if (value === void 0) return;
|
|
76
|
+
if (isMultiMode(mode) ? !Array.isArray(value) : typeof value !== "string") {
|
|
77
|
+
throw new TypeError(
|
|
78
|
+
`UnifiedDropdown ${name} must be ${isMultiMode(mode) ? "a string array" : "a string"} in ${mode} mode.`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
var UnifiedDropdown = react.forwardRef(
|
|
83
|
+
function UnifiedDropdown2({
|
|
84
|
+
mode,
|
|
85
|
+
options = [],
|
|
86
|
+
groups = [],
|
|
87
|
+
value,
|
|
88
|
+
defaultValue,
|
|
89
|
+
placeholder = "Select\u2026",
|
|
90
|
+
trigger,
|
|
91
|
+
triggerLabel,
|
|
92
|
+
searchPlaceholder = "Search\u2026",
|
|
93
|
+
emptyLabel = "No options",
|
|
94
|
+
loadingLabel = "Loading\u2026",
|
|
95
|
+
clearLabel = "Clear selection",
|
|
96
|
+
retryLabel = "Retry",
|
|
97
|
+
loading = false,
|
|
98
|
+
error,
|
|
99
|
+
searchable = mode === "searchable",
|
|
100
|
+
clearable = false,
|
|
101
|
+
maxSelections,
|
|
102
|
+
disabled = false,
|
|
103
|
+
invalid = false,
|
|
104
|
+
open: controlledOpen,
|
|
105
|
+
defaultOpen = false,
|
|
106
|
+
placement = "bottom-start",
|
|
107
|
+
closeOnSelect = mode !== "multi" && mode !== "checkbox",
|
|
108
|
+
portal = true,
|
|
109
|
+
size = "default",
|
|
110
|
+
width = "trigger",
|
|
111
|
+
appearance,
|
|
112
|
+
className,
|
|
113
|
+
classNames,
|
|
114
|
+
slots,
|
|
115
|
+
style,
|
|
116
|
+
onOpenChange,
|
|
117
|
+
onValueChange,
|
|
118
|
+
onSelect,
|
|
119
|
+
onAction,
|
|
120
|
+
onClear,
|
|
121
|
+
onRetry,
|
|
122
|
+
...rootProps
|
|
123
|
+
}, ref) {
|
|
124
|
+
if (!["single", "multi", "searchable", "radio", "checkbox", "tree", "action"].includes(mode)) {
|
|
125
|
+
throw new TypeError(`UnifiedDropdown mode "${String(mode)}" is not supported.`);
|
|
126
|
+
}
|
|
127
|
+
const groupedOptions = react.useMemo(
|
|
128
|
+
() => groups.reduce((result, group) => {
|
|
129
|
+
const groupName = typeof group.label === "string" ? group.label : group.value;
|
|
130
|
+
result.push(...group.options.map((option) => ({ ...option, group: option.group ?? groupName })));
|
|
131
|
+
return result;
|
|
132
|
+
}, [...options]),
|
|
133
|
+
[groups, options]
|
|
134
|
+
);
|
|
135
|
+
validateOptions(groupedOptions);
|
|
136
|
+
if (maxSelections !== void 0 && (!Number.isFinite(maxSelections) || maxSelections < 0)) {
|
|
137
|
+
throw new TypeError("UnifiedDropdown maxSelections must be a non-negative finite number.");
|
|
138
|
+
}
|
|
139
|
+
if (mode === "action" && (value !== void 0 || defaultValue !== void 0)) {
|
|
140
|
+
throw new TypeError("UnifiedDropdown action mode does not accept a value.");
|
|
141
|
+
}
|
|
142
|
+
if (mode !== "action") {
|
|
143
|
+
validateValueShape(mode, value, "value");
|
|
144
|
+
validateValueShape(mode, defaultValue, "defaultValue");
|
|
145
|
+
}
|
|
146
|
+
const id = react.useId();
|
|
147
|
+
const triggerId = `${id}-trigger`;
|
|
148
|
+
const listId = `${id}-listbox`;
|
|
149
|
+
const searchId = `${id}-search`;
|
|
150
|
+
const triggerRef = react.useRef(null);
|
|
151
|
+
const itemRefs = react.useRef([]);
|
|
152
|
+
const [uncontrolledOpen, setUncontrolledOpen] = react.useState(defaultOpen);
|
|
153
|
+
const [uncontrolledValue, setUncontrolledValue] = react.useState(
|
|
154
|
+
defaultValue ?? (isMultiMode(mode) ? [] : "")
|
|
155
|
+
);
|
|
156
|
+
const [query, setQuery] = react.useState("");
|
|
157
|
+
const [activeIndex, setActiveIndex] = react.useState(0);
|
|
158
|
+
const isControlled = controlledOpen !== void 0;
|
|
159
|
+
const open = isControlled ? controlledOpen : uncontrolledOpen;
|
|
160
|
+
const selectedValues = normalizeValues(value ?? uncontrolledValue);
|
|
161
|
+
const flattened = react.useMemo(() => flattenOptions(groupedOptions), [groupedOptions]);
|
|
162
|
+
const visibleOptions = react.useMemo(
|
|
163
|
+
() => searchable ? flattened.filter((option) => matchesSearch(option, query)) : flattened,
|
|
164
|
+
[flattened, query, searchable]
|
|
165
|
+
);
|
|
166
|
+
const selectedSet = react.useMemo(() => new Set(selectedValues), [selectedValues]);
|
|
167
|
+
const selectedOptions = flattened.filter((option) => selectedSet.has(option.value));
|
|
168
|
+
const selectedLabel = selectedOptions.map(getOptionText).join(", ");
|
|
169
|
+
const resolvedTriggerLabel = triggerLabel ?? (selectedLabel || placeholder);
|
|
170
|
+
const isPlaceholder = selectedOptions.length === 0 && !triggerLabel;
|
|
171
|
+
const { side, align } = placementMap[placement];
|
|
172
|
+
const isMenu = mode === "action";
|
|
173
|
+
const usesCheckedMenu = mode === "radio" || mode === "checkbox";
|
|
174
|
+
const contentRole = isMenu || usesCheckedMenu ? "menu" : "listbox";
|
|
175
|
+
react.useEffect(() => {
|
|
176
|
+
if (open) setActiveIndex(0);
|
|
177
|
+
}, [open, query]);
|
|
178
|
+
const setOpen = (nextOpen) => {
|
|
179
|
+
if (disabled) return;
|
|
180
|
+
if (!isControlled) setUncontrolledOpen(nextOpen);
|
|
181
|
+
onOpenChange?.(nextOpen);
|
|
182
|
+
};
|
|
183
|
+
const commitValue = (nextValue) => {
|
|
184
|
+
if (value === void 0) setUncontrolledValue(nextValue);
|
|
185
|
+
onValueChange?.(nextValue);
|
|
186
|
+
};
|
|
187
|
+
const selectOption = (option) => {
|
|
188
|
+
if (disabled || option.disabled) return;
|
|
189
|
+
onSelect?.(option);
|
|
190
|
+
if (mode === "action") {
|
|
191
|
+
if (closeOnSelect) setOpen(false);
|
|
192
|
+
if (onAction) queueMicrotask(() => onAction(option));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (isMultiMode(mode)) {
|
|
196
|
+
const nextValues = selectedSet.has(option.value) ? selectedValues.filter((item) => item !== option.value) : maxSelections !== void 0 && selectedValues.length >= maxSelections ? selectedValues : [...selectedValues, option.value];
|
|
197
|
+
commitValue(nextValues);
|
|
198
|
+
} else {
|
|
199
|
+
commitValue(option.value);
|
|
200
|
+
}
|
|
201
|
+
if (closeOnSelect && !isMultiMode(mode)) setOpen(false);
|
|
202
|
+
};
|
|
203
|
+
const handleTriggerKeyDown = (event) => {
|
|
204
|
+
if (disabled) return;
|
|
205
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
if (!open) setOpen(true);
|
|
208
|
+
const direction = event.key === "ArrowDown" ? 1 : -1;
|
|
209
|
+
setActiveIndex((index) => Math.max(0, Math.min(visibleOptions.length - 1, index + direction)));
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
const handleContentKeyDown = (event) => {
|
|
213
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
214
|
+
event.preventDefault();
|
|
215
|
+
const direction = event.key === "ArrowDown" ? 1 : -1;
|
|
216
|
+
setActiveIndex((index) => {
|
|
217
|
+
const next = index + direction;
|
|
218
|
+
return Math.max(0, Math.min(visibleOptions.length - 1, next));
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (event.key === "Enter" && visibleOptions[activeIndex]) {
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
selectOption(visibleOptions[activeIndex]);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
react.useEffect(() => {
|
|
227
|
+
if (!open) return;
|
|
228
|
+
itemRefs.current[activeIndex]?.scrollIntoView({ block: "nearest" });
|
|
229
|
+
}, [activeIndex, open]);
|
|
230
|
+
const clearSelection = () => {
|
|
231
|
+
commitValue(isMultiMode(mode) ? [] : "");
|
|
232
|
+
onClear?.();
|
|
233
|
+
};
|
|
234
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
235
|
+
"div",
|
|
236
|
+
{
|
|
237
|
+
...rootProps,
|
|
238
|
+
ref,
|
|
239
|
+
className: cn("relative inline-flex min-w-0", className),
|
|
240
|
+
style,
|
|
241
|
+
"data-monkeys-component": "unified-dropdown",
|
|
242
|
+
"data-mode": mode,
|
|
243
|
+
"data-state": open ? "open" : "closed",
|
|
244
|
+
"data-invalid": invalid || void 0,
|
|
245
|
+
"data-disabled": disabled || void 0,
|
|
246
|
+
"data-appearance-preset": appearance?.preset,
|
|
247
|
+
"data-appearance-variant": appearance?.variant,
|
|
248
|
+
"data-appearance-density": appearance?.density,
|
|
249
|
+
"data-appearance-radius": appearance?.radius,
|
|
250
|
+
children: [
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
252
|
+
"button",
|
|
253
|
+
{
|
|
254
|
+
ref: triggerRef,
|
|
255
|
+
id: triggerId,
|
|
256
|
+
type: "button",
|
|
257
|
+
disabled,
|
|
258
|
+
"aria-expanded": open,
|
|
259
|
+
"aria-haspopup": isMenu || usesCheckedMenu ? "menu" : "listbox",
|
|
260
|
+
"aria-controls": open ? listId : void 0,
|
|
261
|
+
"aria-invalid": invalid || void 0,
|
|
262
|
+
onKeyDown: handleTriggerKeyDown,
|
|
263
|
+
className: cn(
|
|
264
|
+
"flex min-w-0 items-center justify-between gap-2 rounded-md border border-input bg-control-surface px-3 text-left text-sm text-foreground shadow-sm outline-none transition-colors",
|
|
265
|
+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-control-surface",
|
|
266
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
267
|
+
size === "sm" ? "h-8 py-1 text-xs" : "h-10 py-2",
|
|
268
|
+
invalid && "border-destructive focus-visible:ring-destructive",
|
|
269
|
+
width === "responsive" && "w-full sm:w-auto",
|
|
270
|
+
classNames?.trigger
|
|
271
|
+
),
|
|
272
|
+
children: [
|
|
273
|
+
trigger ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 shrink-0", children: trigger }) : null,
|
|
274
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 flex-1 truncate", isPlaceholder && "text-muted-foreground"), children: resolvedTriggerLabel }),
|
|
275
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": "true", className: "h-4 w-4 shrink-0 opacity-60" })
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
) }),
|
|
279
|
+
(() => {
|
|
280
|
+
const content = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
281
|
+
PopoverPrimitive__namespace.Content,
|
|
282
|
+
{
|
|
283
|
+
id: listId,
|
|
284
|
+
side,
|
|
285
|
+
align,
|
|
286
|
+
sideOffset: 6,
|
|
287
|
+
collisionPadding: 8,
|
|
288
|
+
avoidCollisions: true,
|
|
289
|
+
onKeyDown: handleContentKeyDown,
|
|
290
|
+
onOpenAutoFocus: (event) => {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
const target = searchable ? document.getElementById(searchId) : itemRefs.current[0];
|
|
293
|
+
target?.focus();
|
|
294
|
+
},
|
|
295
|
+
tabIndex: -1,
|
|
296
|
+
className: cn(
|
|
297
|
+
"z-50 max-h-[min(24rem,calc(100vh-1rem))] max-w-[calc(100vw-1rem)] overflow-y-auto rounded-md border bg-menu-surface p-1 text-popover-foreground shadow-md outline-none",
|
|
298
|
+
width === "trigger" && "w-[var(--radix-popover-trigger-width)] min-w-[12rem]",
|
|
299
|
+
width === "content" && "min-w-[12rem] max-w-[min(32rem,calc(100vw-1rem))]",
|
|
300
|
+
width === "responsive" && "w-[min(var(--radix-popover-trigger-width),calc(100vw-1rem))] min-w-[12rem]",
|
|
301
|
+
classNames?.content
|
|
302
|
+
),
|
|
303
|
+
children: [
|
|
304
|
+
searchable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative mb-1", children: [
|
|
305
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { "aria-hidden": "true", className: "pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
306
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
307
|
+
"input",
|
|
308
|
+
{
|
|
309
|
+
id: searchId,
|
|
310
|
+
value: query,
|
|
311
|
+
onChange: (event) => setQuery(event.target.value),
|
|
312
|
+
placeholder: searchPlaceholder,
|
|
313
|
+
"aria-label": searchPlaceholder,
|
|
314
|
+
className: cn("h-9 w-full rounded-sm border-0 bg-transparent pl-8 pr-2 text-sm outline-none ring-0 placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring", classNames?.search)
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
] }) : null,
|
|
318
|
+
clearable && selectedOptions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mb-1 w-full rounded-sm px-2 py-1 text-left text-xs text-muted-foreground hover:bg-accent", onClick: clearSelection, children: clearLabel }) : null,
|
|
319
|
+
loading && visibleOptions.length === 0 ? slots?.loading ? slots.loading() : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: cn("px-2 py-6 text-center text-sm text-muted-foreground", classNames?.empty), children: loadingLabel }) : error && visibleOptions.length === 0 ? slots?.error ? slots.error() : /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: cn("px-2 py-6 text-center text-sm text-destructive-text", classNames?.empty), children: [
|
|
320
|
+
error,
|
|
321
|
+
onRetry ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mt-2 block w-full text-center text-foreground underline", onClick: onRetry, children: retryLabel }) : null
|
|
322
|
+
] }) : visibleOptions.length === 0 ? slots?.empty ? slots.empty() : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: cn("px-2 py-6 text-center text-sm text-muted-foreground", classNames?.empty), children: emptyLabel }) : /* @__PURE__ */ jsxRuntime.jsx("div", { role: mode === "tree" ? "tree" : contentRole, "aria-multiselectable": mode === "multi" || void 0, children: visibleOptions.map((option, index) => {
|
|
323
|
+
const selected = selectedSet.has(option.value);
|
|
324
|
+
const indicator = mode === "radio" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { "aria-hidden": "true", className: cn("h-3.5 w-3.5", selected && "fill-current") }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": "true", className: "h-4 w-4" });
|
|
325
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
326
|
+
option.group && (index === 0 || visibleOptions[index - 1]?.group !== option.group) ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "presentation", className: cn("px-2 pb-1 pt-2 text-xs font-medium text-muted-foreground", classNames?.groupLabel), children: option.group }) : null,
|
|
327
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
328
|
+
"button",
|
|
329
|
+
{
|
|
330
|
+
ref: (node) => {
|
|
331
|
+
itemRefs.current[index] = node;
|
|
332
|
+
},
|
|
333
|
+
type: "button",
|
|
334
|
+
role: mode === "tree" ? "treeitem" : mode === "radio" ? "menuitemradio" : mode === "checkbox" ? "menuitemcheckbox" : isMenu ? "menuitem" : "option",
|
|
335
|
+
"aria-level": mode === "tree" ? option.depth + 1 : void 0,
|
|
336
|
+
"aria-selected": !isMenu && !usesCheckedMenu ? selected : void 0,
|
|
337
|
+
"aria-checked": usesCheckedMenu ? selected : void 0,
|
|
338
|
+
disabled: option.disabled,
|
|
339
|
+
"data-highlighted": index === activeIndex || void 0,
|
|
340
|
+
"data-state": selected ? "checked" : "unchecked",
|
|
341
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
342
|
+
onClick: () => selectOption(option),
|
|
343
|
+
className: cn(
|
|
344
|
+
"relative flex min-h-9 w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none transition-colors",
|
|
345
|
+
"hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground",
|
|
346
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
347
|
+
index === activeIndex && "bg-accent text-accent-foreground",
|
|
348
|
+
selected && "font-medium",
|
|
349
|
+
option.danger && "text-destructive-text",
|
|
350
|
+
mode !== "action" && "pl-8",
|
|
351
|
+
classNames?.item
|
|
352
|
+
),
|
|
353
|
+
style: mode === "tree" ? { paddingInlineStart: `${8 + option.depth * 16}px` } : void 0,
|
|
354
|
+
children: [
|
|
355
|
+
mode !== "action" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-2 flex h-4 w-4 items-center justify-center", children: selected ? indicator : null }) : null,
|
|
356
|
+
slots?.option ? slots.option({ option, selected, highlighted: index === activeIndex }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
357
|
+
option.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: option.icon }) : null,
|
|
358
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 flex-1 truncate", classNames?.itemLabel), children: option.label }),
|
|
359
|
+
option.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("max-w-[45%] truncate text-xs text-muted-foreground", classNames?.itemDescription), children: option.description }) : null
|
|
360
|
+
] })
|
|
361
|
+
]
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
] }, option.value);
|
|
365
|
+
}) }),
|
|
366
|
+
error && visibleOptions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: "px-2 py-1 text-xs text-destructive-text", children: error }) : null,
|
|
367
|
+
loading && visibleOptions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: "px-2 py-1 text-xs text-muted-foreground", children: loadingLabel }) : null,
|
|
368
|
+
slots?.footer ? slots.footer() : null
|
|
369
|
+
]
|
|
370
|
+
}
|
|
371
|
+
);
|
|
372
|
+
return portal ? /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: content }) : content;
|
|
373
|
+
})()
|
|
374
|
+
]
|
|
375
|
+
}
|
|
376
|
+
) });
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
exports.UnifiedDropdown = UnifiedDropdown;
|
|
381
|
+
//# sourceMappingURL=index.js.map
|
|
382
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/base/utils.ts","../../../src/components/dropdown/UnifiedDropdown.tsx"],"names":["twMerge","forwardRef","UnifiedDropdown","useMemo","useId","useRef","useState","useEffect","jsx","PopoverPrimitive","jsxs","ChevronDown","Search","Circle","Check","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["import type { ReactNode } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...parts: Array<string | false | null | undefined>) {\n return twMerge(parts.filter(Boolean).join(' '));\n}\n\nexport function hasRenderableNode(node: ReactNode) {\n return node !== undefined && node !== null && typeof node !== 'boolean';\n}\n\nexport function hasNonEmptyRenderableNode(node: ReactNode) {\n if (typeof node === 'string') return node.trim().length > 0;\n return hasRenderableNode(node);\n}\n","import * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { Check, ChevronDown, Circle, Search } from 'lucide-react';\nimport {\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n} from 'react';\n\nimport { cn } from '../base/utils';\nimport type {\n UnifiedDropdownMode,\n UnifiedDropdownGroup,\n UnifiedDropdownOption,\n UnifiedDropdownPlacement,\n UnifiedDropdownProps,\n UnifiedDropdownValue,\n} from './types';\n\nconst placementMap: Record<\n UnifiedDropdownPlacement,\n { side: 'top' | 'bottom'; align: 'start' | 'end' }\n> = {\n 'bottom-start': { side: 'bottom', align: 'start' },\n 'bottom-end': { side: 'bottom', align: 'end' },\n 'top-start': { side: 'top', align: 'start' },\n 'top-end': { side: 'top', align: 'end' },\n};\n\nfunction flattenOptions(\n options: readonly UnifiedDropdownOption[],\n depth = 0,\n): Array<UnifiedDropdownOption & { depth: number }> {\n return options.flatMap((option) => [\n { ...option, depth },\n ...(option.children ? flattenOptions(option.children, depth + 1) : []),\n ]);\n}\n\nfunction validateOptions(options: readonly UnifiedDropdownOption[]) {\n const values = new Set<string>();\n flattenOptions(options).forEach((option) => {\n if (!option || typeof option !== 'object') {\n throw new TypeError('UnifiedDropdown options must contain objects.');\n }\n if (typeof option.value !== 'string' || !option.value.trim()) {\n throw new TypeError('UnifiedDropdown option value must be a non-empty string.');\n }\n if (values.has(option.value)) {\n throw new TypeError(`UnifiedDropdown option value \"${option.value}\" must be unique.`);\n }\n values.add(option.value);\n });\n}\n\nfunction normalizeValues(value: UnifiedDropdownValue | undefined) {\n const values = Array.isArray(value) ? value : value === undefined ? [] : [value];\n return [...new Set(values.filter((item): item is string => typeof item === 'string'))];\n}\n\nfunction getOptionText(option: UnifiedDropdownOption) {\n if (option.textValue) return option.textValue;\n return typeof option.label === 'string' ? option.label : option.value;\n}\n\nfunction isMultiMode(mode: UnifiedDropdownMode) {\n return mode === 'multi' || mode === 'checkbox';\n}\n\nfunction matchesSearch(option: UnifiedDropdownOption, query: string) {\n return getOptionText(option).toLocaleLowerCase().includes(query.toLocaleLowerCase());\n}\n\nfunction validateValueShape(\n mode: UnifiedDropdownMode,\n value: UnifiedDropdownValue | undefined,\n name: 'value' | 'defaultValue',\n) {\n if (value === undefined) return;\n if (isMultiMode(mode) ? !Array.isArray(value) : typeof value !== 'string') {\n throw new TypeError(\n `UnifiedDropdown ${name} must be ${isMultiMode(mode) ? 'a string array' : 'a string'} in ${mode} mode.`,\n );\n }\n}\n\nexport const UnifiedDropdown = forwardRef<HTMLDivElement, UnifiedDropdownProps>(\n function UnifiedDropdown(\n {\n mode,\n options = [],\n groups = [],\n value,\n defaultValue,\n placeholder = 'Select…',\n trigger,\n triggerLabel,\n searchPlaceholder = 'Search…',\n emptyLabel = 'No options',\n loadingLabel = 'Loading…',\n clearLabel = 'Clear selection',\n retryLabel = 'Retry',\n loading = false,\n error,\n searchable = mode === 'searchable',\n clearable = false,\n maxSelections,\n disabled = false,\n invalid = false,\n open: controlledOpen,\n defaultOpen = false,\n placement = 'bottom-start',\n closeOnSelect = mode !== 'multi' && mode !== 'checkbox',\n portal = true,\n size = 'default',\n width = 'trigger',\n appearance,\n className,\n classNames,\n slots,\n style,\n onOpenChange,\n onValueChange,\n onSelect,\n onAction,\n onClear,\n onRetry,\n ...rootProps\n },\n ref,\n ) {\n if (!['single', 'multi', 'searchable', 'radio', 'checkbox', 'tree', 'action'].includes(mode)) {\n throw new TypeError(`UnifiedDropdown mode \"${String(mode)}\" is not supported.`);\n }\n const groupedOptions = useMemo(\n () => groups.reduce<UnifiedDropdownOption[]>((result, group: UnifiedDropdownGroup) => {\n const groupName = typeof group.label === 'string' ? group.label : group.value;\n result.push(...group.options.map((option) => ({ ...option, group: option.group ?? groupName })));\n return result;\n }, [...options]),\n [groups, options],\n );\n validateOptions(groupedOptions);\n if (maxSelections !== undefined && (!Number.isFinite(maxSelections) || maxSelections < 0)) {\n throw new TypeError('UnifiedDropdown maxSelections must be a non-negative finite number.');\n }\n if (mode === 'action' && (value !== undefined || defaultValue !== undefined)) {\n throw new TypeError('UnifiedDropdown action mode does not accept a value.');\n }\n if (mode !== 'action') {\n validateValueShape(mode, value, 'value');\n validateValueShape(mode, defaultValue, 'defaultValue');\n }\n\n const id = useId();\n const triggerId = `${id}-trigger`;\n const listId = `${id}-listbox`;\n const searchId = `${id}-search`;\n const triggerRef = useRef<HTMLButtonElement | null>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const [uncontrolledValue, setUncontrolledValue] = useState<UnifiedDropdownValue>(\n defaultValue ?? (isMultiMode(mode) ? [] : ''),\n );\n const [query, setQuery] = useState('');\n const [activeIndex, setActiveIndex] = useState(0);\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : uncontrolledOpen;\n const selectedValues = normalizeValues(value ?? uncontrolledValue);\n const flattened = useMemo(() => flattenOptions(groupedOptions), [groupedOptions]);\n const visibleOptions = useMemo(\n () => (searchable ? flattened.filter((option) => matchesSearch(option, query)) : flattened),\n [flattened, query, searchable],\n );\n const selectedSet = useMemo(() => new Set(selectedValues), [selectedValues]);\n const selectedOptions = flattened.filter((option) => selectedSet.has(option.value));\n const selectedLabel = selectedOptions.map(getOptionText).join(', ');\n const resolvedTriggerLabel = triggerLabel ?? (selectedLabel || placeholder);\n const isPlaceholder = selectedOptions.length === 0 && !triggerLabel;\n const { side, align } = placementMap[placement];\n const isMenu = mode === 'action';\n const usesCheckedMenu = mode === 'radio' || mode === 'checkbox';\n const contentRole = isMenu || usesCheckedMenu ? 'menu' : 'listbox';\n\n useEffect(() => {\n if (open) setActiveIndex(0);\n }, [open, query]);\n\n const setOpen = (nextOpen: boolean) => {\n if (disabled) return;\n if (!isControlled) setUncontrolledOpen(nextOpen);\n onOpenChange?.(nextOpen);\n };\n\n const commitValue = (nextValue: UnifiedDropdownValue) => {\n if (value === undefined) setUncontrolledValue(nextValue);\n onValueChange?.(nextValue);\n };\n\n const selectOption = (option: UnifiedDropdownOption) => {\n if (disabled || option.disabled) return;\n onSelect?.(option);\n if (mode === 'action') {\n if (closeOnSelect) setOpen(false);\n if (onAction) queueMicrotask(() => onAction(option));\n return;\n }\n if (isMultiMode(mode)) {\n const nextValues = selectedSet.has(option.value)\n ? selectedValues.filter((item) => item !== option.value)\n : maxSelections !== undefined && selectedValues.length >= maxSelections\n ? selectedValues\n : [...selectedValues, option.value];\n commitValue(nextValues);\n } else {\n commitValue(option.value);\n }\n if (closeOnSelect && !isMultiMode(mode)) setOpen(false);\n };\n\n const handleTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (disabled) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n if (!open) setOpen(true);\n const direction = event.key === 'ArrowDown' ? 1 : -1;\n setActiveIndex((index) => Math.max(0, Math.min(visibleOptions.length - 1, index + direction)));\n }\n };\n\n const handleContentKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const direction = event.key === 'ArrowDown' ? 1 : -1;\n setActiveIndex((index) => {\n const next = index + direction;\n return Math.max(0, Math.min(visibleOptions.length - 1, next));\n });\n }\n if (event.key === 'Enter' && visibleOptions[activeIndex]) {\n event.preventDefault();\n selectOption(visibleOptions[activeIndex]!);\n }\n };\n\n useEffect(() => {\n if (!open) return;\n itemRefs.current[activeIndex]?.scrollIntoView({ block: 'nearest' });\n }, [activeIndex, open]);\n\n const clearSelection = () => {\n commitValue(isMultiMode(mode) ? [] : '');\n onClear?.();\n };\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <div\n {...rootProps}\n ref={ref}\n className={cn('relative inline-flex min-w-0', className)}\n style={style}\n data-monkeys-component=\"unified-dropdown\"\n data-mode={mode}\n data-state={open ? 'open' : 'closed'}\n data-invalid={invalid || undefined}\n data-disabled={disabled || undefined}\n data-appearance-preset={appearance?.preset}\n data-appearance-variant={appearance?.variant}\n data-appearance-density={appearance?.density}\n data-appearance-radius={appearance?.radius}\n >\n <PopoverPrimitive.Trigger asChild>\n <button\n ref={triggerRef}\n id={triggerId}\n type=\"button\"\n disabled={disabled}\n aria-expanded={open}\n aria-haspopup={isMenu || usesCheckedMenu ? 'menu' : 'listbox'}\n aria-controls={open ? listId : undefined}\n aria-invalid={invalid || undefined}\n onKeyDown={handleTriggerKeyDown}\n className={cn(\n 'flex min-w-0 items-center justify-between gap-2 rounded-md border border-input bg-control-surface px-3 text-left text-sm text-foreground shadow-sm outline-none transition-colors',\n 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-control-surface',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n size === 'sm' ? 'h-8 py-1 text-xs' : 'h-10 py-2',\n invalid && 'border-destructive focus-visible:ring-destructive',\n width === 'responsive' && 'w-full sm:w-auto',\n classNames?.trigger,\n )}\n >\n {trigger ? <span className=\"min-w-0 shrink-0\">{trigger}</span> : null}\n <span className={cn('min-w-0 flex-1 truncate', isPlaceholder && 'text-muted-foreground')}>\n {resolvedTriggerLabel}\n </span>\n <ChevronDown aria-hidden=\"true\" className=\"h-4 w-4 shrink-0 opacity-60\" />\n </button>\n </PopoverPrimitive.Trigger>\n {(() => {\n const content = (\n <PopoverPrimitive.Content\n id={listId}\n side={side}\n align={align}\n sideOffset={6}\n collisionPadding={8}\n avoidCollisions\n onKeyDown={handleContentKeyDown}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n const target = searchable\n ? document.getElementById(searchId)\n : itemRefs.current[0];\n target?.focus();\n }}\n tabIndex={-1}\n className={cn(\n 'z-50 max-h-[min(24rem,calc(100vh-1rem))] max-w-[calc(100vw-1rem)] overflow-y-auto rounded-md border bg-menu-surface p-1 text-popover-foreground shadow-md outline-none',\n width === 'trigger' && 'w-[var(--radix-popover-trigger-width)] min-w-[12rem]',\n width === 'content' && 'min-w-[12rem] max-w-[min(32rem,calc(100vw-1rem))]',\n width === 'responsive' && 'w-[min(var(--radix-popover-trigger-width),calc(100vw-1rem))] min-w-[12rem]',\n classNames?.content,\n )}\n >\n {searchable ? (\n <div className=\"relative mb-1\">\n <Search aria-hidden=\"true\" className=\"pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <input\n id={searchId}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n className={cn('h-9 w-full rounded-sm border-0 bg-transparent pl-8 pr-2 text-sm outline-none ring-0 placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring', classNames?.search)}\n />\n </div>\n ) : null}\n {clearable && selectedOptions.length > 0 ? (\n <button type=\"button\" className=\"mb-1 w-full rounded-sm px-2 py-1 text-left text-xs text-muted-foreground hover:bg-accent\" onClick={clearSelection}>\n {clearLabel}\n </button>\n ) : null}\n {loading && visibleOptions.length === 0 ? (\n slots?.loading ? slots.loading() : <div role=\"status\" className={cn('px-2 py-6 text-center text-sm text-muted-foreground', classNames?.empty)}>{loadingLabel}</div>\n ) : error && visibleOptions.length === 0 ? (\n slots?.error ? slots.error() : <div role=\"alert\" className={cn('px-2 py-6 text-center text-sm text-destructive-text', classNames?.empty)}>{error}{onRetry ? <button type=\"button\" className=\"mt-2 block w-full text-center text-foreground underline\" onClick={onRetry}>{retryLabel}</button> : null}</div>\n ) : visibleOptions.length === 0 ? (\n slots?.empty ? slots.empty() : <div role=\"status\" className={cn('px-2 py-6 text-center text-sm text-muted-foreground', classNames?.empty)}>{emptyLabel}</div>\n ) : (\n <div role={mode === 'tree' ? 'tree' : contentRole} aria-multiselectable={mode === 'multi' || undefined}>\n {visibleOptions.map((option, index) => {\n const selected = selectedSet.has(option.value);\n const indicator = mode === 'radio' ? <Circle aria-hidden=\"true\" className={cn('h-3.5 w-3.5', selected && 'fill-current')} /> : <Check aria-hidden=\"true\" className=\"h-4 w-4\" />;\n return (\n <div key={option.value}>\n {option.group && (index === 0 || visibleOptions[index - 1]?.group !== option.group) ? (\n <div role=\"presentation\" className={cn('px-2 pb-1 pt-2 text-xs font-medium text-muted-foreground', classNames?.groupLabel)}>{option.group}</div>\n ) : null}\n <button\n ref={(node) => { itemRefs.current[index] = node; }}\n type=\"button\"\n role={mode === 'tree' ? 'treeitem' : mode === 'radio' ? 'menuitemradio' : mode === 'checkbox' ? 'menuitemcheckbox' : isMenu ? 'menuitem' : 'option'}\n aria-level={mode === 'tree' ? option.depth + 1 : undefined}\n aria-selected={!isMenu && !usesCheckedMenu ? selected : undefined}\n aria-checked={usesCheckedMenu ? selected : undefined}\n disabled={option.disabled}\n data-highlighted={index === activeIndex || undefined}\n data-state={selected ? 'checked' : 'unchecked'}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n className={cn(\n 'relative flex min-h-9 w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none transition-colors',\n 'hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground',\n 'disabled:pointer-events-none disabled:opacity-50',\n index === activeIndex && 'bg-accent text-accent-foreground',\n selected && 'font-medium',\n option.danger && 'text-destructive-text',\n mode !== 'action' && 'pl-8',\n classNames?.item,\n )}\n style={mode === 'tree' ? { paddingInlineStart: `${8 + option.depth * 16}px` } : undefined}\n >\n {mode !== 'action' ? <span className=\"absolute left-2 flex h-4 w-4 items-center justify-center\">{selected ? indicator : null}</span> : null}\n {slots?.option ? slots.option({ option, selected, highlighted: index === activeIndex }) : <>\n {option.icon ? <span className=\"shrink-0\">{option.icon}</span> : null}\n <span className={cn('min-w-0 flex-1 truncate', classNames?.itemLabel)}>{option.label}</span>\n {option.description ? <span className={cn('max-w-[45%] truncate text-xs text-muted-foreground', classNames?.itemDescription)}>{option.description}</span> : null}\n </>}\n </button>\n </div>\n );\n })}\n </div>\n )}\n {error && visibleOptions.length > 0 ? <div role=\"status\" className=\"px-2 py-1 text-xs text-destructive-text\">{error}</div> : null}\n {loading && visibleOptions.length > 0 ? <div role=\"status\" className=\"px-2 py-1 text-xs text-muted-foreground\">{loadingLabel}</div> : null}\n {slots?.footer ? slots.footer() : null}\n </PopoverPrimitive.Content>\n );\n return portal ? <PopoverPrimitive.Portal>{content}</PopoverPrimitive.Portal> : content;\n })()}\n </div>\n </PopoverPrimitive.Root>\n );\n },\n);\n"]}
|