@adaptabletools/adaptable
Version:
Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
127 lines (126 loc) • 13.7 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from 'react';
import { Combobox as ComboboxPrimitive } from '@base-ui/react';
import { cn, POPUP_Z_INDEX } from '../../lib/utils';
import { Button } from './button';
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from './input-group';
import { CheckIcon, ChevronDownIcon, XIcon, Loader2Icon } from 'lucide-react';
import { CheckBox } from '../CheckBox';
const useFilteredItems = ComboboxPrimitive.useFilteredItems;
export { useFilteredItems, ComboboxPrimitive };
const Combobox = ComboboxPrimitive.Root;
const RESIZABLE_LIST_CLASS = 'twa:group-data-resizable/combobox-content:max-h-none twa:group-data-resizable/combobox-content:flex-1 twa:group-data-resizable/combobox-content:min-h-0';
const RESIZABLE_VIRTUALIZED_LIST_CLASS = `${RESIZABLE_LIST_CLASS} twa:group-data-resizable/combobox-content:flex twa:group-data-resizable/combobox-content:flex-col`;
const RESIZABLE_VIRTUALIZED_SCROLL_CLASS = 'twa:group-data-resizable/combobox-content:h-auto twa:group-data-resizable/combobox-content:max-h-none twa:group-data-resizable/combobox-content:flex-1 twa:group-data-resizable/combobox-content:min-h-0';
function ComboboxValue({ ...props }) {
return _jsx(ComboboxPrimitive.Value, { "data-slot": "combobox-value", ...props });
}
const ComboboxTrigger = React.forwardRef(function ComboboxTrigger({ className, children, icon, ...props }, ref) {
return (_jsxs(ComboboxPrimitive.Trigger, { "data-slot": "combobox-trigger", className: cn('twa:[&_svg:not([class*=size-])]:size-4', className), ref: ref, ...props, children: [children, icon !== undefined ? (icon) : (_jsx(ChevronDownIcon, { className: "twa:pointer-events-none twa:size-4 twa:text-muted-foreground" }))] }));
});
export const ComboboxClear = React.forwardRef(function ComboboxClear({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.Clear, { "data-slot": "combobox-clear", render: _jsx(InputGroupButton, { variant: "ghost", size: "icon-xs", className: "twa:min-h-auto!" }), className: className, ref: ref, ...props, children: _jsx(XIcon, { className: "twa:pointer-events-none", strokeWidth: 1 }) }));
});
const ComboboxInput = React.forwardRef(function ComboboxInput({ className, children, disabled = false, isLoading = false, showTrigger = true, showClear = false, groupRef, ...props }, ref) {
const { 'aria-label': ariaLabel, ...rest } = props;
return (_jsxs(InputGroup, { ref: groupRef, className: cn('twa:w-auto', className), "aria-label": ariaLabel, children: [_jsx(ComboboxPrimitive.Input, { ref: ref, render: _jsx(InputGroupInput, { disabled: disabled }), ...rest }), _jsxs(InputGroupAddon, { align: "inline-end", children: [isLoading && (_jsx(Loader2Icon, { className: "twa:size-4 twa:text-muted-foreground twa:animate-spin" })), showTrigger && (_jsx(InputGroupButton, { size: "icon-xs", variant: "ghost", render: _jsx(ComboboxTrigger, {}), "data-slot": "combobox-toggle", className: "twa:group-has-data-[slot=combobox-clear]/input-group:hidden twa:data-pressed:bg-transparent twa:min-h-auto!", disabled: disabled })), showClear && _jsx(ComboboxClear, { disabled: disabled })] }), children] }));
});
function ComboboxContent({ className, side = 'bottom', sideOffset = 6, align = 'start', alignOffset = 0, anchor, resizable = false, contentRef, style, ...props }) {
const [userSize, setUserSize] = React.useState(null);
const styleObject = typeof style === 'function' ? undefined : style;
const expectedSizeRef = React.useRef({});
expectedSizeRef.current = {
width: userSize?.width ?? styleObject?.width,
height: userSize?.height ?? styleObject?.height,
};
const styleObserverRef = React.useRef(null);
const pendingUserSizeRef = React.useRef(null);
const pinTimerRef = React.useRef(null);
const flushPendingUserSize = React.useCallback(() => {
if (pinTimerRef.current) {
clearTimeout(pinTimerRef.current);
pinTimerRef.current = null;
}
if (pendingUserSizeRef.current) {
setUserSize(pendingUserSizeRef.current);
pendingUserSizeRef.current = null;
}
}, []);
const popupRef = React.useCallback((el) => {
styleObserverRef.current?.disconnect();
styleObserverRef.current = null;
if (!el) {
flushPendingUserSize();
}
contentRef?.(el);
if (el && resizable) {
const observer = new MutationObserver(() => {
const { width, height } = el.style;
const expected = expectedSizeRef.current;
const isUserSize = (actual, expectedValue) => !!actual && actual !== expectedValue && actual.endsWith('px');
if (!isUserSize(width, expected.width) && !isUserSize(height, expected.height)) {
return;
}
pendingUserSizeRef.current = {
width: width || `${el.offsetWidth}px`,
height: height || `${el.offsetHeight}px`,
};
if (pinTimerRef.current) {
clearTimeout(pinTimerRef.current);
}
pinTimerRef.current = setTimeout(flushPendingUserSize, 150);
});
observer.observe(el, { attributes: true, attributeFilter: ['style'] });
styleObserverRef.current = observer;
}
}, [resizable, contentRef, flushPendingUserSize]);
const resizableStyle = resizable
? { resize: 'both' }
: undefined;
return (_jsx(ComboboxPrimitive.Portal, { children: _jsx(ComboboxPrimitive.Positioner, { side: side, sideOffset: sideOffset, align: align, alignOffset: alignOffset, anchor: anchor, className: `twa:isolate ${POPUP_Z_INDEX}`, children: _jsx(ComboboxPrimitive.Popup, { ref: popupRef, "data-slot": "combobox-content", "data-chips": !!anchor, "data-resizable": resizable || undefined, style: { ...resizableStyle, ...styleObject, ...userSize }, className: cn('twa:group/combobox-content twa:relative twa:origin-(--transform-origin) twa:overflow-hidden twa:rounded-input twa:bg-popover twa:text-popover-foreground twa:shadow-md twa:ring-1 twa:ring-foreground/10 twa:duration-100 twa:data-[side=bottom]:slide-in-from-top-2 twa:data-[side=inline-end]:slide-in-from-left-2 twa:data-[side=inline-start]:slide-in-from-right-2 twa:data-[side=left]:slide-in-from-right-2 twa:data-[side=right]:slide-in-from-left-2 twa:data-[side=top]:slide-in-from-bottom-2 twa:*:data-[slot=input-group]:m-1 twa:*:data-[slot=input-group]:mb-0 twa:*:data-[slot=input-group]:h-8 twa:*:data-[slot=input-group]:border-input/30 twa:*:data-[slot=input-group]:bg-input/30 twa:*:data-[slot=input-group]:shadow-none twa:data-open:animate-in twa:data-open:fade-in-0 twa:data-open:zoom-in-95 twa:data-closed:animate-out twa:data-closed:fade-out-0 twa:data-closed:zoom-out-95', 'twa:max-h-[min(var(--available-height,80vh),80vh)]', 'twa:max-w-[min(var(--available-width,80vw),80vw)]', 'twa:min-w-[min(calc(var(--anchor-width)+--spacing(7)),var(--available-width),80vw)]', resizable ? 'twa:flex twa:flex-col twa:min-h-24' : 'twa:w-(--anchor-width)', className), ...props }) }) }));
}
const ComboboxList = React.forwardRef(function ComboboxList({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.List, { "data-slot": "combobox-list", className: cn('twa:no-scrollbar twa:max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] twa:scroll-py-1 twa:overflow-y-auto twa:overscroll-contain twa:p-1 twa:data-empty:p-0', RESIZABLE_LIST_CLASS, className), ref: ref, ...props }));
});
const checkboxIndicatorRender = (props, state) => {
const clsForSquare = state.selected ? 'twa:ring-1 twa:ring-accent-foreground' : '';
return (_jsx(CheckBox, { checked: state.selected, tabIndex: -1, checkSquareClassName: clsForSquare, className: "twa:p-0 twa:m-0 twa:cursor-pointer" }));
};
const ComboboxItem = React.forwardRef(function ComboboxItem({ className, children, renderCheckboxIndicator, ...props }, ref) {
return (_jsxs(ComboboxPrimitive.Item, { ref: ref, className: cn('twa:relative twa:flex twa:w-full twa:cursor-default twa:items-center twa:gap-2 twa:rounded-input twa:py-1.5 twa:pl-2 twa:text-sm twa:outline-hidden twa:select-none twa:data-highlighted:bg-accent twa:data-highlighted:text-accent-foreground twa:not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground twa:data-disabled:pointer-events-none twa:data-disabled:opacity-50 twa:[&_svg]:pointer-events-none twa:[&_svg]:shrink-0 twa:[&_svg:not([class*=size-])]:size-4', 'twa:cursor-pointer', renderCheckboxIndicator ? 'twa:pr-2' : 'twa:pr-8', className), ...props, "data-slot": "combobox-item", children: [renderCheckboxIndicator ? (_jsx(ComboboxPrimitive.ItemIndicator, { keepMounted: true, render: renderCheckboxIndicator === true ? checkboxIndicatorRender : renderCheckboxIndicator })) : null, children, !renderCheckboxIndicator && (_jsx(ComboboxPrimitive.ItemIndicator, { render: _jsx("span", { className: "twa:pointer-events-none twa:absolute twa:right-2 twa:flex twa:size-4 twa:items-center twa:justify-center" }), children: _jsx(CheckIcon, { className: "twa:pointer-events-none" }) }))] }));
});
const ComboboxGroup = React.forwardRef(function ComboboxGroup({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.Group, { "data-slot": "combobox-group", className: cn(className), ref: ref, ...props }));
});
const ComboboxLabel = React.forwardRef(function ComboboxLabel({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.GroupLabel, { "data-slot": "combobox-label", className: cn('twa:px-2 twa:py-1.5 twa:text-xs twa:text-muted-foreground', className), ref: ref, ...props }));
});
function ComboboxCollection({ ...props }) {
return _jsx(ComboboxPrimitive.Collection, { "data-slot": "combobox-collection", ...props });
}
const ComboboxEmpty = React.forwardRef(function ComboboxEmpty({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.Empty, { "data-slot": "combobox-empty", className: cn('twa:hidden twa:w-full twa:justify-center twa:py-2 twa:text-center twa:text-sm twa:text-muted-foreground twa:group-data-empty/combobox-content:flex', className), ref: ref, ...props }));
});
const ComboboxSeparator = React.forwardRef(function ComboboxSeparator({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.Separator, { "data-slot": "combobox-separator", className: cn('twa:-mx-1 twa:my-1 twa:h-px twa:bg-border', className), ref: ref, ...props }));
});
const ComboboxChips = React.forwardRef(function ComboboxChips({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.Chips, { "data-slot": "combobox-chips", className: cn('twa:focus-within:outline-none', 'twa:flex twa:flex-wrap twa:items-center twa:gap-1.5 twa:rounded-input twa:border twa:border-input twa:bg-input-background twa:bg-clip-padding twa:text-sm twa:shadow-xs twa:transition-[color,box-shadow] twa:focus-within:border-ring twa:focus-within:ring-3 twa:focus-within:ring-ring/50 twa:has-aria-invalid:border-destructive twa:has-aria-invalid:ring-3 twa:has-aria-invalid:ring-destructive/20 twa:has-data-[slot=combobox-chip]:px-1.5 twa:dark:has-aria-invalid:border-destructive/50 twa:dark:has-aria-invalid:ring-destructive/40', 'twa:py-1', 'twa:px-2.5', 'twa:min-h-input', 'twa:[&>input]:max-h-[calc(var(--ab-input-height)-1.5*var(--ab-base-space))]!', className), ref: ref, ...props }));
});
const ComboboxChip = React.forwardRef(function ComboboxChip({ className, children, showRemove = true, onRemove, ...props }, ref) {
return (_jsxs(ComboboxPrimitive.Chip, { ref: ref, "data-slot": "combobox-chip", className: cn('twa:flex twa:h-[calc(--spacing(5.5))] twa:w-fit twa:items-center twa:justify-center twa:gap-1 twa:rounded-input twa:bg-muted twa:px-1.5 twa:text-xs twa:font-medium twa:whitespace-nowrap twa:text-input-foreground twa:has-disabled:pointer-events-none twa:has-disabled:cursor-not-allowed twa:has-disabled:opacity-50 twa:has-data-[slot=combobox-chip-remove]:pr-0', className), ...props, children: [children, showRemove &&
(onRemove ? (_jsx(Button, { type: "button", variant: "ghost", size: "icon-xs", tabIndex: -1, "data-slot": "combobox-chip-remove", className: "twa:-ml-1 twa:opacity-50 twa:hover:opacity-100", onMouseDown: (e) => {
e.preventDefault();
e.stopPropagation();
}, onClick: (e) => {
e.stopPropagation();
onRemove(e);
}, children: _jsx(XIcon, { className: "twa:pointer-events-none" }) })) : (_jsx(ComboboxPrimitive.ChipRemove, { render: _jsx(Button, { variant: "ghost", size: "icon-xs" }), className: "twa:-ml-1 twa:opacity-50 twa:hover:opacity-100", "data-slot": "combobox-chip-remove", children: _jsx(XIcon, { className: "twa:pointer-events-none" }) })))] }));
});
const ComboboxChipsInput = React.forwardRef(function ComboboxChipsInput({ className, ...props }, ref) {
return (_jsx(ComboboxPrimitive.Input, { "data-slot": "combobox-chip-input", className: cn('twa:placeholder:text-muted-foreground twa:min-w-16 twa:flex-1 twa:px-2.5 twa:outline-none twa:border-none twa:bg-transparent twa:min-h-auto!', className), ref: ref, ...props }));
});
function useComboboxAnchor() {
return React.useRef(null);
}
export { Combobox, ComboboxInput, ComboboxContent, ComboboxList, ComboboxItem, ComboboxGroup, ComboboxLabel, ComboboxCollection, ComboboxEmpty, ComboboxSeparator, ComboboxChips, ComboboxChip, ComboboxChipsInput, ComboboxTrigger, ComboboxValue, useComboboxAnchor, RESIZABLE_VIRTUALIZED_LIST_CLASS, RESIZABLE_VIRTUALIZED_SCROLL_CLASS, };