mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-22 19:41:53 +03:00
Fixed dropdown blur and unified components (#9062)
- Removed disableBlur property from dropdown because it is no longer needed since there's only one OverlayContainer component so there can be only one blur at a time. - Removed blur CSS properties from every component that used it because one standalone OverlayContainer is able to handle all cases if placed properly. - Also removed disableBackgroundBlur property from SingleRecordSelect - Removed FieldInputOverlay and FieldTextAreaOverlay components that were a first attempt to create something like an OverlayContainer - Used new unified OverlayContainer in RecordInlineCell and RecordTableCell - Fixed ScrollWrapper so that it works well both for dropdown with non overflowing content and dropdown with overflowing content. - Removed export default value on SearchVariablesDropdown as it is not used in this codebase - Refactored SearchVariablesDropdown function as component anti-pattern - Refactored SearchVariablesDropdownFieldItems UI problems with separator and missing ScrollWrapper behavior - Refactored SearchVariablesDropdownObjectItems with UI problems with separator and missing ScrollWrapper behavior - Fixed blur bug on Firefox due to wrong placement of the element that had the CSS property. Blur works on Firefox it it's on the container that has the highest level in the tree. - Fixed bug in ActivityTargetInlineCell by removing an unnecessary container component StyledSelectContainer - Unified problems of field height with a new common component FieldInputContainer, instead of putting width and height at the wrong abstraction level, width and height are a field's concern not a dropdown, overlay or low-level input concern. - Fixed block editor dropdown with new OverlayContainer - Aligning field dropdown with their anchor on inline and table cells, there are still many small pixel misalignments that give a low quality impression. - Fixed FormDateFieldInput that was missing OverlayContainer
This commit is contained in:
parent
4aabe9e224
commit
860dec3428
@ -1,4 +1,3 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { isNull } from '@sniptt/guards';
|
||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
@ -32,12 +31,6 @@ import { MultiRecordSelect } from '@/object-record/relation-picker/components/Mu
|
||||
import { RecordPickerComponentInstanceContext } from '@/object-record/relation-picker/states/contexts/RecordPickerComponentInstanceContext';
|
||||
import { prefillRecord } from '@/object-record/utils/prefillRecord';
|
||||
|
||||
const StyledSelectContainer = styled.div`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
`;
|
||||
|
||||
type ActivityTargetInlineCellEditModeProps = {
|
||||
activity: Task | Note;
|
||||
activityTargetWithTargetRecords: ActivityTargetWithTargetRecord[];
|
||||
@ -282,7 +275,7 @@ export const ActivityTargetInlineCellEditMode = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledSelectContainer>
|
||||
<>
|
||||
<RecordPickerComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordPickerInstanceId }}
|
||||
>
|
||||
@ -295,6 +288,6 @@ export const ActivityTargetInlineCellEditMode = ({
|
||||
<ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect />
|
||||
<MultiRecordSelect onSubmit={handleSubmit} onChange={handleChange} />
|
||||
</RecordPickerComponentInstanceContext.Provider>
|
||||
</StyledSelectContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -137,7 +137,6 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
disableBlur
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<LightButton Icon={IconPlus} title="Add filter rule" />
|
||||
|
@ -22,7 +22,6 @@ export const AdvancedFilterLogicalOperatorDropdown = ({
|
||||
|
||||
return (
|
||||
<Select
|
||||
disableBlur
|
||||
fullWidth
|
||||
dropdownId={`advanced-filter-logical-operator-${viewFilterGroup.id}`}
|
||||
value={viewFilterGroup.logicalOperator}
|
||||
|
@ -68,7 +68,6 @@ export const AdvancedFilterRuleOptionsDropdown = ({
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
disableBlur
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<AdvancedFilterRuleOptionsDropdownButton dropdownId={dropdownId} />
|
||||
|
@ -41,7 +41,6 @@ export const AdvancedFilterViewFilterFieldSelect = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
<Dropdown
|
||||
disableBlur
|
||||
dropdownId={advancedFilterDropdownId}
|
||||
clickableComponent={
|
||||
<SelectControl
|
||||
|
@ -76,7 +76,6 @@ export const AdvancedFilterViewFilterOperandSelect = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
<Dropdown
|
||||
disableBlur
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<SelectControl
|
||||
|
@ -39,7 +39,6 @@ export const AdvancedFilterViewFilterValueInput = ({
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
disableBlur
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<SelectControl
|
||||
|
@ -98,7 +98,7 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
{/** TODO: Should be removed when view settings contains more options */}
|
||||
{viewType === ViewType.Kanban && (
|
||||
<>
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuItemsContainer withoutScrollWrapper>
|
||||
<MenuItem
|
||||
onClick={() => onContentChange('viewSettings')}
|
||||
LeftIcon={IconLayout}
|
||||
@ -109,7 +109,7 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuItemsContainer withoutScrollWrapper>
|
||||
<MenuItem
|
||||
onClick={() => onContentChange('fields')}
|
||||
LeftIcon={IconTag}
|
||||
|
@ -81,11 +81,8 @@ const StyledBoardCard = styled.div<{ selected: boolean }>`
|
||||
`;
|
||||
|
||||
const StyledTextInput = styled(TextInput)`
|
||||
backdrop-filter: blur(12px) saturate(200%) contrast(50%) brightness(130%);
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
width: ${({ theme }) => theme.spacing(53)};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
width: ${({ theme }) => theme.spacing(53)};
|
||||
`;
|
||||
|
||||
const StyledBoardCardWrapper = styled.div`
|
||||
|
@ -6,6 +6,7 @@ import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { MenuItem } from 'twenty-ui';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
|
||||
const StyledMenuContainer = styled.div`
|
||||
position: absolute;
|
||||
@ -20,6 +21,7 @@ type RecordBoardColumnDropdownMenuProps = {
|
||||
stageId: string;
|
||||
};
|
||||
|
||||
// TODO: unify and use Dropdown component
|
||||
export const RecordBoardColumnDropdownMenu = ({
|
||||
onClose,
|
||||
}: RecordBoardColumnDropdownMenuProps) => {
|
||||
@ -39,21 +41,23 @@ export const RecordBoardColumnDropdownMenu = ({
|
||||
|
||||
return (
|
||||
<StyledMenuContainer ref={boardColumnMenuRef}>
|
||||
<DropdownMenu data-select-disable>
|
||||
<DropdownMenuItemsContainer>
|
||||
{recordGroupActions.map((action) => (
|
||||
<MenuItem
|
||||
key={action.id}
|
||||
onClick={() => {
|
||||
action.callback();
|
||||
closeMenu();
|
||||
}}
|
||||
LeftIcon={action.icon}
|
||||
text={action.label}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
<OverlayContainer>
|
||||
<DropdownMenu data-select-disable>
|
||||
<DropdownMenuItemsContainer>
|
||||
{recordGroupActions.map((action) => (
|
||||
<MenuItem
|
||||
key={action.id}
|
||||
onClick={() => {
|
||||
action.callback();
|
||||
closeMenu();
|
||||
}}
|
||||
LeftIcon={action.icon}
|
||||
text={action.label}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</OverlayContainer>
|
||||
</StyledMenuContainer>
|
||||
);
|
||||
};
|
||||
|
@ -1,23 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
|
||||
import { recordBoardNewRecordByColumnIdSelector } from '@/object-record/record-board/states/selectors/recordBoardNewRecordByColumnIdSelector';
|
||||
import { SingleRecordSelect } from '@/object-record/relation-picker/components/SingleRecordSelect';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledCompanyPickerContainer = styled.div`
|
||||
align-items: center;
|
||||
align-self: baseline;
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
border: none;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
export const RecordBoardColumnNewOpportunity = ({
|
||||
columnId,
|
||||
position,
|
||||
@ -36,9 +23,8 @@ export const RecordBoardColumnNewOpportunity = ({
|
||||
return (
|
||||
<>
|
||||
{newRecord.isCreating && newRecord.position === position && (
|
||||
<StyledCompanyPickerContainer>
|
||||
<OverlayContainer>
|
||||
<SingleRecordSelect
|
||||
disableBackgroundBlur
|
||||
onCancel={() => handleCreateSuccess(position, columnId, false)}
|
||||
onRecordSelected={(company) =>
|
||||
company ? handleEntitySelect(position, company) : null
|
||||
@ -47,7 +33,7 @@ export const RecordBoardColumnNewOpportunity = ({
|
||||
recordPickerInstanceId="relation-picker"
|
||||
selectedRecordIds={[]}
|
||||
/>
|
||||
</StyledCompanyPickerContainer>
|
||||
</OverlayContainer>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -3,7 +3,6 @@ import { FormFieldInputInputContainer } from '@/object-record/record-field/form-
|
||||
import { FormFieldInputRowContainer } from '@/object-record/record-field/form-types/components/FormFieldInputRowContainer';
|
||||
import { VariableChip } from '@/object-record/record-field/form-types/components/VariableChip';
|
||||
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
||||
import { StyledCalendarContainer } from '@/ui/field/input/components/DateInput';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import {
|
||||
InternalDatePicker,
|
||||
@ -16,6 +15,7 @@ import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate'
|
||||
import { parseDateToString } from '@/ui/input/components/internal/date/utils/parseDateToString';
|
||||
import { parseStringToDate } from '@/ui/input/components/internal/date/utils/parseStringToDate';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { UserContext } from '@/users/contexts/UserContext';
|
||||
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
||||
@ -338,7 +338,7 @@ export const FormDateFieldInput = ({
|
||||
{draftValue.mode === 'edit' ? (
|
||||
<StyledDateInputContainer>
|
||||
<StyledDateInputAbsoluteContainer>
|
||||
<StyledCalendarContainer>
|
||||
<OverlayContainer>
|
||||
<InternalDatePicker
|
||||
date={pickerDate ?? new Date()}
|
||||
isDateTimeInput={false}
|
||||
@ -349,7 +349,7 @@ export const FormDateFieldInput = ({
|
||||
onClear={handlePickerClear}
|
||||
hideHeaderInput
|
||||
/>
|
||||
</StyledCalendarContainer>
|
||||
</OverlayContainer>
|
||||
</StyledDateInputAbsoluteContainer>
|
||||
</StyledDateInputContainer>
|
||||
) : null}
|
||||
|
@ -9,6 +9,7 @@ import { SelectOption } from '@/spreadsheet-import/types';
|
||||
import { SelectDisplay } from '@/ui/field/display/components/SelectDisplay';
|
||||
import { SelectInput } from '@/ui/field/input/components/SelectInput';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
@ -238,19 +239,21 @@ export const FormSelectFieldInput = ({
|
||||
<StyledSelectInputContainer>
|
||||
{draftValue.type === 'static' &&
|
||||
draftValue.editingMode === 'edit' && (
|
||||
<SelectInput
|
||||
selectableListId={SINGLE_RECORD_SELECT_BASE_LIST}
|
||||
selectableItemIdArray={optionIds}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onEnter={handleSelectEnter}
|
||||
onOptionSelected={handleSubmit}
|
||||
options={options}
|
||||
onCancel={onCancel}
|
||||
defaultOption={selectedOption}
|
||||
onFilterChange={setFilteredOptions}
|
||||
onClear={handleClearField}
|
||||
clearLabel={clearLabel}
|
||||
/>
|
||||
<OverlayContainer>
|
||||
<SelectInput
|
||||
selectableListId={SINGLE_RECORD_SELECT_BASE_LIST}
|
||||
selectableItemIdArray={optionIds}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onEnter={handleSelectEnter}
|
||||
onOptionSelected={handleSubmit}
|
||||
options={options}
|
||||
onCancel={onCancel}
|
||||
defaultOption={selectedOption}
|
||||
onFilterChange={setFilteredOptions}
|
||||
onClear={handleClearField}
|
||||
clearLabel={clearLabel}
|
||||
/>
|
||||
</OverlayContainer>
|
||||
)}
|
||||
</StyledSelectInputContainer>
|
||||
|
||||
|
@ -4,7 +4,6 @@ import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode';
|
||||
import { FieldCurrencyValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { CurrencyInput } from '@/ui/field/input/components/CurrencyInput';
|
||||
|
||||
import { FieldInputOverlay } from '../../../../../ui/field/input/components/FieldInputOverlay';
|
||||
import { useCurrencyField } from '../../hooks/useCurrencyField';
|
||||
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
@ -118,21 +117,19 @@ export const CurrencyFieldInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<CurrencyInput
|
||||
value={draftValue?.amount?.toString() ?? ''}
|
||||
currencyCode={currencyCode}
|
||||
autoFocus
|
||||
placeholder="Currency"
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
onChange={handleChange}
|
||||
onSelect={handleSelect}
|
||||
hotkeyScope={hotkeyScope}
|
||||
/>
|
||||
</FieldInputOverlay>
|
||||
<CurrencyInput
|
||||
value={draftValue?.amount?.toString() ?? ''}
|
||||
currencyCode={currencyCode}
|
||||
autoFocus
|
||||
placeholder="Currency"
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
onChange={handleChange}
|
||||
onSelect={handleSelect}
|
||||
hotkeyScope={hotkeyScope}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { useFullNameField } from '@/object-record/record-field/meta-types/hooks/useFullNameField';
|
||||
import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleText';
|
||||
import { DoubleTextInput } from '@/ui/field/input/components/DoubleTextInput';
|
||||
import { FieldInputOverlay } from '@/ui/field/input/components/FieldInputOverlay';
|
||||
|
||||
import { FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS } from '@/object-record/record-field/meta-types/input/constants/FirstNamePlaceholder';
|
||||
import { LAST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS } from '@/object-record/record-field/meta-types/input/constants/LastNamePlaceholder';
|
||||
@ -79,25 +78,23 @@ export const FullNameFieldInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<DoubleTextInput
|
||||
firstValue={draftValue?.firstName ?? ''}
|
||||
secondValue={draftValue?.lastName ?? ''}
|
||||
firstValuePlaceholder={
|
||||
FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS
|
||||
}
|
||||
secondValuePlaceholder={
|
||||
LAST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS
|
||||
}
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
onPaste={handlePaste}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</FieldInputOverlay>
|
||||
<DoubleTextInput
|
||||
firstValue={draftValue?.firstName ?? ''}
|
||||
secondValue={draftValue?.lastName ?? ''}
|
||||
firstValuePlaceholder={
|
||||
FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS
|
||||
}
|
||||
secondValuePlaceholder={
|
||||
LAST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS
|
||||
}
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
onPaste={handlePaste}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,3 @@
|
||||
import styled from '@emotion/styled';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { IconCheck, IconPlus, LightIconButton, MenuItem } from 'twenty-ui';
|
||||
@ -18,11 +17,6 @@ import { moveArrayItem } from '~/utils/array/moveArrayItem';
|
||||
import { toSpliced } from '~/utils/array/toSpliced';
|
||||
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
|
||||
|
||||
const StyledDropdownMenu = styled(DropdownMenu)`
|
||||
margin: -1px;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
type MultiItemFieldInputProps<T> = {
|
||||
items: T[];
|
||||
onPersist: (updatedItems: T[]) => void;
|
||||
@ -164,7 +158,7 @@ export const MultiItemFieldInput = <T,>({
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledDropdownMenu ref={containerRef} width={200}>
|
||||
<DropdownMenu ref={containerRef} width={200}>
|
||||
{!!items.length && (
|
||||
<>
|
||||
<DropdownMenuItemsContainer>
|
||||
@ -222,6 +216,6 @@ export const MultiItemFieldInput = <T,>({
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
)}
|
||||
</StyledDropdownMenu>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { TextInput } from '@/ui/field/input/components/TextInput';
|
||||
|
||||
import { FieldInputOverlay } from '../../../../../ui/field/input/components/FieldInputOverlay';
|
||||
import { useNumberField } from '../../hooks/useNumberField';
|
||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/meta-types/input/components/DateTimeFieldInput';
|
||||
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
||||
import { useNumberField } from '../../hooks/useNumberField';
|
||||
|
||||
export type FieldInputEvent = (persist: () => void) => void;
|
||||
|
||||
@ -57,7 +57,7 @@ export const NumberFieldInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<FieldInputContainer>
|
||||
<TextInput
|
||||
placeholder={fieldDefinition.metadata.placeHolder}
|
||||
autoFocus
|
||||
@ -70,6 +70,6 @@ export const NumberFieldInput = ({
|
||||
hotkeyScope={hotkeyScope}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</FieldInputOverlay>
|
||||
</FieldInputContainer>
|
||||
);
|
||||
};
|
||||
|
@ -18,7 +18,6 @@ export const DEFAULT_PHONE_COUNTRY_CODE = '1';
|
||||
|
||||
const StyledCustomPhoneInput = styled(ReactPhoneNumberInput)`
|
||||
font-family: ${({ theme }) => theme.font.family};
|
||||
height: 32px;
|
||||
${TEXT_INPUT_STYLE}
|
||||
padding: 0;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { FieldTextAreaOverlay } from '@/ui/field/input/components/FieldTextAreaOverlay';
|
||||
import { TextAreaInput } from '@/ui/field/input/components/TextAreaInput';
|
||||
|
||||
import { useJsonField } from '../../hooks/useJsonField';
|
||||
@ -59,20 +58,18 @@ export const RawJsonFieldInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldTextAreaOverlay>
|
||||
<TextAreaInput
|
||||
placeholder={fieldDefinition.metadata.placeHolder}
|
||||
autoFocus
|
||||
value={draftValue ?? ''}
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onChange={handleChange}
|
||||
maxRows={25}
|
||||
/>
|
||||
</FieldTextAreaOverlay>
|
||||
<TextAreaInput
|
||||
placeholder={fieldDefinition.metadata.placeHolder}
|
||||
autoFocus
|
||||
value={draftValue ?? ''}
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onChange={handleChange}
|
||||
maxRows={25}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,3 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { RelationPicker } from '@/object-record/relation-picker/components/RelationPicker';
|
||||
import { RecordForSelect } from '@/object-record/relation-picker/types/RecordForSelect';
|
||||
|
||||
@ -8,12 +6,6 @@ import { useRelationField } from '../../hooks/useRelationField';
|
||||
|
||||
import { FieldInputEvent } from './DateTimeFieldInput';
|
||||
|
||||
const StyledRelationPickerContainer = styled.div`
|
||||
left: -1px;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
`;
|
||||
|
||||
export type RelationToOneFieldInputProps = {
|
||||
onSubmit?: FieldInputEvent;
|
||||
onCancel?: () => void;
|
||||
@ -33,14 +25,12 @@ export const RelationToOneFieldInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledRelationPickerContainer>
|
||||
<RelationPicker
|
||||
fieldDefinition={fieldDefinition}
|
||||
selectedRecordId={fieldValue?.id}
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={onCancel}
|
||||
initialSearchFilter={initialSearchValue}
|
||||
/>
|
||||
</StyledRelationPickerContainer>
|
||||
<RelationPicker
|
||||
fieldDefinition={fieldDefinition}
|
||||
selectedRecordId={fieldValue?.id}
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={onCancel}
|
||||
initialSearchFilter={initialSearchValue}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { FieldTextAreaOverlay } from '@/ui/field/input/components/FieldTextAreaOverlay';
|
||||
import { TextAreaInput } from '@/ui/field/input/components/TextAreaInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useTextField } from '../../hooks/useTextField';
|
||||
|
||||
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
||||
import { turnIntoUndefinedIfWhitespacesOnly } from '~/utils/string/turnIntoUndefinedIfWhitespacesOnly';
|
||||
import {
|
||||
FieldInputClickOutsideEvent,
|
||||
@ -57,7 +57,7 @@ export const TextFieldInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldTextAreaOverlay>
|
||||
<FieldInputContainer>
|
||||
<TextAreaInput
|
||||
placeholder={fieldDefinition.metadata.placeHolder}
|
||||
autoFocus
|
||||
@ -70,6 +70,6 @@ export const TextFieldInput = ({
|
||||
hotkeyScope={hotkeyScope}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</FieldTextAreaOverlay>
|
||||
</FieldInputContainer>
|
||||
);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ const StyledInlineCellButtonContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
export const RecordInlineCellButton = ({ Icon }: { Icon: IconComponent }) => {
|
||||
return (
|
||||
<AnimatedContainer>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { RecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import styled from '@emotion/styled';
|
||||
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
|
||||
import { useContext } from 'react';
|
||||
@ -11,24 +12,14 @@ const StyledInlineCellEditModeContainer = styled.div`
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
height: 24px;
|
||||
`;
|
||||
|
||||
const StyledInlineCellInput = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
min-height: 32px;
|
||||
|
||||
width: 240px;
|
||||
|
||||
z-index: 30;
|
||||
background: transparent;
|
||||
`;
|
||||
|
||||
type RecordInlineCellEditModeProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
// TODO: Refactor this to avoid setting absolute px values.
|
||||
export const RecordInlineCellEditMode = ({
|
||||
children,
|
||||
}: RecordInlineCellEditModeProps) => {
|
||||
@ -46,7 +37,7 @@ export const RecordInlineCellEditMode = ({
|
||||
}
|
||||
: {
|
||||
mainAxis: -29,
|
||||
crossAxis: -4,
|
||||
crossAxis: -5,
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -59,9 +50,9 @@ export const RecordInlineCellEditMode = ({
|
||||
data-testid="inline-cell-edit-mode-container"
|
||||
>
|
||||
{createPortal(
|
||||
<StyledInlineCellInput ref={refs.setFloating} style={floatingStyles}>
|
||||
<OverlayContainer ref={refs.setFloating} style={floatingStyles}>
|
||||
{children}
|
||||
</StyledInlineCellInput>,
|
||||
</OverlayContainer>,
|
||||
document.body,
|
||||
)}
|
||||
</StyledInlineCellEditModeContainer>
|
||||
|
@ -11,6 +11,7 @@ const StyledClickableContainer = styled.div<{
|
||||
readonly?: boolean;
|
||||
isCentered?: boolean;
|
||||
}>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
width: 100%;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import styled from '@emotion/styled';
|
||||
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
|
||||
import { ReactElement } from 'react';
|
||||
@ -12,16 +13,6 @@ const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModePr
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
const StyledTableCellInput = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
min-height: 32px;
|
||||
min-width: 200px;
|
||||
|
||||
z-index: 10;
|
||||
`;
|
||||
|
||||
export type RecordTableCellEditModeProps = {
|
||||
children: ReactElement;
|
||||
transparent?: boolean;
|
||||
@ -37,8 +28,8 @@ export const RecordTableCellEditMode = ({
|
||||
middleware: [
|
||||
flip(),
|
||||
offset({
|
||||
mainAxis: -31,
|
||||
crossAxis: -2,
|
||||
mainAxis: -33,
|
||||
crossAxis: -3,
|
||||
}),
|
||||
],
|
||||
whileElementsMounted: autoUpdate,
|
||||
@ -49,9 +40,9 @@ export const RecordTableCellEditMode = ({
|
||||
ref={refs.setReference}
|
||||
data-testid="editable-cell-edit-mode-container"
|
||||
>
|
||||
<StyledTableCellInput ref={refs.setFloating} style={floatingStyles}>
|
||||
<OverlayContainer ref={refs.setFloating} style={floatingStyles}>
|
||||
{children}
|
||||
</StyledTableCellInput>
|
||||
</OverlayContainer>
|
||||
</StyledEditableCellEditModeContainer>
|
||||
);
|
||||
};
|
||||
|
@ -96,6 +96,7 @@ export const MultiRecordSelect = ({
|
||||
[setSearchFilter],
|
||||
);
|
||||
|
||||
// TODO: refactor this in a separate component
|
||||
const results = (
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<SelectableList
|
||||
@ -139,7 +140,7 @@ export const MultiRecordSelect = ({
|
||||
onSubmit?.();
|
||||
}}
|
||||
/>
|
||||
<DropdownMenu ref={containerRef} data-select-disable>
|
||||
<DropdownMenu ref={containerRef} data-select-disable width={200}>
|
||||
{dropdownPlacement?.includes('end') && (
|
||||
<>
|
||||
{isDefined(onCreate) && (
|
||||
|
@ -9,12 +9,10 @@ import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useLis
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export type SingleRecordSelectProps = {
|
||||
disableBackgroundBlur?: boolean;
|
||||
width?: number;
|
||||
} & SingleRecordSelectMenuItemsWithSearchProps;
|
||||
|
||||
export const SingleRecordSelect = ({
|
||||
disableBackgroundBlur = false,
|
||||
EmptyIcon,
|
||||
emptyLabel,
|
||||
excludedRecordIds,
|
||||
@ -45,12 +43,7 @@ export const SingleRecordSelect = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownMenu
|
||||
disableBlur={disableBackgroundBlur}
|
||||
ref={containerRef}
|
||||
width={width}
|
||||
data-select-disable
|
||||
>
|
||||
<DropdownMenu ref={containerRef} width={width} data-select-disable>
|
||||
<SingleRecordSelectMenuItemsWithSearch
|
||||
{...{
|
||||
EmptyIcon,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { EnvironmentVariable } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariablesSection';
|
||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
@ -101,7 +100,6 @@ export const SettingsServerlessFunctionTabEnvironmentVariableTableRow = ({
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Dropdown
|
||||
dropdownMenuWidth="100px"
|
||||
dropdownId={dropDownId}
|
||||
clickableComponent={
|
||||
<LightIconButton
|
||||
@ -111,26 +109,24 @@ export const SettingsServerlessFunctionTabEnvironmentVariableTableRow = ({
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenu disableBlur disableBorder width="auto">
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
text={'Edit'}
|
||||
LeftIcon={IconPencil}
|
||||
onClick={() => {
|
||||
setEditMode(true);
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
<MenuItem
|
||||
text={'Delete'}
|
||||
LeftIcon={IconTrash}
|
||||
onClick={() => {
|
||||
onDelete();
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
text={'Edit'}
|
||||
LeftIcon={IconPencil}
|
||||
onClick={() => {
|
||||
setEditMode(true);
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
<MenuItem
|
||||
text={'Delete'}
|
||||
LeftIcon={IconTrash}
|
||||
onClick={() => {
|
||||
onDelete();
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropDownId,
|
||||
|
@ -15,11 +15,6 @@ import { useRecoilValue } from 'recoil';
|
||||
import { isDefined, MOBILE_VIEWPORT } from 'twenty-ui';
|
||||
|
||||
const StyledAddressContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
|
||||
padding: 4px 8px;
|
||||
|
||||
width: 344px;
|
||||
@ -27,11 +22,6 @@ const StyledAddressContainer = styled.div`
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
}
|
||||
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
width: auto;
|
||||
min-width: 100px;
|
||||
|
@ -21,10 +21,6 @@ export const StyledIMaskInput = styled(IMaskInput)<StyledInputProps>`
|
||||
const StyledContainer = styled.div`
|
||||
align-items: center;
|
||||
|
||||
border: none;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRef, useState } from 'react';
|
||||
import { Nullable } from 'twenty-ui';
|
||||
|
||||
import {
|
||||
@ -9,15 +9,6 @@ import {
|
||||
} from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
export const StyledCalendarContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
`;
|
||||
|
||||
export type DateInputProps = {
|
||||
value: Nullable<Date>;
|
||||
@ -89,19 +80,17 @@ export const DateInput = ({
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef}>
|
||||
<StyledCalendarContainer>
|
||||
<InternalDatePicker
|
||||
date={internalValue ?? new Date()}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={handleMouseSelect}
|
||||
clearable={clearable ? clearable : false}
|
||||
isDateTimeInput={isDateTimeInput}
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClear={handleClear}
|
||||
hideHeaderInput={hideHeaderInput}
|
||||
/>
|
||||
</StyledCalendarContainer>
|
||||
<InternalDatePicker
|
||||
date={internalValue ?? new Date()}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={handleMouseSelect}
|
||||
clearable={clearable ? clearable : false}
|
||||
isDateTimeInput={isDateTimeInput}
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClear={handleClear}
|
||||
hideHeaderInput={hideHeaderInput}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -12,22 +12,18 @@ import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleT
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { splitFullName } from '~/utils/format/spiltFullName';
|
||||
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
|
||||
import { StyledTextInput } from './TextInput';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
& > input:last-child {
|
||||
border-left: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-left: 1px solid ${({ theme }) => theme.border.color.strong};
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
}
|
||||
`;
|
||||
@ -186,39 +182,41 @@ export const DoubleTextInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer ref={containerRef}>
|
||||
<StyledTextInput
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
onFocus={() => setFocusPosition('left')}
|
||||
ref={firstValueInputRef}
|
||||
placeholder={firstValuePlaceholder}
|
||||
value={firstInternalValue}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
handleChange(
|
||||
turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
|
||||
secondInternalValue,
|
||||
);
|
||||
}}
|
||||
onPaste={(event: ClipboardEvent<HTMLInputElement>) =>
|
||||
handleOnPaste(event)
|
||||
}
|
||||
onClick={handleClickToPreventParentClickEvents}
|
||||
/>
|
||||
<StyledTextInput
|
||||
autoComplete="off"
|
||||
onFocus={() => setFocusPosition('right')}
|
||||
ref={secondValueInputRef}
|
||||
placeholder={secondValuePlaceholder}
|
||||
value={secondInternalValue}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
handleChange(
|
||||
firstInternalValue,
|
||||
turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
|
||||
);
|
||||
}}
|
||||
onClick={handleClickToPreventParentClickEvents}
|
||||
/>
|
||||
</StyledContainer>
|
||||
<FieldInputContainer>
|
||||
<StyledContainer ref={containerRef}>
|
||||
<StyledTextInput
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
onFocus={() => setFocusPosition('left')}
|
||||
ref={firstValueInputRef}
|
||||
placeholder={firstValuePlaceholder}
|
||||
value={firstInternalValue}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
handleChange(
|
||||
turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
|
||||
secondInternalValue,
|
||||
);
|
||||
}}
|
||||
onPaste={(event: ClipboardEvent<HTMLInputElement>) =>
|
||||
handleOnPaste(event)
|
||||
}
|
||||
onClick={handleClickToPreventParentClickEvents}
|
||||
/>
|
||||
<StyledTextInput
|
||||
autoComplete="off"
|
||||
onFocus={() => setFocusPosition('right')}
|
||||
ref={secondValueInputRef}
|
||||
placeholder={secondValuePlaceholder}
|
||||
value={secondInternalValue}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
handleChange(
|
||||
firstInternalValue,
|
||||
turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
|
||||
);
|
||||
}}
|
||||
onClick={handleClickToPreventParentClickEvents}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</FieldInputContainer>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
// eslint-disable-next-line @nx/workspace-styled-components-prefixed-with-styled
|
||||
export const FieldInputContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
min-height: 32px;
|
||||
min-width: 200px;
|
||||
width: 100%;
|
||||
`;
|
@ -1,16 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { OVERLAY_BACKGROUND } from 'twenty-ui';
|
||||
|
||||
const StyledFieldInputOverlay = styled.div`
|
||||
align-items: center;
|
||||
border: ${({ theme }) => `1px solid ${theme.border.color.light}`};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
height: 32px;
|
||||
justify-content: space-between;
|
||||
margin: -1px;
|
||||
width: 100%;
|
||||
${OVERLAY_BACKGROUND}
|
||||
`;
|
||||
|
||||
export const FieldInputOverlay = StyledFieldInputOverlay;
|
@ -1,16 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { OVERLAY_BACKGROUND } from 'twenty-ui';
|
||||
|
||||
const StyledFieldTextAreaOverlay = styled.div`
|
||||
align-items: center;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
margin: -1px;
|
||||
max-height: 420px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
${OVERLAY_BACKGROUND}
|
||||
`;
|
||||
|
||||
export const FieldTextAreaOverlay = StyledFieldTextAreaOverlay;
|
@ -33,33 +33,14 @@ const StyledTextArea = styled(TextareaAutosize)`
|
||||
resize: none;
|
||||
max-height: 400px;
|
||||
width: calc(100% - ${({ theme }) => theme.spacing(7)});
|
||||
background: transparent;
|
||||
|
||||
line-height: 18px;
|
||||
`;
|
||||
|
||||
const StyledTextAreaContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
|
||||
@supports (
|
||||
(backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px))
|
||||
) {
|
||||
background: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
-webkit-backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledLightIconButtonContainer = styled.div`
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
top: 16px;
|
||||
transform: translateY(-50%);
|
||||
right: 0;
|
||||
`;
|
||||
@ -114,7 +95,7 @@ export const TextAreaInput = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledTextAreaContainer>
|
||||
<>
|
||||
<StyledTextArea
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
@ -130,6 +111,6 @@ export const TextAreaInput = ({
|
||||
<LightCopyIconButton copyText={internalText} />
|
||||
</StyledLightIconButtonContainer>
|
||||
)}
|
||||
</StyledTextAreaContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -3,11 +3,11 @@ import { useMemo, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import {
|
||||
IconApps,
|
||||
IconComponent,
|
||||
useIcons,
|
||||
IconButton,
|
||||
IconButtonVariant,
|
||||
IconComponent,
|
||||
LightIconButton,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
@ -33,7 +33,6 @@ export type IconPickerProps = {
|
||||
onOpen?: () => void;
|
||||
variant?: IconButtonVariant;
|
||||
className?: string;
|
||||
disableBlur?: boolean;
|
||||
};
|
||||
|
||||
const StyledMenuIconItemsContainer = styled.div`
|
||||
@ -90,7 +89,6 @@ export const IconPicker = ({
|
||||
onClose,
|
||||
onOpen,
|
||||
variant = 'secondary',
|
||||
disableBlur = false,
|
||||
className,
|
||||
}: IconPickerProps) => {
|
||||
const [searchString, setSearchString] = useState('');
|
||||
@ -172,7 +170,6 @@ export const IconPicker = ({
|
||||
/>
|
||||
}
|
||||
dropdownMenuWidth={176}
|
||||
disableBlur={disableBlur}
|
||||
dropdownComponents={
|
||||
<SelectableList
|
||||
selectableListId="icon-list"
|
||||
|
@ -32,7 +32,6 @@ export type SelectProps<Value extends SelectValue> = {
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
selectSizeVariant?: SelectSizeVariant;
|
||||
disableBlur?: boolean;
|
||||
dropdownId: string;
|
||||
dropdownWidth?: `${string}px` | 'auto' | number;
|
||||
dropdownWidthAuto?: boolean;
|
||||
@ -63,7 +62,6 @@ export const Select = <Value extends SelectValue>({
|
||||
className,
|
||||
disabled: disabledFromProps,
|
||||
selectSizeVariant,
|
||||
disableBlur = false,
|
||||
dropdownId,
|
||||
dropdownWidth = 176,
|
||||
dropdownWidthAuto = false,
|
||||
@ -135,7 +133,6 @@ export const Select = <Value extends SelectValue>({
|
||||
selectSizeVariant={selectSizeVariant}
|
||||
/>
|
||||
}
|
||||
disableBlur={disableBlur}
|
||||
dropdownComponents={
|
||||
<>
|
||||
{!!withSearchInput && (
|
||||
|
@ -32,7 +32,7 @@ export const CurrencyPickerDropdownSelect = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenu disableBlur>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuSearchInput
|
||||
value={searchFilter}
|
||||
onChange={(event) => setSearchFilter(event.target.value)}
|
||||
|
@ -81,7 +81,6 @@ export const AbsoluteDatePickerHeader = ({
|
||||
<Select
|
||||
dropdownId={MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID}
|
||||
options={getMonthSelectOptions()}
|
||||
disableBlur
|
||||
onChange={onChangeMonth}
|
||||
value={endOfDayInLocalTimezone.getMonth()}
|
||||
fullWidth
|
||||
@ -91,7 +90,6 @@ export const AbsoluteDatePickerHeader = ({
|
||||
onChange={onChangeYear}
|
||||
value={endOfDayInLocalTimezone.getFullYear()}
|
||||
options={years}
|
||||
disableBlur
|
||||
fullWidth
|
||||
/>
|
||||
<LightIconButton
|
||||
|
@ -16,8 +16,6 @@ import { isDefined } from 'twenty-ui';
|
||||
|
||||
const StyledInputContainer = styled.div`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-top-left-radius: ${({ theme }) => theme.border.radius.md};
|
||||
border-top-right-radius: ${({ theme }) => theme.border.radius.md};
|
||||
|
@ -5,7 +5,6 @@ import { Key } from 'ts-key-enum';
|
||||
import {
|
||||
IconCalendarX,
|
||||
MenuItemLeftContent,
|
||||
OVERLAY_BACKGROUND,
|
||||
StyledHoverableMenuItemBase,
|
||||
} from 'twenty-ui';
|
||||
|
||||
@ -122,8 +121,6 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>`
|
||||
|
||||
& .react-datepicker__month-dropdown,
|
||||
& .react-datepicker__year-dropdown {
|
||||
border: ${({ theme }) => theme.border.color.light};
|
||||
${OVERLAY_BACKGROUND}
|
||||
overflow-y: scroll;
|
||||
top: ${({ theme }) => theme.spacing(2)};
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ export const RelativeDatePickerHeader = (
|
||||
return (
|
||||
<StyledContainer>
|
||||
<Select
|
||||
disableBlur
|
||||
dropdownId="direction-select"
|
||||
value={direction}
|
||||
onChange={(newDirection) => {
|
||||
@ -95,7 +94,6 @@ export const RelativeDatePickerHeader = (
|
||||
disabled={direction === 'THIS'}
|
||||
/>
|
||||
<Select
|
||||
disableBlur
|
||||
dropdownId="unit-select"
|
||||
value={unit}
|
||||
onChange={(newUnit) => {
|
||||
|
@ -2,7 +2,6 @@ import styled from '@emotion/styled';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { Country } from '@/ui/input/components/internal/types/Country';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
@ -47,7 +46,7 @@ export const PhoneCountryPickerDropdownSelect = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenu width="auto" disableBlur>
|
||||
<>
|
||||
<DropdownMenuSearchInput
|
||||
value={searchFilter}
|
||||
onChange={(event) => setSearchFilter(event.currentTarget.value)}
|
||||
@ -91,6 +90,6 @@ export const PhoneCountryPickerDropdownSelect = ({
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ const StyledEditor = styled.div`
|
||||
}
|
||||
& .bn-drag-handle-menu {
|
||||
background: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: blur(12px) saturate(200%) contrast(50%) brightness(130%);
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
box-shadow:
|
||||
0px 2px 4px rgba(0, 0, 0, 0.04),
|
||||
2px 4px 16px rgba(0, 0, 0, 0.12);
|
||||
@ -64,6 +64,19 @@ const StyledEditor = styled.div`
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
left: 26px;
|
||||
}
|
||||
|
||||
& .bn-container .bn-suggestion-menu-item:hover {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
& .bn-suggestion-menu {
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
background: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
}
|
||||
|
||||
& .mantine-Menu-item {
|
||||
background-color: transparent;
|
||||
min-width: 152px;
|
||||
|
@ -4,6 +4,9 @@ import { IconComponent, MenuItemSuggestion } from 'twenty-ui';
|
||||
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import { useFloating } from '@floating-ui/react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
export type SuggestionItem = {
|
||||
title: string;
|
||||
@ -14,28 +17,43 @@ export type SuggestionItem = {
|
||||
|
||||
type CustomSlashMenuProps = SuggestionMenuProps<SuggestionItem>;
|
||||
|
||||
const StyledSlashMenu = styled.div`
|
||||
* {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
const StyledContainer = styled.div`
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
`;
|
||||
|
||||
const StyledInnerContainer = styled.div`
|
||||
height: 250px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const CustomSlashMenu = (props: CustomSlashMenuProps) => {
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
placement: 'bottom-start',
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledSlashMenu>
|
||||
<DropdownMenu style={{ zIndex: 2001 }}>
|
||||
<DropdownMenuItemsContainer>
|
||||
{props.items.map((item, index) => (
|
||||
<MenuItemSuggestion
|
||||
key={item.title}
|
||||
onClick={() => item.onItemClick()}
|
||||
text={item.title}
|
||||
LeftIcon={item.Icon}
|
||||
selected={props.selectedIndex === index}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledSlashMenu>
|
||||
<StyledContainer ref={refs.setReference}>
|
||||
{createPortal(
|
||||
<OverlayContainer ref={refs.setFloating} style={floatingStyles}>
|
||||
<StyledInnerContainer>
|
||||
<DropdownMenu style={{ zIndex: 2001 }}>
|
||||
<DropdownMenuItemsContainer>
|
||||
{props.items.map((item, index) => (
|
||||
<MenuItemSuggestion
|
||||
key={item.title}
|
||||
onClick={() => item.onItemClick()}
|
||||
text={item.title}
|
||||
LeftIcon={item.Icon}
|
||||
selected={props.selectedIndex === index}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledInnerContainer>
|
||||
</OverlayContainer>,
|
||||
document.body,
|
||||
)}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
@ -37,7 +37,6 @@ type DropdownProps = {
|
||||
dropdownMenuWidth?: `${string}px` | `${number}%` | 'auto' | number;
|
||||
dropdownOffset?: { x?: number; y?: number };
|
||||
dropdownStrategy?: 'fixed' | 'absolute';
|
||||
disableBlur?: boolean;
|
||||
onClickOutside?: () => void;
|
||||
onClose?: () => void;
|
||||
onOpen?: () => void;
|
||||
@ -55,7 +54,6 @@ export const Dropdown = ({
|
||||
dropdownPlacement = 'bottom-end',
|
||||
dropdownStrategy = 'absolute',
|
||||
dropdownOffset = { x: 0, y: 0 },
|
||||
disableBlur = false,
|
||||
onClickOutside,
|
||||
onClose,
|
||||
onOpen,
|
||||
@ -123,7 +121,6 @@ export const Dropdown = ({
|
||||
<DropdownContent
|
||||
className={className}
|
||||
floatingStyles={floatingStyles}
|
||||
disableBlur={disableBlur}
|
||||
dropdownMenuWidth={dropdownMenuWidth}
|
||||
dropdownComponents={dropdownComponents}
|
||||
dropdownId={dropdownId}
|
||||
|
@ -3,12 +3,14 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useInternalHotkeyScopeManagement } from '@/ui/layout/dropdown/hooks/useInternalHotkeyScopeManagement';
|
||||
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
||||
import { dropdownMaxHeightComponentStateV2 } from '@/ui/layout/dropdown/states/dropdownMaxHeightComponentStateV2';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
FloatingPortal,
|
||||
Placement,
|
||||
@ -19,6 +21,11 @@ import { Keys } from 'react-hotkeys-hook';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
export const StyledDropdownContentContainer = styled.div`
|
||||
display: flex;
|
||||
z-index: 30;
|
||||
`;
|
||||
|
||||
export type DropdownContentProps = {
|
||||
className?: string;
|
||||
dropdownId: string;
|
||||
@ -32,7 +39,6 @@ export type DropdownContentProps = {
|
||||
scope: string;
|
||||
};
|
||||
onHotkeyTriggered?: () => void;
|
||||
disableBlur?: boolean;
|
||||
dropdownMenuWidth?: `${string}px` | `${number}%` | 'auto' | number;
|
||||
dropdownComponents: React.ReactNode;
|
||||
parentDropdownId?: string;
|
||||
@ -49,7 +55,6 @@ export const DropdownContent = ({
|
||||
floatingStyles,
|
||||
hotkey,
|
||||
onHotkeyTriggered,
|
||||
disableBlur,
|
||||
dropdownMenuWidth,
|
||||
dropdownComponents,
|
||||
avoidPortal,
|
||||
@ -59,7 +64,7 @@ export const DropdownContent = ({
|
||||
|
||||
const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState);
|
||||
|
||||
const [dropdownMaxHeight] = useRecoilComponentStateV2(
|
||||
const dropdownMaxHeight = useRecoilComponentValueV2(
|
||||
dropdownMaxHeightComponentStateV2,
|
||||
dropdownId,
|
||||
);
|
||||
@ -114,28 +119,36 @@ export const DropdownContent = ({
|
||||
<HotkeyEffect hotkey={hotkey} onHotkeyTriggered={onHotkeyTriggered} />
|
||||
)}
|
||||
{avoidPortal ? (
|
||||
<DropdownMenu
|
||||
className={className}
|
||||
disableBlur={disableBlur}
|
||||
width={dropdownMenuWidth ?? dropdownWidth}
|
||||
data-select-disable
|
||||
<StyledDropdownContentContainer
|
||||
ref={floatingUiRefs.setFloating}
|
||||
style={dropdownMenuStyles}
|
||||
>
|
||||
{dropdownComponents}
|
||||
</DropdownMenu>
|
||||
<OverlayContainer>
|
||||
<DropdownMenu
|
||||
className={className}
|
||||
width={dropdownMenuWidth ?? dropdownWidth}
|
||||
data-select-disable
|
||||
>
|
||||
{dropdownComponents}
|
||||
</DropdownMenu>
|
||||
</OverlayContainer>
|
||||
</StyledDropdownContentContainer>
|
||||
) : (
|
||||
<FloatingPortal>
|
||||
<DropdownMenu
|
||||
className={className}
|
||||
disableBlur={disableBlur}
|
||||
width={dropdownMenuWidth ?? dropdownWidth}
|
||||
data-select-disable
|
||||
<StyledDropdownContentContainer
|
||||
ref={floatingUiRefs.setFloating}
|
||||
style={dropdownMenuStyles}
|
||||
>
|
||||
{dropdownComponents}
|
||||
</DropdownMenu>
|
||||
<OverlayContainer>
|
||||
<DropdownMenu
|
||||
className={className}
|
||||
width={dropdownMenuWidth ?? dropdownWidth}
|
||||
data-select-disable
|
||||
>
|
||||
{dropdownComponents}
|
||||
</DropdownMenu>
|
||||
</OverlayContainer>
|
||||
</StyledDropdownContentContainer>
|
||||
</FloatingPortal>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,29 +1,12 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledDropdownMenu = styled.div<{
|
||||
disableBlur?: boolean;
|
||||
disableBorder?: boolean;
|
||||
width?: `${string}px` | `${number}%` | 'auto' | number;
|
||||
}>`
|
||||
backdrop-filter: ${({ theme, disableBlur }) =>
|
||||
disableBlur ? 'none' : theme.blur.medium};
|
||||
|
||||
color: ${({ theme }) => theme.font.color.secondary};
|
||||
|
||||
background: ${({ theme, disableBlur }) =>
|
||||
disableBlur
|
||||
? theme.background.primary
|
||||
: theme.background.transparent.primary};
|
||||
|
||||
border: ${({ disableBorder, theme }) =>
|
||||
disableBorder ? 'none' : `1px solid ${theme.border.color.medium}`};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
z-index: 30;
|
||||
height: 100%;
|
||||
width: ${({ width = 200 }) =>
|
||||
typeof width === 'number' ? `${width}px` : width};
|
||||
`;
|
||||
|
@ -13,11 +13,6 @@ const StyledInput = styled.input<{
|
||||
}>`
|
||||
${TEXT_INPUT_STYLE}
|
||||
|
||||
border: 1px solid ${({ theme, hasError }) =>
|
||||
hasError ? theme.border.color.danger : theme.border.color.medium};
|
||||
background-color: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
box-sizing: border-box;
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
height: 32px;
|
||||
|
@ -6,12 +6,9 @@ import { TEXT_INPUT_STYLE } from 'twenty-ui';
|
||||
const StyledDropdownMenuSearchInputContainer = styled.div`
|
||||
align-items: center;
|
||||
--vertical-padding: ${({ theme }) => theme.spacing(2)};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
background: ${({ theme }) => theme.background.transparent.secondary};
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
flex-direction: row;
|
||||
height: calc(36px - 2 * var(--vertical-padding));
|
||||
min-height: calc(36px - 2 * var(--vertical-padding));
|
||||
padding: var(--vertical-padding) 0;
|
||||
|
||||
width: 100%;
|
||||
|
@ -3,8 +3,10 @@ import styled from '@emotion/styled';
|
||||
import { FloatingPortal, offset, shift, useFloating } from '@floating-ui/react';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { StyledDropdownContentContainer } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||
|
||||
type ExpandedListDropdownProps = {
|
||||
anchorElement?: HTMLElement;
|
||||
@ -16,11 +18,6 @@ type ExpandedListDropdownProps = {
|
||||
const StyledExpandedListContainer = styled.div<{
|
||||
withBorder?: boolean;
|
||||
}>`
|
||||
backdrop-filter: ${({ theme }) => theme.blur.strong};
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
box-shadow: ${({ theme }) =>
|
||||
`0px 2px 4px ${theme.boxShadow.light}, 2px 4px 16px ${theme.boxShadow.strong}`};
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
@ -33,6 +30,7 @@ const StyledExpandedListContainer = styled.div<{
|
||||
`};
|
||||
`;
|
||||
|
||||
// TODO: unify this and use Dropdown component instead
|
||||
export const ExpandedListDropdown = ({
|
||||
anchorElement,
|
||||
children,
|
||||
@ -55,19 +53,24 @@ export const ExpandedListDropdown = ({
|
||||
|
||||
return (
|
||||
<FloatingPortal>
|
||||
<DropdownMenu
|
||||
<StyledDropdownContentContainer
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
width={
|
||||
anchorElement
|
||||
? Math.max(220, anchorElement.getBoundingClientRect().width)
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<StyledExpandedListContainer withBorder={withBorder}>
|
||||
{children}
|
||||
</StyledExpandedListContainer>
|
||||
</DropdownMenu>
|
||||
<OverlayContainer>
|
||||
<DropdownMenu
|
||||
width={
|
||||
anchorElement
|
||||
? Math.max(220, anchorElement.getBoundingClientRect().width)
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<StyledExpandedListContainer withBorder={withBorder}>
|
||||
{children}
|
||||
</StyledExpandedListContainer>
|
||||
</DropdownMenu>
|
||||
</OverlayContainer>
|
||||
</StyledDropdownContentContainer>
|
||||
</FloatingPortal>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,20 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
// eslint-disable-next-line @nx/workspace-styled-components-prefixed-with-styled
|
||||
export const OverlayContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||
width: fit-content;
|
||||
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
|
||||
background: ${({ theme }) => theme.background.transparent.primary};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
z-index: 30;
|
||||
`;
|
@ -93,7 +93,6 @@ export const MenuItemWithOptionDropdown = ({
|
||||
dropdownComponents={dropdownContent}
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||
disableBlur
|
||||
/>
|
||||
</div>
|
||||
{hasSubMenu && (
|
||||
|
@ -17,7 +17,7 @@ import 'overlayscrollbars/overlayscrollbars.css';
|
||||
|
||||
const StyledScrollWrapper = styled.div<{ scrollHide?: boolean }>`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
height: fit-content;
|
||||
width: 100%;
|
||||
|
||||
.os-scrollbar-handle {
|
||||
|
@ -128,7 +128,6 @@ export const ViewPickerContentCreateMode = () => {
|
||||
<IconPicker
|
||||
onChange={onIconChange}
|
||||
selectedIconKey={selectedIcon}
|
||||
disableBlur
|
||||
onClose={() => setHotkeyScope(ViewsHotkeyScope.ListDropdown)}
|
||||
/>
|
||||
<TextInputV2
|
||||
@ -142,7 +141,6 @@ export const ViewPickerContentCreateMode = () => {
|
||||
</ViewPickerIconAndNameContainer>
|
||||
<ViewPickerSelectContainer>
|
||||
<Select
|
||||
disableBlur
|
||||
label="View type"
|
||||
fullWidth
|
||||
value={viewPickerType}
|
||||
@ -165,7 +163,6 @@ export const ViewPickerContentCreateMode = () => {
|
||||
<>
|
||||
<ViewPickerSelectContainer>
|
||||
<Select
|
||||
disableBlur
|
||||
label="Stages"
|
||||
fullWidth
|
||||
value={viewPickerKanbanFieldMetadataId}
|
||||
|
@ -76,7 +76,6 @@ export const ViewPickerContentEditMode = () => {
|
||||
<IconPicker
|
||||
onChange={onIconChange}
|
||||
selectedIconKey={viewPickerSelectedIcon}
|
||||
disableBlur
|
||||
onClose={() => setHotkeyScope(ViewsHotkeyScope.ListDropdown)}
|
||||
/>
|
||||
<TextInputV2
|
||||
|
@ -17,7 +17,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { WorkflowSingleRecordFieldChip } from '@/workflow/components/WorkflowSingleRecordFieldChip';
|
||||
import SearchVariablesDropdown from '@/workflow/search-variables/components/SearchVariablesDropdown';
|
||||
import { SearchVariablesDropdown } from '@/workflow/search-variables/components/SearchVariablesDropdown';
|
||||
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
||||
import SearchVariablesDropdown from '@/workflow/search-variables/components/SearchVariablesDropdown';
|
||||
import { SearchVariablesDropdown } from '@/workflow/search-variables/components/SearchVariablesDropdown';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SearchVariablesDropdownFieldItems } from '@/workflow/search-variables/components/SearchVariablesDropdownFieldItems';
|
||||
@ -20,6 +19,7 @@ const StyledDropdownVariableButtonContainer = styled(
|
||||
transparentBackground
|
||||
? 'transparent'
|
||||
: theme.background.transparent.lighter};
|
||||
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
:hover {
|
||||
@ -27,12 +27,7 @@ const StyledDropdownVariableButtonContainer = styled(
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledDropdownComponentsContainer = styled(DropdownMenuItemsContainer)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const SearchVariablesDropdown = ({
|
||||
export const SearchVariablesDropdown = ({
|
||||
inputId,
|
||||
onVariableSelect,
|
||||
disabled,
|
||||
@ -76,36 +71,6 @@ const SearchVariablesDropdown = ({
|
||||
setSelectedStep(undefined);
|
||||
};
|
||||
|
||||
const renderSearchVariablesDropdownComponents = () => {
|
||||
if (!isDefined(selectedStep)) {
|
||||
return (
|
||||
<SearchVariablesDropdownWorkflowStepItems
|
||||
dropdownId={dropdownId}
|
||||
steps={availableVariablesInWorkflowStep}
|
||||
onSelect={handleStepSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (isDefined(objectNameSingularToSelect)) {
|
||||
return (
|
||||
<SearchVariablesDropdownObjectItems
|
||||
step={selectedStep}
|
||||
onSelect={handleSubItemSelect}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SearchVariablesDropdownFieldItems
|
||||
step={selectedStep}
|
||||
onSelect={handleSubItemSelect}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
if (disabled === true) {
|
||||
return (
|
||||
<StyledDropdownVariableButtonContainer
|
||||
@ -138,14 +103,28 @@ const SearchVariablesDropdown = ({
|
||||
</StyledDropdownVariableButtonContainer>
|
||||
}
|
||||
dropdownComponents={
|
||||
<StyledDropdownComponentsContainer>
|
||||
{renderSearchVariablesDropdownComponents()}
|
||||
</StyledDropdownComponentsContainer>
|
||||
!isDefined(selectedStep) ? (
|
||||
<SearchVariablesDropdownWorkflowStepItems
|
||||
dropdownId={dropdownId}
|
||||
steps={availableVariablesInWorkflowStep}
|
||||
onSelect={handleStepSelect}
|
||||
/>
|
||||
) : isDefined(objectNameSingularToSelect) ? (
|
||||
<SearchVariablesDropdownObjectItems
|
||||
step={selectedStep}
|
||||
onSelect={handleSubItemSelect}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
) : (
|
||||
<SearchVariablesDropdownFieldItems
|
||||
step={selectedStep}
|
||||
onSelect={handleSubItemSelect}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
)
|
||||
}
|
||||
dropdownPlacement="bottom-end"
|
||||
dropdownOffset={{ x: 0, y: 4 }}
|
||||
dropdownOffset={{ x: 2, y: 4 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchVariablesDropdown;
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import {
|
||||
BaseOutputSchema,
|
||||
LinkOutputSchema,
|
||||
@ -8,11 +10,9 @@ import {
|
||||
} from '@/workflow/search-variables/types/StepOutputSchema';
|
||||
import { isBaseOutputSchema } from '@/workflow/search-variables/utils/isBaseOutputSchema';
|
||||
import { isRecordOutputSchema } from '@/workflow/search-variables/utils/isRecordOutputSchema';
|
||||
import { useTheme } from '@emotion/react';
|
||||
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
HorizontalSeparator,
|
||||
IconChevronLeft,
|
||||
isDefined,
|
||||
MenuItemSelect,
|
||||
@ -37,7 +37,6 @@ export const SearchVariablesDropdownFieldItems = ({
|
||||
onSelect,
|
||||
onBack,
|
||||
}: SearchVariablesDropdownFieldItemsProps) => {
|
||||
const theme = useTheme();
|
||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
const { getIcon } = useIcons();
|
||||
@ -139,30 +138,25 @@ export const SearchVariablesDropdownFieldItems = ({
|
||||
>
|
||||
<OverflowingTextWithTooltip text={headerLabel} />
|
||||
</DropdownMenuHeader>
|
||||
<HorizontalSeparator
|
||||
color={theme.background.transparent.primary}
|
||||
noMargin
|
||||
/>
|
||||
<DropdownMenuSearchInput
|
||||
autoFocus
|
||||
value={searchInputValue}
|
||||
onChange={(event) => setSearchInputValue(event.target.value)}
|
||||
/>
|
||||
<HorizontalSeparator
|
||||
color={theme.background.transparent.primary}
|
||||
noMargin
|
||||
/>
|
||||
{filteredOptions.map(([key, value]) => (
|
||||
<MenuItemSelect
|
||||
key={key}
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={() => handleSelectField(key)}
|
||||
text={value.label || key}
|
||||
hasSubMenu={!value.isLeaf}
|
||||
LeftIcon={value.icon ? getIcon(value.icon) : undefined}
|
||||
/>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
{filteredOptions.map(([key, value]) => (
|
||||
<MenuItemSelect
|
||||
key={key}
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={() => handleSelectField(key)}
|
||||
text={value.label || key}
|
||||
hasSubMenu={!value.isLeaf}
|
||||
LeftIcon={value.icon ? getIcon(value.icon) : undefined}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import {
|
||||
OutputSchema,
|
||||
StepOutputSchema,
|
||||
} from '@/workflow/search-variables/types/StepOutputSchema';
|
||||
import { isBaseOutputSchema } from '@/workflow/search-variables/utils/isBaseOutputSchema';
|
||||
import { isRecordOutputSchema } from '@/workflow/search-variables/utils/isRecordOutputSchema';
|
||||
import { useTheme } from '@emotion/react';
|
||||
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
HorizontalSeparator,
|
||||
IconChevronLeft,
|
||||
MenuItemSelect,
|
||||
OverflowingTextWithTooltip,
|
||||
@ -28,7 +28,6 @@ export const SearchVariablesDropdownObjectItems = ({
|
||||
onSelect,
|
||||
onBack,
|
||||
}: SearchVariablesDropdownObjectItemsProps) => {
|
||||
const theme = useTheme();
|
||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
const { getIcon } = useIcons();
|
||||
@ -119,44 +118,39 @@ export const SearchVariablesDropdownObjectItems = ({
|
||||
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={goBack}>
|
||||
<OverflowingTextWithTooltip text={headerLabel} />
|
||||
</DropdownMenuHeader>
|
||||
<HorizontalSeparator
|
||||
color={theme.background.transparent.primary}
|
||||
noMargin
|
||||
/>
|
||||
<DropdownMenuSearchInput
|
||||
autoFocus
|
||||
value={searchInputValue}
|
||||
onChange={(event) => setSearchInputValue(event.target.value)}
|
||||
/>
|
||||
<HorizontalSeparator
|
||||
color={theme.background.transparent.primary}
|
||||
noMargin
|
||||
/>
|
||||
{shouldDisplaySubStepObject && displayedSubStepObject?.label && (
|
||||
<MenuItemSelect
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={handleSelectObject}
|
||||
text={displayedSubStepObject.label}
|
||||
hasSubMenu={false}
|
||||
LeftIcon={
|
||||
displayedSubStepObject.icon
|
||||
? getIcon(displayedSubStepObject.icon)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{filteredOptions.map(([key, value]) => (
|
||||
<MenuItemSelect
|
||||
key={key}
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={() => handleSelectField(key)}
|
||||
text={value.label || key}
|
||||
hasSubMenu={!value.isLeaf}
|
||||
LeftIcon={value.icon ? getIcon(value.icon) : undefined}
|
||||
/>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
{shouldDisplaySubStepObject && displayedSubStepObject?.label && (
|
||||
<MenuItemSelect
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={handleSelectObject}
|
||||
text={displayedSubStepObject.label}
|
||||
hasSubMenu={false}
|
||||
LeftIcon={
|
||||
displayedSubStepObject.icon
|
||||
? getIcon(displayedSubStepObject.icon)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{filteredOptions.map(([key, value]) => (
|
||||
<MenuItemSelect
|
||||
key={key}
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={() => handleSelectField(key)}
|
||||
text={value.label || key}
|
||||
hasSubMenu={!value.isLeaf}
|
||||
LeftIcon={value.icon ? getIcon(value.icon) : undefined}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { StepOutputSchema } from '@/workflow/search-variables/types/StepOutputSchema';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
HorizontalSeparator,
|
||||
IconX,
|
||||
MenuItem,
|
||||
MenuItemSelect,
|
||||
@ -24,7 +24,6 @@ export const SearchVariablesDropdownWorkflowStepItems = ({
|
||||
steps,
|
||||
onSelect,
|
||||
}: SearchVariablesDropdownWorkflowStepItemsProps) => {
|
||||
const theme = useTheme();
|
||||
const { getIcon } = useIcons();
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
|
||||
@ -41,40 +40,35 @@ export const SearchVariablesDropdownWorkflowStepItems = ({
|
||||
<DropdownMenuHeader StartIcon={IconX} onClick={closeDropdown}>
|
||||
<OverflowingTextWithTooltip text={'Select Step'} />
|
||||
</DropdownMenuHeader>
|
||||
<HorizontalSeparator
|
||||
color={theme.background.transparent.primary}
|
||||
noMargin
|
||||
/>
|
||||
<DropdownMenuSearchInput
|
||||
autoFocus
|
||||
value={searchInputValue}
|
||||
onChange={(event) => setSearchInputValue(event.target.value)}
|
||||
/>
|
||||
<HorizontalSeparator
|
||||
color={theme.background.transparent.primary}
|
||||
noMargin
|
||||
/>
|
||||
{availableSteps.length > 0 ? (
|
||||
availableSteps.map((item, _index) => (
|
||||
<MenuItemSelect
|
||||
key={`step-${item.id}`}
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={() => onSelect(item.id)}
|
||||
text={item.name}
|
||||
LeftIcon={item.icon ? getIcon(item.icon) : undefined}
|
||||
hasSubMenu
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
{availableSteps.length > 0 ? (
|
||||
availableSteps.map((item, _index) => (
|
||||
<MenuItemSelect
|
||||
key={`step-${item.id}`}
|
||||
selected={false}
|
||||
hovered={false}
|
||||
onClick={() => onSelect(item.id)}
|
||||
text={item.name}
|
||||
LeftIcon={item.icon ? getIcon(item.icon) : undefined}
|
||||
hasSubMenu
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<MenuItem
|
||||
key="no-steps"
|
||||
onClick={() => {}}
|
||||
text="No variables available"
|
||||
LeftIcon={undefined}
|
||||
hasSubMenu={false}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<MenuItem
|
||||
key="no-steps"
|
||||
onClick={() => {}}
|
||||
text="No variables available"
|
||||
LeftIcon={undefined}
|
||||
hasSubMenu={false}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -19,7 +19,6 @@ export const DateTimeSettingsTimeZoneSelect = ({
|
||||
|
||||
return (
|
||||
<Select
|
||||
disableBlur
|
||||
dropdownId="settings-accounts-calendar-time-zone"
|
||||
label="Time zone"
|
||||
dropdownWidthAuto
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import { ThemeType } from '..';
|
||||
|
||||
export const OVERLAY_BACKGROUND = (props: { theme: ThemeType }) => css`
|
||||
backdrop-filter: ${props.theme.blur.medium};
|
||||
background: ${props.theme.background.transparent.secondary};
|
||||
box-shadow: ${props.theme.boxShadow.strong};
|
||||
`;
|
@ -25,7 +25,6 @@ export * from './constants/MainColorNames';
|
||||
export * from './constants/MainColors';
|
||||
export * from './constants/MobileViewport';
|
||||
export * from './constants/Modal';
|
||||
export * from './constants/OverlayBackground';
|
||||
export * from './constants/Rgba';
|
||||
export * from './constants/SecondaryColors';
|
||||
export * from './constants/SnackBarCommon';
|
||||
|
Loading…
Reference in New Issue
Block a user