@vesture/react 0.2.8 → 0.2.10
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.css +138 -2
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +49 -2
- package/dist/index.js +363 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -501,13 +501,17 @@ interface ComboboxProps {
|
|
|
501
501
|
disabled?: boolean;
|
|
502
502
|
invalid?: boolean;
|
|
503
503
|
loading?: boolean;
|
|
504
|
+
/** Number of filtered options at/above which the listbox switches to virtualized (windowed) rendering. */
|
|
505
|
+
virtualizationThreshold?: number;
|
|
506
|
+
/** Row height (px) used for virtualized listbox rows; defaults to the `.option` class's rendered height. */
|
|
507
|
+
optionHeight?: number;
|
|
504
508
|
id?: string;
|
|
505
509
|
className?: string;
|
|
506
510
|
"aria-label"?: string;
|
|
507
511
|
"aria-labelledby"?: string;
|
|
508
512
|
}
|
|
509
513
|
|
|
510
|
-
declare function Combobox({ options, multiple, value: controlledValue, defaultValue, onChange, onInputChange, filterOptions, placeholder, noOptionsMessage, disabled, invalid, loading, id, className, ...rest }: ComboboxProps): ReactElement;
|
|
514
|
+
declare function Combobox({ options, multiple, value: controlledValue, defaultValue, onChange, onInputChange, filterOptions, placeholder, noOptionsMessage, disabled, invalid, loading, virtualizationThreshold, optionHeight, id, className, ...rest }: ComboboxProps): ReactElement;
|
|
511
515
|
|
|
512
516
|
interface TreeNode<T = unknown> {
|
|
513
517
|
id: string;
|
|
@@ -535,4 +539,47 @@ interface TreeViewProps<T = unknown> {
|
|
|
535
539
|
|
|
536
540
|
declare function TreeView<T = unknown>({ nodes, expanded: controlledExpanded, defaultExpanded, onExpandedChange, selected: controlledSelected, defaultSelected, onSelectedChange, selectable, onLoadChildren, height, rowHeight, }: TreeViewProps<T>): ReactElement;
|
|
537
541
|
|
|
538
|
-
|
|
542
|
+
interface CommandItem {
|
|
543
|
+
id: string;
|
|
544
|
+
label: string;
|
|
545
|
+
description?: string;
|
|
546
|
+
icon?: ReactNode;
|
|
547
|
+
/** Extra searchable terms not shown in the label. */
|
|
548
|
+
keywords?: string[];
|
|
549
|
+
/** Display-only, e.g. "⌘K". */
|
|
550
|
+
shortcut?: string;
|
|
551
|
+
/** Groups render under a section header, in the order groups first appear in `commands`. */
|
|
552
|
+
group?: string;
|
|
553
|
+
onSelect: () => void;
|
|
554
|
+
disabled?: boolean;
|
|
555
|
+
}
|
|
556
|
+
interface CommandPaletteProps {
|
|
557
|
+
open: boolean;
|
|
558
|
+
onOpenChange: (open: boolean) => void;
|
|
559
|
+
commands: CommandItem[];
|
|
560
|
+
placeholder?: string;
|
|
561
|
+
emptyMessage?: string;
|
|
562
|
+
/** Overrides the default case-insensitive substring match against label + keywords + group. */
|
|
563
|
+
filterCommands?: (commands: CommandItem[], query: string) => CommandItem[];
|
|
564
|
+
/** Number of rows (commands + group headers) at/above which the list switches to virtualized rendering. */
|
|
565
|
+
virtualizationThreshold?: number;
|
|
566
|
+
/** Row height (px) used for virtualized rows; defaults to the `.option` class's rendered height. */
|
|
567
|
+
rowHeight?: number;
|
|
568
|
+
"aria-label"?: string;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
declare function CommandPalette({ open, onOpenChange, commands, placeholder, emptyMessage, filterCommands, virtualizationThreshold, rowHeight, "aria-label": ariaLabel }: CommandPaletteProps): ReactElement | null;
|
|
572
|
+
|
|
573
|
+
interface UseCommandPaletteShortcutOptions {
|
|
574
|
+
key?: string;
|
|
575
|
+
metaKey?: boolean;
|
|
576
|
+
ctrlKey?: boolean;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Attaches a document-level Cmd+K (Mac) / Ctrl+K (elsewhere) listener that
|
|
580
|
+
* calls onOpenChange(true). Separate from CommandPalette so consumers can
|
|
581
|
+
* wire their own trigger instead.
|
|
582
|
+
*/
|
|
583
|
+
declare function useCommandPaletteShortcut(onOpenChange: (open: boolean) => void, options?: UseCommandPaletteShortcutOptions): void;
|
|
584
|
+
|
|
585
|
+
export { Accordion, AccordionContent, type AccordionContentProps, AccordionItem, type AccordionItemProps, type AccordionProps, AccordionTrigger, type AccordionTriggerProps, Alert, type AlertProps, type AlertVariant, Avatar, type AvatarProps, type AvatarSize, type AvatarStatus, Badge, type BadgeProps, type BadgeVariant, Breadcrumbs, BreadcrumbsItem, type BreadcrumbsItemProps, type BreadcrumbsProps, Button, type ButtonProps, type ButtonVariant, Calendar, type CalendarProps, Card, type CardElevation, type CardProps, Checkbox, type CheckboxProps, Combobox, type ComboboxOption, type ComboboxProps, type CommandItem, CommandPalette, type CommandPaletteProps, DataGrid, type DataGridColumn, type DataGridExportOptions, type DataGridHandle, type DataGridProps, DatePicker, type DatePickerProps, type DateRange, DateRangePicker, type DateRangePickerProps, Divider, type DividerOrientation, type DividerProps, DropdownMenu, DropdownMenuItem, type DropdownMenuItemProps, type DropdownMenuProps, Input, type InputProps, Label, type LabelProps, Modal, type ModalProps, NumberInput, type NumberInputProps, Pagination, type PaginationProps, Popover, type PopoverProps, Progress, type ProgressProps, Radio, type RadioProps, Select, type SelectProps, Slider, type SliderProps, type SliderValue, type SortDirection, type SortState, Spinner, type SpinnerProps, type SpinnerSize, Stack, type StackAlign, type StackDirection, type StackGap, type StackJustify, type StackProps, Switch, type SwitchProps, Tabs, TabsList, type TabsListProps, TabsPanel, type TabsPanelProps, type TabsProps, TabsTrigger, type TabsTriggerProps, Textarea, type TextareaProps, type ToastContextValue, type ToastOptions, ToastProvider, type ToastVariant, Tooltip, type TooltipProps, type TreeNode, TreeView, type TreeViewProps, type TreeViewSelectable, type UseCommandPaletteShortcutOptions, useCommandPaletteShortcut, useToast };
|
package/dist/index.js
CHANGED
|
@@ -3246,14 +3246,17 @@ import {
|
|
|
3246
3246
|
var chip = "Combobox_chip__26nhic2";
|
|
3247
3247
|
var chipRemove = "Combobox_chipRemove__26nhic3";
|
|
3248
3248
|
var chipsWrapper = "Combobox_chipsWrapper__26nhic1";
|
|
3249
|
-
var emptyState2 = "
|
|
3249
|
+
var emptyState2 = "Combobox_emptyState__26nhic8";
|
|
3250
3250
|
var inputEl = "Combobox_inputEl__26nhic4";
|
|
3251
3251
|
var listbox = "Combobox_listbox__26nhic5";
|
|
3252
3252
|
var option = "Combobox_option__26nhic6";
|
|
3253
|
+
var virtualSpacer = "Combobox_virtualSpacer__26nhic7";
|
|
3253
3254
|
var wrapper9 = "Combobox_wrapper__26nhic0";
|
|
3254
3255
|
|
|
3255
3256
|
// src/components/Combobox/Combobox.tsx
|
|
3256
3257
|
import { jsx as jsx40, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3258
|
+
var DEFAULT_OPTION_HEIGHT = 37;
|
|
3259
|
+
var OVERSCAN = 5;
|
|
3257
3260
|
function defaultFilter(options, inputText) {
|
|
3258
3261
|
const query = inputText.trim().toLowerCase();
|
|
3259
3262
|
if (!query) return options;
|
|
@@ -3276,6 +3279,8 @@ function Combobox({
|
|
|
3276
3279
|
disabled = false,
|
|
3277
3280
|
invalid,
|
|
3278
3281
|
loading = false,
|
|
3282
|
+
virtualizationThreshold = 50,
|
|
3283
|
+
optionHeight = DEFAULT_OPTION_HEIGHT,
|
|
3279
3284
|
id,
|
|
3280
3285
|
className,
|
|
3281
3286
|
...rest
|
|
@@ -3302,8 +3307,37 @@ function Combobox({
|
|
|
3302
3307
|
}
|
|
3303
3308
|
}, [singleValue, multiple]);
|
|
3304
3309
|
const inputRef = useRef9(null);
|
|
3310
|
+
const listboxRef = useRef9(null);
|
|
3305
3311
|
const listboxId = useId2();
|
|
3312
|
+
const [scrollTop, setScrollTop] = useState14(0);
|
|
3313
|
+
const [viewportHeight, setViewportHeight] = useState14(280);
|
|
3306
3314
|
const filteredOptions = filterOptions(options, multiple ? inputText : open ? inputText : "");
|
|
3315
|
+
const isVirtualized = filteredOptions.length >= virtualizationThreshold;
|
|
3316
|
+
useEffect7(() => {
|
|
3317
|
+
setScrollTop(0);
|
|
3318
|
+
setActiveIndex(null);
|
|
3319
|
+
if (listboxRef.current) listboxRef.current.scrollTop = 0;
|
|
3320
|
+
}, [options]);
|
|
3321
|
+
useEffect7(() => {
|
|
3322
|
+
if (!open) return;
|
|
3323
|
+
const node = listboxRef.current;
|
|
3324
|
+
if (!node) return;
|
|
3325
|
+
if (node.clientHeight > 0) setViewportHeight(node.clientHeight);
|
|
3326
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
3327
|
+
const observer = new ResizeObserver((entries) => {
|
|
3328
|
+
const entry = entries[0];
|
|
3329
|
+
if (entry) setViewportHeight(entry.contentRect.height);
|
|
3330
|
+
});
|
|
3331
|
+
observer.observe(node);
|
|
3332
|
+
return () => observer.disconnect();
|
|
3333
|
+
}, [open]);
|
|
3334
|
+
const totalHeight = filteredOptions.length * optionHeight;
|
|
3335
|
+
const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
|
|
3336
|
+
const effectiveScrollTop = Math.min(scrollTop, maxScrollTop);
|
|
3337
|
+
const visibleCount = Math.ceil(viewportHeight / optionHeight) + OVERSCAN * 2;
|
|
3338
|
+
const startIndex = isVirtualized ? Math.max(0, Math.floor(effectiveScrollTop / optionHeight) - OVERSCAN) : 0;
|
|
3339
|
+
const endIndex = isVirtualized ? Math.min(filteredOptions.length, startIndex + visibleCount) : filteredOptions.length;
|
|
3340
|
+
const visibleOptions = filteredOptions.slice(startIndex, endIndex);
|
|
3307
3341
|
const { refs, floatingStyles, context } = useFloating7({
|
|
3308
3342
|
open,
|
|
3309
3343
|
onOpenChange: setOpen,
|
|
@@ -3348,6 +3382,21 @@ function Combobox({
|
|
|
3348
3382
|
setOpen(true);
|
|
3349
3383
|
setActiveIndex(null);
|
|
3350
3384
|
};
|
|
3385
|
+
const scrollIndexIntoView = (index) => {
|
|
3386
|
+
if (!isVirtualized) return;
|
|
3387
|
+
const rowTop = index * optionHeight;
|
|
3388
|
+
const rowBottom = rowTop + optionHeight;
|
|
3389
|
+
let next = scrollTop;
|
|
3390
|
+
if (rowTop < scrollTop) {
|
|
3391
|
+
next = rowTop;
|
|
3392
|
+
} else if (rowBottom > scrollTop + viewportHeight) {
|
|
3393
|
+
next = rowBottom - viewportHeight;
|
|
3394
|
+
} else {
|
|
3395
|
+
return;
|
|
3396
|
+
}
|
|
3397
|
+
setScrollTop(next);
|
|
3398
|
+
if (listboxRef.current) listboxRef.current.scrollTop = next;
|
|
3399
|
+
};
|
|
3351
3400
|
const moveActiveIndex = (direction2) => {
|
|
3352
3401
|
if (filteredOptions.length === 0) return;
|
|
3353
3402
|
let next = activeIndex ?? (direction2 === 1 ? -1 : filteredOptions.length);
|
|
@@ -3355,6 +3404,7 @@ function Combobox({
|
|
|
3355
3404
|
next = (next + direction2 + filteredOptions.length) % filteredOptions.length;
|
|
3356
3405
|
if (!filteredOptions[next]?.disabled) {
|
|
3357
3406
|
setActiveIndex(next);
|
|
3407
|
+
scrollIndexIntoView(next);
|
|
3358
3408
|
return;
|
|
3359
3409
|
}
|
|
3360
3410
|
}
|
|
@@ -3448,14 +3498,40 @@ function Combobox({
|
|
|
3448
3498
|
open ? /* @__PURE__ */ jsx40(FloatingPortal7, { children: /* @__PURE__ */ jsx40(
|
|
3449
3499
|
"div",
|
|
3450
3500
|
{
|
|
3451
|
-
ref:
|
|
3501
|
+
ref: (node) => {
|
|
3502
|
+
refs.setFloating(node);
|
|
3503
|
+
listboxRef.current = node;
|
|
3504
|
+
},
|
|
3452
3505
|
id: listboxId,
|
|
3453
3506
|
role: "listbox",
|
|
3454
3507
|
"aria-multiselectable": multiple || void 0,
|
|
3455
3508
|
className: listbox,
|
|
3456
3509
|
style: floatingStyles,
|
|
3510
|
+
onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
|
|
3457
3511
|
...getFloatingProps(),
|
|
3458
|
-
children: loading ? /* @__PURE__ */ jsx40("div", { className: emptyState2, children: "Loading\u2026" }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx40("div", { className: emptyState2, children: noOptionsMessage }) :
|
|
3512
|
+
children: loading ? /* @__PURE__ */ jsx40("div", { className: emptyState2, children: "Loading\u2026" }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx40("div", { className: emptyState2, children: noOptionsMessage }) : isVirtualized ? /* @__PURE__ */ jsx40("div", { className: virtualSpacer, style: { height: totalHeight }, children: visibleOptions.map((opt, i) => {
|
|
3513
|
+
const index = startIndex + i;
|
|
3514
|
+
const isSelected = multiple ? selectedValues.includes(opt.value) : opt.value === singleValue;
|
|
3515
|
+
return /* @__PURE__ */ jsx40(
|
|
3516
|
+
"div",
|
|
3517
|
+
{
|
|
3518
|
+
id: `${listboxId}-option-${index}`,
|
|
3519
|
+
role: "option",
|
|
3520
|
+
"aria-selected": isSelected,
|
|
3521
|
+
"aria-disabled": opt.disabled || void 0,
|
|
3522
|
+
"data-active": activeIndex === index || void 0,
|
|
3523
|
+
className: option,
|
|
3524
|
+
style: { position: "absolute", top: index * optionHeight, left: 0, right: 0, height: optionHeight },
|
|
3525
|
+
onMouseDown: (event) => {
|
|
3526
|
+
event.preventDefault();
|
|
3527
|
+
selectOption(opt);
|
|
3528
|
+
},
|
|
3529
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
3530
|
+
children: opt.label
|
|
3531
|
+
},
|
|
3532
|
+
opt.value
|
|
3533
|
+
);
|
|
3534
|
+
}) }) : filteredOptions.map((opt, index) => {
|
|
3459
3535
|
const isSelected = multiple ? selectedValues.includes(opt.value) : opt.value === singleValue;
|
|
3460
3536
|
return /* @__PURE__ */ jsx40(
|
|
3461
3537
|
"div",
|
|
@@ -3581,8 +3657,8 @@ function TreeView({
|
|
|
3581
3657
|
const rowRefs = useRef10(/* @__PURE__ */ new Map());
|
|
3582
3658
|
const nodeIndex = useMemo4(() => {
|
|
3583
3659
|
const map = /* @__PURE__ */ new Map();
|
|
3584
|
-
function walk(
|
|
3585
|
-
for (const node of
|
|
3660
|
+
function walk(list5, parentId) {
|
|
3661
|
+
for (const node of list5) {
|
|
3586
3662
|
map.set(node.id, { node, parentId });
|
|
3587
3663
|
const children = getChildren(node, loadedChildren);
|
|
3588
3664
|
if (children) walk(children, node.id);
|
|
@@ -3593,8 +3669,8 @@ function TreeView({
|
|
|
3593
3669
|
}, [nodes, loadedChildren]);
|
|
3594
3670
|
const flatNodes = useMemo4(() => {
|
|
3595
3671
|
const result = [];
|
|
3596
|
-
function walk(
|
|
3597
|
-
for (const node of
|
|
3672
|
+
function walk(list5, depth) {
|
|
3673
|
+
for (const node of list5) {
|
|
3598
3674
|
const children = getChildren(node, loadedChildren);
|
|
3599
3675
|
const nodeHasChildren = children ? children.length > 0 : node.hasChildren === true;
|
|
3600
3676
|
const isExpanded = expandedSet.has(node.id);
|
|
@@ -3859,6 +3935,284 @@ function TreeView({
|
|
|
3859
3935
|
);
|
|
3860
3936
|
}
|
|
3861
3937
|
|
|
3938
|
+
// src/components/CommandPalette/CommandPalette.tsx
|
|
3939
|
+
import { useEffect as useEffect9, useId as useId3, useMemo as useMemo5, useRef as useRef11, useState as useState16 } from "react";
|
|
3940
|
+
import {
|
|
3941
|
+
FloatingFocusManager as FloatingFocusManager6,
|
|
3942
|
+
FloatingOverlay as FloatingOverlay2,
|
|
3943
|
+
FloatingPortal as FloatingPortal8,
|
|
3944
|
+
useDismiss as useDismiss8,
|
|
3945
|
+
useFloating as useFloating8,
|
|
3946
|
+
useInteractions as useInteractions8,
|
|
3947
|
+
useRole as useRole8
|
|
3948
|
+
} from "@floating-ui/react";
|
|
3949
|
+
|
|
3950
|
+
// src/components/CommandPalette/CommandPalette.css.ts
|
|
3951
|
+
var emptyState3 = "CommandPalette_emptyState__14otg5db";
|
|
3952
|
+
var groupHeader = "CommandPalette_groupHeader__14otg5d5";
|
|
3953
|
+
var inputEl2 = "CommandPalette_inputEl__14otg5d2";
|
|
3954
|
+
var list4 = "CommandPalette_list__14otg5d3";
|
|
3955
|
+
var option2 = "CommandPalette_option__14otg5d6";
|
|
3956
|
+
var optionDescription = "CommandPalette_optionDescription__14otg5d9";
|
|
3957
|
+
var optionIcon = "CommandPalette_optionIcon__14otg5d7";
|
|
3958
|
+
var optionLabel = "CommandPalette_optionLabel__14otg5d8";
|
|
3959
|
+
var overlay2 = "CommandPalette_overlay__14otg5d0";
|
|
3960
|
+
var palette = "CommandPalette_palette__14otg5d1";
|
|
3961
|
+
var shortcut = "CommandPalette_shortcut__14otg5da";
|
|
3962
|
+
var virtualSpacer2 = "CommandPalette_virtualSpacer__14otg5d4";
|
|
3963
|
+
|
|
3964
|
+
// src/components/CommandPalette/CommandPalette.tsx
|
|
3965
|
+
import { jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3966
|
+
var DEFAULT_ROW_HEIGHT = 40;
|
|
3967
|
+
var OVERSCAN2 = 5;
|
|
3968
|
+
function defaultFilterCommands(commands, query) {
|
|
3969
|
+
const q = query.trim().toLowerCase();
|
|
3970
|
+
if (!q) return commands;
|
|
3971
|
+
return commands.filter((command) => {
|
|
3972
|
+
const haystack = [command.label, command.group, ...command.keywords ?? []].filter(Boolean).join(" ").toLowerCase();
|
|
3973
|
+
return haystack.includes(q);
|
|
3974
|
+
});
|
|
3975
|
+
}
|
|
3976
|
+
function buildRows(commands) {
|
|
3977
|
+
const rows = [];
|
|
3978
|
+
const itemRowIndices = [];
|
|
3979
|
+
const seenGroups = /* @__PURE__ */ new Set();
|
|
3980
|
+
commands.forEach((command, itemIndex) => {
|
|
3981
|
+
if (command.group && !seenGroups.has(command.group)) {
|
|
3982
|
+
seenGroups.add(command.group);
|
|
3983
|
+
rows.push({ type: "header", key: `__group-${command.group}`, group: command.group });
|
|
3984
|
+
}
|
|
3985
|
+
itemRowIndices[itemIndex] = rows.length;
|
|
3986
|
+
rows.push({ type: "item", key: command.id, command, itemIndex });
|
|
3987
|
+
});
|
|
3988
|
+
return { rows, itemRowIndices };
|
|
3989
|
+
}
|
|
3990
|
+
function CommandPalette({
|
|
3991
|
+
open,
|
|
3992
|
+
onOpenChange,
|
|
3993
|
+
commands,
|
|
3994
|
+
placeholder = "Type a command or search...",
|
|
3995
|
+
emptyMessage = "No matching commands",
|
|
3996
|
+
filterCommands = defaultFilterCommands,
|
|
3997
|
+
virtualizationThreshold = 50,
|
|
3998
|
+
rowHeight = DEFAULT_ROW_HEIGHT,
|
|
3999
|
+
"aria-label": ariaLabel
|
|
4000
|
+
}) {
|
|
4001
|
+
const [query, setQuery] = useState16("");
|
|
4002
|
+
const [activeIndex, setActiveIndex] = useState16(null);
|
|
4003
|
+
const [scrollTop, setScrollTop] = useState16(0);
|
|
4004
|
+
const [viewportHeight, setViewportHeight] = useState16(320);
|
|
4005
|
+
const inputRef = useRef11(null);
|
|
4006
|
+
const listRef = useRef11(null);
|
|
4007
|
+
const listId = useId3();
|
|
4008
|
+
const { refs, context } = useFloating8({ open, onOpenChange });
|
|
4009
|
+
const { getFloatingProps } = useInteractions8([useDismiss8(context), useRole8(context, { role: "dialog" })]);
|
|
4010
|
+
const filteredCommands = useMemo5(() => filterCommands(commands, query), [commands, filterCommands, query]);
|
|
4011
|
+
const { rows, itemRowIndices } = useMemo5(() => buildRows(filteredCommands), [filteredCommands]);
|
|
4012
|
+
const isVirtualized = rows.length >= virtualizationThreshold;
|
|
4013
|
+
useEffect9(() => {
|
|
4014
|
+
if (!open) return;
|
|
4015
|
+
setQuery("");
|
|
4016
|
+
setActiveIndex(null);
|
|
4017
|
+
setScrollTop(0);
|
|
4018
|
+
if (listRef.current) listRef.current.scrollTop = 0;
|
|
4019
|
+
}, [open]);
|
|
4020
|
+
useEffect9(() => {
|
|
4021
|
+
setActiveIndex(null);
|
|
4022
|
+
setScrollTop(0);
|
|
4023
|
+
if (listRef.current) listRef.current.scrollTop = 0;
|
|
4024
|
+
}, [query]);
|
|
4025
|
+
useEffect9(() => {
|
|
4026
|
+
if (!open) return;
|
|
4027
|
+
const node = listRef.current;
|
|
4028
|
+
if (!node) return;
|
|
4029
|
+
if (node.clientHeight > 0) setViewportHeight(node.clientHeight);
|
|
4030
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
4031
|
+
const observer = new ResizeObserver((entries) => {
|
|
4032
|
+
const entry = entries[0];
|
|
4033
|
+
if (entry) setViewportHeight(entry.contentRect.height);
|
|
4034
|
+
});
|
|
4035
|
+
observer.observe(node);
|
|
4036
|
+
return () => observer.disconnect();
|
|
4037
|
+
}, [open]);
|
|
4038
|
+
if (!open) {
|
|
4039
|
+
return null;
|
|
4040
|
+
}
|
|
4041
|
+
const totalHeight = rows.length * rowHeight;
|
|
4042
|
+
const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
|
|
4043
|
+
const effectiveScrollTop = Math.min(scrollTop, maxScrollTop);
|
|
4044
|
+
const visibleCount = Math.ceil(viewportHeight / rowHeight) + OVERSCAN2 * 2;
|
|
4045
|
+
const startIndex = isVirtualized ? Math.max(0, Math.floor(effectiveScrollTop / rowHeight) - OVERSCAN2) : 0;
|
|
4046
|
+
const endIndex = isVirtualized ? Math.min(rows.length, startIndex + visibleCount) : rows.length;
|
|
4047
|
+
const visibleRows = rows.slice(startIndex, endIndex);
|
|
4048
|
+
const scrollRowIntoView = (rowIndex) => {
|
|
4049
|
+
if (!isVirtualized) return;
|
|
4050
|
+
const rowTop = rowIndex * rowHeight;
|
|
4051
|
+
const rowBottom = rowTop + rowHeight;
|
|
4052
|
+
let next = scrollTop;
|
|
4053
|
+
if (rowTop < scrollTop) {
|
|
4054
|
+
next = rowTop;
|
|
4055
|
+
} else if (rowBottom > scrollTop + viewportHeight) {
|
|
4056
|
+
next = rowBottom - viewportHeight;
|
|
4057
|
+
} else {
|
|
4058
|
+
return;
|
|
4059
|
+
}
|
|
4060
|
+
setScrollTop(next);
|
|
4061
|
+
if (listRef.current) listRef.current.scrollTop = next;
|
|
4062
|
+
};
|
|
4063
|
+
const moveActiveIndex = (direction2) => {
|
|
4064
|
+
if (filteredCommands.length === 0) return;
|
|
4065
|
+
let next = activeIndex ?? (direction2 === 1 ? -1 : filteredCommands.length);
|
|
4066
|
+
for (let step = 0; step < filteredCommands.length; step++) {
|
|
4067
|
+
next = (next + direction2 + filteredCommands.length) % filteredCommands.length;
|
|
4068
|
+
if (!filteredCommands[next]?.disabled) {
|
|
4069
|
+
setActiveIndex(next);
|
|
4070
|
+
const rowIndex = itemRowIndices[next];
|
|
4071
|
+
if (rowIndex !== void 0) scrollRowIntoView(rowIndex);
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
};
|
|
4076
|
+
const selectCommand = (command) => {
|
|
4077
|
+
if (command.disabled) return;
|
|
4078
|
+
command.onSelect();
|
|
4079
|
+
onOpenChange(false);
|
|
4080
|
+
};
|
|
4081
|
+
const handleKeyDown = (event) => {
|
|
4082
|
+
switch (event.key) {
|
|
4083
|
+
case "ArrowDown":
|
|
4084
|
+
event.preventDefault();
|
|
4085
|
+
moveActiveIndex(1);
|
|
4086
|
+
return;
|
|
4087
|
+
case "ArrowUp":
|
|
4088
|
+
event.preventDefault();
|
|
4089
|
+
moveActiveIndex(-1);
|
|
4090
|
+
return;
|
|
4091
|
+
case "Enter": {
|
|
4092
|
+
event.preventDefault();
|
|
4093
|
+
const active = activeIndex !== null ? filteredCommands[activeIndex] : void 0;
|
|
4094
|
+
if (active) selectCommand(active);
|
|
4095
|
+
return;
|
|
4096
|
+
}
|
|
4097
|
+
case "Escape":
|
|
4098
|
+
event.preventDefault();
|
|
4099
|
+
onOpenChange(false);
|
|
4100
|
+
return;
|
|
4101
|
+
default:
|
|
4102
|
+
}
|
|
4103
|
+
};
|
|
4104
|
+
const activeCommand = activeIndex !== null ? filteredCommands[activeIndex] : void 0;
|
|
4105
|
+
const activeOptionId = activeCommand ? `${listId}-option-${activeCommand.id}` : void 0;
|
|
4106
|
+
const renderRow = (row3, rowIndex, rowStyle) => {
|
|
4107
|
+
if (row3.type === "header") {
|
|
4108
|
+
return /* @__PURE__ */ jsx42("div", { role: "presentation", className: groupHeader, style: rowStyle, children: row3.group }, row3.key);
|
|
4109
|
+
}
|
|
4110
|
+
const { command, itemIndex } = row3;
|
|
4111
|
+
const isActive = itemIndex === activeIndex;
|
|
4112
|
+
return /* @__PURE__ */ jsxs25(
|
|
4113
|
+
"div",
|
|
4114
|
+
{
|
|
4115
|
+
id: `${listId}-option-${command.id}`,
|
|
4116
|
+
role: "option",
|
|
4117
|
+
"aria-selected": isActive,
|
|
4118
|
+
"aria-disabled": command.disabled || void 0,
|
|
4119
|
+
"data-active": isActive || void 0,
|
|
4120
|
+
className: option2,
|
|
4121
|
+
style: rowStyle,
|
|
4122
|
+
onMouseDown: (event) => {
|
|
4123
|
+
event.preventDefault();
|
|
4124
|
+
selectCommand(command);
|
|
4125
|
+
},
|
|
4126
|
+
onMouseEnter: () => {
|
|
4127
|
+
if (!command.disabled) setActiveIndex(itemIndex);
|
|
4128
|
+
},
|
|
4129
|
+
children: [
|
|
4130
|
+
command.icon ? /* @__PURE__ */ jsx42("span", { className: optionIcon, children: command.icon }) : null,
|
|
4131
|
+
/* @__PURE__ */ jsxs25("span", { className: optionLabel, children: [
|
|
4132
|
+
command.label,
|
|
4133
|
+
command.description ? /* @__PURE__ */ jsx42("span", { className: optionDescription, children: command.description }) : null
|
|
4134
|
+
] }),
|
|
4135
|
+
command.shortcut ? /* @__PURE__ */ jsx42("span", { className: shortcut, children: command.shortcut }) : null
|
|
4136
|
+
]
|
|
4137
|
+
},
|
|
4138
|
+
row3.key
|
|
4139
|
+
);
|
|
4140
|
+
};
|
|
4141
|
+
return /* @__PURE__ */ jsx42(FloatingPortal8, { children: /* @__PURE__ */ jsx42(FloatingOverlay2, { className: overlay2, lockScroll: true, children: /* @__PURE__ */ jsx42(FloatingFocusManager6, { context, initialFocus: inputRef, children: /* @__PURE__ */ jsxs25(
|
|
4142
|
+
"div",
|
|
4143
|
+
{
|
|
4144
|
+
ref: refs.setFloating,
|
|
4145
|
+
className: palette,
|
|
4146
|
+
"aria-label": ariaLabel ?? "Command palette",
|
|
4147
|
+
...getFloatingProps(),
|
|
4148
|
+
children: [
|
|
4149
|
+
/* @__PURE__ */ jsx42(
|
|
4150
|
+
"input",
|
|
4151
|
+
{
|
|
4152
|
+
ref: inputRef,
|
|
4153
|
+
type: "text",
|
|
4154
|
+
role: "combobox",
|
|
4155
|
+
className: inputEl2,
|
|
4156
|
+
value: query,
|
|
4157
|
+
placeholder,
|
|
4158
|
+
autoComplete: "off",
|
|
4159
|
+
"aria-autocomplete": "list",
|
|
4160
|
+
"aria-expanded": true,
|
|
4161
|
+
"aria-controls": listId,
|
|
4162
|
+
"aria-activedescendant": activeOptionId,
|
|
4163
|
+
onChange: (event) => setQuery(event.target.value),
|
|
4164
|
+
onKeyDown: handleKeyDown
|
|
4165
|
+
}
|
|
4166
|
+
),
|
|
4167
|
+
/* @__PURE__ */ jsx42(
|
|
4168
|
+
"div",
|
|
4169
|
+
{
|
|
4170
|
+
ref: listRef,
|
|
4171
|
+
id: listId,
|
|
4172
|
+
role: "listbox",
|
|
4173
|
+
className: list4,
|
|
4174
|
+
onScroll: (event) => setScrollTop(event.currentTarget.scrollTop),
|
|
4175
|
+
children: filteredCommands.length === 0 ? /* @__PURE__ */ jsx42("div", { className: emptyState3, children: emptyMessage }) : isVirtualized ? /* @__PURE__ */ jsx42("div", { className: virtualSpacer2, style: { height: totalHeight }, children: visibleRows.map((row3, i) => {
|
|
4176
|
+
const rowIndex = startIndex + i;
|
|
4177
|
+
return renderRow(row3, rowIndex, {
|
|
4178
|
+
position: "absolute",
|
|
4179
|
+
top: rowIndex * rowHeight,
|
|
4180
|
+
left: 0,
|
|
4181
|
+
right: 0,
|
|
4182
|
+
height: rowHeight
|
|
4183
|
+
});
|
|
4184
|
+
}) }) : rows.map((row3, rowIndex) => renderRow(row3, rowIndex))
|
|
4185
|
+
}
|
|
4186
|
+
)
|
|
4187
|
+
]
|
|
4188
|
+
}
|
|
4189
|
+
) }) }) });
|
|
4190
|
+
}
|
|
4191
|
+
|
|
4192
|
+
// src/components/CommandPalette/useCommandPaletteShortcut.ts
|
|
4193
|
+
import { useEffect as useEffect10 } from "react";
|
|
4194
|
+
function isMac() {
|
|
4195
|
+
if (typeof navigator === "undefined") return false;
|
|
4196
|
+
return /Mac|iPhone|iPad|iPod/.test(navigator.platform ?? navigator.userAgent ?? "");
|
|
4197
|
+
}
|
|
4198
|
+
function useCommandPaletteShortcut(onOpenChange, options = {}) {
|
|
4199
|
+
const { key = "k", metaKey, ctrlKey } = options;
|
|
4200
|
+
useEffect10(() => {
|
|
4201
|
+
const explicit = metaKey !== void 0 || ctrlKey !== void 0;
|
|
4202
|
+
const useMeta = explicit ? Boolean(metaKey) : isMac();
|
|
4203
|
+
const useCtrl = explicit ? Boolean(ctrlKey) : !isMac();
|
|
4204
|
+
const handleKeyDown = (event) => {
|
|
4205
|
+
if (event.key.toLowerCase() !== key.toLowerCase()) return;
|
|
4206
|
+
if (event.metaKey !== useMeta) return;
|
|
4207
|
+
if (event.ctrlKey !== useCtrl) return;
|
|
4208
|
+
event.preventDefault();
|
|
4209
|
+
onOpenChange(true);
|
|
4210
|
+
};
|
|
4211
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
4212
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
4213
|
+
}, [onOpenChange, key, metaKey, ctrlKey]);
|
|
4214
|
+
}
|
|
4215
|
+
|
|
3862
4216
|
// src/index.ts
|
|
3863
4217
|
import { vars as vars3, defaultThemeClass, defaultThemeVars } from "@vesture/tokens";
|
|
3864
4218
|
export {
|
|
@@ -3876,6 +4230,7 @@ export {
|
|
|
3876
4230
|
Card,
|
|
3877
4231
|
Checkbox,
|
|
3878
4232
|
Combobox,
|
|
4233
|
+
CommandPalette,
|
|
3879
4234
|
DataGrid,
|
|
3880
4235
|
DatePicker,
|
|
3881
4236
|
DateRangePicker,
|
|
@@ -3905,6 +4260,7 @@ export {
|
|
|
3905
4260
|
TreeView,
|
|
3906
4261
|
defaultThemeClass,
|
|
3907
4262
|
defaultThemeVars,
|
|
4263
|
+
useCommandPaletteShortcut,
|
|
3908
4264
|
useToast,
|
|
3909
4265
|
vars3 as vars
|
|
3910
4266
|
};
|