UNPKG

@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
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, };