This PR fixes the issue about the easy fast follow-up part on advanced filter. Fixes https://github.com/twentyhq/core-team-issues/issues/675 Changes : - Changed horizontal gap to spacing(1) for AdvancedFilterDropdownRow - Created a DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET for all sub-dropdowns in advanced filter dropdown with a y-offset of 2px. - Created a DropdownOffset type - Used a padding-left of spacing(2.25) in AdvancedFilterLogicalOperatorCell to allign the disabled text with the text in the Select component - Added IconTrash and accent danger on AdvancedFilterRecordFilterGroupOptionsDropdown and AdvancedFilterRecordFilterOptionsDropdown - Removed unnecessary CSS properties on AdvancedFilterRootRecordFilterGroup - Set dropdownMenuWith to 280 for AdvancedFilterValueInputDropdownButton - Fixed Dropdown generic clickable component container that was expanding - Set IconFilter instead of IconFilterCog in AdvancedFilterChip - Set AdvancedFilterDropdownButton dropdown content width to 650 instead of 800 - Refactored generic IconButton component so that it disambiguates secondary and tertiary variant for the color CSS props
171 lines
5.1 KiB
TypeScript
171 lines
5.1 KiB
TypeScript
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
|
import { DropdownOnToggleEffect } from '@/ui/layout/dropdown/components/DropdownOnToggleEffect';
|
|
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
|
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
|
import { dropdownHotkeyComponentState } from '@/ui/layout/dropdown/states/dropdownHotkeyComponentState';
|
|
import { DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
|
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
|
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
|
import styled from '@emotion/styled';
|
|
import {
|
|
Placement,
|
|
autoUpdate,
|
|
flip,
|
|
offset,
|
|
size,
|
|
useFloating,
|
|
} from '@floating-ui/react';
|
|
import { MouseEvent, ReactNode } from 'react';
|
|
import { flushSync } from 'react-dom';
|
|
import { Keys } from 'react-hotkeys-hook';
|
|
import { useRecoilCallback } from 'recoil';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import { sleep } from '~/utils/sleep';
|
|
import { useDropdown } from '../hooks/useDropdown';
|
|
|
|
const StyledDropdownFallbackAnchor = styled.div`
|
|
left: 0;
|
|
position: fixed;
|
|
top: 0;
|
|
`;
|
|
|
|
const StyledClickableComponent = styled.div`
|
|
height: fit-content;
|
|
`;
|
|
|
|
export type DropdownProps = {
|
|
className?: string;
|
|
clickableComponent?: ReactNode;
|
|
dropdownComponents: ReactNode;
|
|
hotkey?: {
|
|
key: Keys;
|
|
scope: string;
|
|
};
|
|
dropdownHotkeyScope: HotkeyScope;
|
|
dropdownId: string;
|
|
dropdownPlacement?: Placement;
|
|
dropdownMenuWidth?: `${string}px` | `${number}%` | 'auto' | number;
|
|
dropdownOffset?: DropdownOffset;
|
|
dropdownStrategy?: 'fixed' | 'absolute';
|
|
onClickOutside?: () => void;
|
|
onClose?: () => void;
|
|
onOpen?: () => void;
|
|
avoidPortal?: boolean;
|
|
};
|
|
|
|
export const Dropdown = ({
|
|
className,
|
|
clickableComponent,
|
|
dropdownComponents,
|
|
dropdownMenuWidth,
|
|
hotkey,
|
|
dropdownId,
|
|
dropdownHotkeyScope,
|
|
dropdownPlacement = 'bottom-end',
|
|
dropdownStrategy = 'absolute',
|
|
dropdownOffset,
|
|
onClickOutside,
|
|
onClose,
|
|
onOpen,
|
|
avoidPortal,
|
|
}: DropdownProps) => {
|
|
const { isDropdownOpen, toggleDropdown } = useDropdown(dropdownId);
|
|
|
|
const isUsingOffset =
|
|
isDefined(dropdownOffset?.x) || isDefined(dropdownOffset?.y);
|
|
|
|
const offsetMiddleware = isUsingOffset
|
|
? [
|
|
offset({
|
|
crossAxis: dropdownOffset?.x ?? 0,
|
|
mainAxis: dropdownOffset?.y ?? 0,
|
|
}),
|
|
]
|
|
: [];
|
|
|
|
const { refs, floatingStyles, placement } = useFloating({
|
|
placement: dropdownPlacement,
|
|
middleware: [
|
|
...offsetMiddleware,
|
|
flip(),
|
|
size({
|
|
padding: 32,
|
|
apply: () => {
|
|
flushSync(() => {
|
|
// TODO: I think this is not needed anymore let's remove it if not used for a few weeks
|
|
// setDropdownMaxHeight(availableHeight);
|
|
});
|
|
},
|
|
boundary: document.querySelector('#root') ?? undefined,
|
|
}),
|
|
],
|
|
whileElementsMounted: autoUpdate,
|
|
strategy: dropdownStrategy,
|
|
});
|
|
|
|
const handleClickableComponentClick = useRecoilCallback(
|
|
({ set }) =>
|
|
async (event: MouseEvent) => {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
|
|
// TODO: refactor this when we have finished dropdown refactor with state and V1 + V2
|
|
set(
|
|
dropdownHotkeyComponentState({ scopeId: dropdownId }),
|
|
dropdownHotkeyScope,
|
|
);
|
|
|
|
await sleep(100);
|
|
|
|
toggleDropdown();
|
|
onClickOutside?.();
|
|
},
|
|
[dropdownId, dropdownHotkeyScope, onClickOutside, toggleDropdown],
|
|
);
|
|
|
|
return (
|
|
<DropdownComponentInstanceContext.Provider
|
|
value={{ instanceId: dropdownId }}
|
|
>
|
|
<DropdownScope dropdownScopeId={getScopeIdFromComponentId(dropdownId)}>
|
|
<>
|
|
{isDefined(clickableComponent) ? (
|
|
<StyledClickableComponent
|
|
ref={refs.setReference}
|
|
onClick={handleClickableComponentClick}
|
|
aria-controls={`${dropdownId}-options`}
|
|
aria-expanded={isDropdownOpen}
|
|
aria-haspopup={true}
|
|
role="button"
|
|
>
|
|
{clickableComponent}
|
|
</StyledClickableComponent>
|
|
) : (
|
|
<StyledDropdownFallbackAnchor ref={refs.setReference} />
|
|
)}
|
|
{isDropdownOpen && (
|
|
<DropdownContent
|
|
className={className}
|
|
floatingStyles={floatingStyles}
|
|
dropdownMenuWidth={dropdownMenuWidth}
|
|
dropdownComponents={dropdownComponents}
|
|
dropdownId={dropdownId}
|
|
dropdownPlacement={placement}
|
|
floatingUiRefs={refs}
|
|
hotkeyScope={dropdownHotkeyScope}
|
|
hotkey={hotkey}
|
|
onClickOutside={onClickOutside}
|
|
onHotkeyTriggered={toggleDropdown}
|
|
avoidPortal={avoidPortal}
|
|
/>
|
|
)}
|
|
<DropdownOnToggleEffect
|
|
onDropdownClose={onClose}
|
|
onDropdownOpen={onOpen}
|
|
/>
|
|
</>
|
|
</DropdownScope>
|
|
</DropdownComponentInstanceContext.Provider>
|
|
);
|
|
};
|