Migrate to twenty-ui - input/button (#7994)

This PR was created by [GitStart](https://gitstart.com/) to address the
requirements from this ticket:
[TWNTY-7529](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-7529).

 --- 

### Description

- Migrated all button components to `twenty-ui`    \
  \
  `Button`\
  `ButtonGroup`\
  `ColorPickerButton`\
  `FloatingButton`\
  `FloatingButtonGroup`\
  `FloatingIconButton`\
  `FloatingIconButtonGroup`\
  `IconButton`\
  `IconButtonGroup`\
  `LightButton`\
  `LightIconButton`\
  `LightIconButtonGroup`\
  `MainButton`\
  \
  Fixes twentyhq/private-issues#89

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-app[bot]
2024-10-24 13:20:02 +02:00
committed by GitHub
parent 60e44ccf73
commit 0a28c15747
152 changed files with 450 additions and 505 deletions

View File

@ -3,8 +3,8 @@ import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { ChangeEvent, useRef } from 'react';
import { Button } from '@/ui/input/button/components/Button';
import { AppThemeProvider } from '@/ui/theme/components/AppThemeProvider';
import { Button } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';

View File

@ -1,7 +1,5 @@
import styled from '@emotion/styled';
import { IconArrowBackUp, IconUserCircle } from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { Button, IconArrowBackUp, IconUserCircle } from 'twenty-ui';
const StyledThreadBottomBar = styled.div`
align-items: center;

View File

@ -1,10 +1,9 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import { IconArrowsVertical } from 'twenty-ui';
import { Button, IconArrowsVertical } from 'twenty-ui';
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
import { EmailThreadMessageWithSender } from '@/activities/emails/types/EmailThreadMessageWithSender';
import { Button } from '@/ui/input/button/components/Button';
const StyledButtonContainer = styled.div`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};

View File

@ -9,12 +9,11 @@ import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMe
import { IntermediaryMessages } from '@/activities/emails/right-drawer/components/IntermediaryMessages';
import { useRightDrawerEmailThread } from '@/activities/emails/right-drawer/hooks/useRightDrawerEmailThread';
import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/states/lastViewableEmailThreadIdState';
import { Button } from '@/ui/input/button/components/Button';
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
import { messageThreadState } from '@/ui/layout/right-drawer/states/messageThreadState';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { IconArrowBackUp } from 'twenty-ui';
import { Button, IconArrowBackUp } from 'twenty-ui';
const StyledWrapper = styled.div`
display: flex;

View File

@ -3,9 +3,9 @@ import {
IconDownload,
IconPencil,
IconTrash,
LightIconButton,
} from 'twenty-ui';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -6,6 +6,7 @@ import {
AnimatedPlaceholderEmptySubTitle,
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
Button,
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
IconPlus,
} from 'twenty-ui';
@ -16,7 +17,6 @@ import { DropZone } from '@/activities/files/components/DropZone';
import { useAttachments } from '@/activities/files/hooks/useAttachments';
import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttachmentFile';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { Button } from '@/ui/input/button/components/Button';
import { isDefined } from '~/utils/isDefined';
const StyledAttachmentsContainer = styled.div`

View File

@ -1,3 +1,9 @@
import { SkeletonLoader } from '@/activities/components/SkeletonLoader';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { NoteList } from '@/activities/notes/components/NoteList';
import { useNotes } from '@/activities/notes/hooks/useNotes';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import styled from '@emotion/styled';
import {
AnimatedPlaceholder,
@ -5,18 +11,11 @@ import {
AnimatedPlaceholderEmptySubTitle,
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
Button,
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
IconPlus,
} from 'twenty-ui';
import { SkeletonLoader } from '@/activities/components/SkeletonLoader';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { NoteList } from '@/activities/notes/components/NoteList';
import { useNotes } from '@/activities/notes/hooks/useNotes';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { Button } from '@/ui/input/button/components/Button';
const StyledNotesContainer = styled.div`
display: flex;
flex: 1;

View File

@ -1,10 +1,9 @@
import { isNonEmptyArray } from '@sniptt/guards';
import { IconPlus } from 'twenty-ui';
import { Button, IconPlus } from 'twenty-ui';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { Button } from '@/ui/input/button/components/Button';
export const AddTaskButton = ({
activityTargetableObjects,

View File

@ -6,6 +6,7 @@ import {
AnimatedPlaceholderEmptySubTitle,
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
Button,
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
IconPlus,
} from 'twenty-ui';
@ -15,11 +16,9 @@ import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateAct
import { TASKS_TAB_LIST_COMPONENT_ID } from '@/activities/tasks/constants/TasksTabListComponentId';
import { useTasks } from '@/activities/tasks/hooks/useTasks';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { Button } from '@/ui/input/button/components/Button';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { Task } from '@/activities/types/Task';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import groupBy from 'lodash.groupby';
import { AddTaskButton } from './AddTaskButton';
import { TaskList } from './TaskList';

View File

@ -1,10 +1,13 @@
import { useSetRecoilState } from 'recoil';
import { IconCheckbox, IconNotes, IconPaperclip } from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup';
import { TAB_LIST_COMPONENT_ID } from '@/ui/layout/show-page/components/ShowPageSubContainer';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { useSetRecoilState } from 'recoil';
import {
Button,
ButtonGroup,
IconCheckbox,
IconNotes,
IconPaperclip,
} from 'twenty-ui';
export const TimelineCreateButtonGroup = ({
isInRightDrawer = false,

View File

@ -1,7 +1,5 @@
import styled from '@emotion/styled';
import { IconChevronDown, IconChevronUp } from 'twenty-ui';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { IconButton, IconChevronDown, IconChevronUp } from 'twenty-ui';
type EventCardToggleButtonProps = {
isOpen: boolean;

View File

@ -1,12 +1,3 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useMemo, useState } from 'react';
import { Controller } from 'react-hook-form';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { ActionLink, IconGoogle, IconKey, IconMicrosoft } from 'twenty-ui';
import { FooterNote } from '@/auth/sign-in-up/components/FooterNote';
import { HorizontalSeparator } from '@/auth/sign-in-up/components/HorizontalSeparator';
import { useHandleResetPassword } from '@/auth/sign-in-up/hooks/useHandleResetPassword';
@ -19,8 +10,21 @@ import { isRequestingCaptchaTokenState } from '@/captcha/states/isRequestingCapt
import { authProvidersState } from '@/client-config/states/authProvidersState';
import { captchaProviderState } from '@/client-config/states/captchaProviderState';
import { Loader } from '@/ui/feedback/loader/components/Loader';
import { MainButton } from '@/ui/input/button/components/MainButton';
import { TextInput } from '@/ui/input/components/TextInput';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useMemo, useState } from 'react';
import { Controller } from 'react-hook-form';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import {
ActionLink,
IconGoogle,
IconKey,
IconMicrosoft,
MainButton,
} from 'twenty-ui';
import { isDefined } from '~/utils/isDefined';
const StyledContentContainer = styled.div`

View File

@ -16,7 +16,6 @@ import { getCompanyDomainName } from '@/object-metadata/utils/getCompanyDomainNa
import { useSearchRecords } from '@/object-record/hooks/useSearchRecords';
import { Opportunity } from '@/opportunities/types/Opportunity';
import { Person } from '@/people/types/Person';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@ -30,7 +29,14 @@ import { isNonEmptyString } from '@sniptt/guards';
import { useMemo, useRef } from 'react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { Avatar, IconNotes, IconSparkles, IconX, isDefined } from 'twenty-ui';
import {
Avatar,
IconNotes,
IconSparkles,
IconX,
LightIconButton,
isDefined,
} from 'twenty-ui';
import { useDebounce } from 'use-debounce';
import { getLogoUrlFromDomainName } from '~/utils';

View File

@ -9,11 +9,10 @@ import {
AnimatedPlaceholderEmptySubTitle,
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
Button,
IconRefresh,
THEME_LIGHT,
} from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
type GenericErrorFallbackProps = FallbackProps;

View File

@ -1,6 +1,5 @@
import { Button } from '@/ui/input/button/components/Button';
import styled from '@emotion/styled';
import { Banner, BannerVariant, IconComponent } from 'twenty-ui';
import { Banner, BannerVariant, Button, IconComponent } from 'twenty-ui';
const StyledBanner = styled(Banner)`
position: absolute;

View File

@ -1,6 +1,4 @@
import { IconX } from 'twenty-ui';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { IconButton, IconX } from 'twenty-ui';
import {
StyledContainer,

View File

@ -1,8 +1,7 @@
import { IconPlus } from 'twenty-ui';
import { IconPlus, LightButton } from 'twenty-ui';
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { LightButton } from '@/ui/input/button/components/LightButton';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
type AddObjectFilterFromDetailsButtonProps = {

View File

@ -17,7 +17,6 @@ import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/
import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Checkbox, CheckboxVariant } from '@/ui/input/components/Checkbox';
import { TextInput } from '@/ui/input/components/TextInput';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
@ -33,6 +32,7 @@ import {
ChipSize,
IconEye,
IconEyeOff,
LightIconButton,
} from 'twenty-ui';
import { useDebouncedCallback } from 'use-debounce';
import { useAddNewCard } from '../../record-board-column/hooks/useAddNewCard';

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { useContext, useState } from 'react';
import { IconDotsVertical, IconPlus, Tag } from 'twenty-ui';
import { IconDotsVertical, IconPlus, LightIconButton, Tag } from 'twenty-ui';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
@ -12,7 +12,6 @@ import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-b
import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope';
import { RecordBoardColumnDefinitionType } from '@/object-record/record-board/types/RecordBoardColumnDefinition';
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
const StyledHeader = styled.div`

View File

@ -1,10 +1,9 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconCopy } from 'twenty-ui';
import { IconCopy, LightIconButton } from 'twenty-ui';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
const StyledButtonContainer = styled.div`
padding: 0 ${({ theme }) => theme.spacing(1)};

View File

@ -1,10 +1,9 @@
import styled from '@emotion/styled';
import React, { useRef, useState } from 'react';
import { Key } from 'ts-key-enum';
import { IconCheck, IconPlus } from 'twenty-ui';
import { IconCheck, IconPlus, LightIconButton } from 'twenty-ui';
import { PhoneRecord } from '@/object-record/record-field/types/FieldMetadata';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import {
DropdownMenuInput,

View File

@ -7,7 +7,6 @@ import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/
import { RecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem';
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@ -15,7 +14,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import styled from '@emotion/styled';
import { useCallback, useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { IconPlus } from 'twenty-ui';
import { IconButton, IconPlus } from 'twenty-ui';
const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
width: 100%;

View File

@ -1,7 +1,9 @@
import styled from '@emotion/styled';
import { AnimatedContainer, IconComponent } from 'twenty-ui';
import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton';
import {
AnimatedContainer,
FloatingIconButton,
IconComponent,
} from 'twenty-ui';
const StyledInlineCellButtonContainer = styled.div`
align-items: center;

View File

@ -9,6 +9,7 @@ import {
IconDotsVertical,
IconTrash,
IconUnlink,
LightIconButton,
} from 'twenty-ui';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
@ -33,7 +34,6 @@ import { RecordDetailRecordsListItem } from '@/object-record/record-show/record-
import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';

View File

@ -2,7 +2,7 @@ import styled from '@emotion/styled';
import qs from 'qs';
import { useCallback, useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { IconForbid, IconPencil, IconPlus } from 'twenty-ui';
import { IconForbid, IconPencil, IconPlus, LightIconButton } from 'twenty-ui';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
@ -26,7 +26,6 @@ import { EntityForSelect } from '@/object-record/relation-picker/types/EntityFor
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';

View File

@ -1,6 +1,5 @@
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { Button } from '@/ui/input/button/components/Button';
import { useContext } from 'react';
import {
AnimatedPlaceholder,
@ -9,6 +8,7 @@ import {
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
AnimatedPlaceholderType,
Button,
IconComponent,
} from 'twenty-ui';

View File

@ -1,7 +1,9 @@
import styled from '@emotion/styled';
import { AnimatedContainer, IconComponent } from 'twenty-ui';
import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton';
import {
AnimatedContainer,
FloatingIconButton,
IconComponent,
} from 'twenty-ui';
const StyledButtonContainer = styled.div`
margin: ${({ theme }) => theme.spacing(1)};

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import { useCallback, useMemo, useState } from 'react';
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
import { IconPlus } from 'twenty-ui';
import { IconPlus, LightIconButton } from 'twenty-ui';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
@ -12,7 +12,6 @@ import { useTableColumns } from '@/object-record/record-table/hooks/useTableColu
import { RecordTableColumnHeadWithDropdown } from '@/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown';
import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';

View File

@ -1,12 +1,12 @@
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { Key } from 'ts-key-enum';
import { z } from 'zod';
import { Button } from '@/ui/input/button/components/Button';
import { TextInput } from '@/ui/input/components/TextInput';
import { Button } from 'twenty-ui';
import { isDomain } from '~/utils/is-domain';
const StyledContainer = styled.div`

View File

@ -1,9 +1,7 @@
import { IconX, OverflowingTextWithTooltip } from 'twenty-ui';
import { BlocklistItem } from '@/accounts/types/BlocklistItem';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { IconButton, IconX, OverflowingTextWithTooltip } from 'twenty-ui';
import { formatToHumanReadableDate } from '~/utils/date-utils';
type SettingsAccountsBlocklistTableRowProps = {

View File

@ -1,8 +1,7 @@
import styled from '@emotion/styled';
import { IconGoogle } from 'twenty-ui';
import { Button, IconGoogle } from 'twenty-ui';
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
import { Button } from '@/ui/input/button/components/Button';
import { Card } from '@/ui/layout/card/components/Card';
import { CardContent } from '@/ui/layout/card/components/CardContent';
import { CardHeader } from '@/ui/layout/card/components/CardHeader';

View File

@ -5,13 +5,13 @@ import {
IconMail,
IconRefresh,
IconTrash,
LightIconButton,
} from 'twenty-ui';
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useDestroyOneRecord } from '@/object-record/hooks/useDestroyOneRecord';
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -1,4 +1,4 @@
import { LightButton } from '@/ui/input/button/components/LightButton';
import { LightButton } from 'twenty-ui';
type CancelButtonProps = {
onCancel?: () => void;

View File

@ -1,6 +1,4 @@
import { IconDeviceFloppy } from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { Button, IconDeviceFloppy } from 'twenty-ui';
type SaveButtonProps = {
onSave?: () => void;

View File

@ -1,5 +1,4 @@
import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
import { Button } from '@/ui/input/button/components/Button';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@ -13,7 +12,7 @@ import {
useParams,
useSearchParams,
} from 'react-router-dom';
import { IconChevronDown, isDefined } from 'twenty-ui';
import { Button, IconChevronDown, isDefined } from 'twenty-ui';
const StyledContainer = styled.div`
align-items: center;

View File

@ -1,8 +1,7 @@
import styled from '@emotion/styled';
import { Button } from '@/ui/input/button/components/Button';
import { TextInput } from '@/ui/input/components/TextInput';
import { IconInfoCircle, IconMinus, IconPlus } from 'twenty-ui';
import { Button, IconInfoCircle, IconMinus, IconPlus } from 'twenty-ui';
import { castAsNumberOrNull } from '~/utils/cast-as-number-or-null';
type SettingsDataModelFieldNumberDecimalsInputProps = {

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import { DropResult } from '@hello-pangea/dnd';
import { Controller, useFormContext } from 'react-hook-form';
import { IconPlus, IconTool, MAIN_COLORS } from 'twenty-ui';
import { IconPlus, IconTool, LightButton, MAIN_COLORS } from 'twenty-ui';
import { z } from 'zod';
import {
@ -14,7 +14,6 @@ import { selectFieldDefaultValueSchema } from '@/object-record/record-field/vali
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
import { generateNewSelectOption } from '@/settings/data-model/fields/forms/select/utils/generateNewSelectOption';
import { isSelectOptionDefaultValue } from '@/settings/data-model/utils/isSelectOptionDefaultValue';
import { LightButton } from '@/ui/input/button/components/LightButton';
import { CardContent } from '@/ui/layout/card/components/CardContent';
import { CardFooter } from '@/ui/layout/card/components/CardFooter';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';

View File

@ -8,6 +8,7 @@ import {
IconGripVertical,
IconTrash,
IconX,
LightIconButton,
MAIN_COLOR_NAMES,
} from 'twenty-ui';
import { v4 } from 'uuid';
@ -16,7 +17,6 @@ import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataIt
import { EXPANDED_WIDTH_ANIMATION_VARIANTS } from '@/settings/constants/ExpandedWidthAnimationVariants';
import { OPTION_VALUE_MAXIMUM_LENGTH } from '@/settings/data-model/constants/OptionValueMaximumLength';
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { TextInput } from '@/ui/input/components/TextInput';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';

View File

@ -1,3 +1,7 @@
import { SettingsDataModelOverviewEffect } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect';
import { SettingsDataModelOverviewObject } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject';
import { SettingsDataModelOverviewRelationMarkers } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers';
import { calculateHandlePosition } from '@/settings/data-model/graph-overview/utils/calculateHandlePosition';
import styled from '@emotion/styled';
import { useCallback, useState } from 'react';
import ReactFlow, {
@ -13,6 +17,8 @@ import ReactFlow, {
useReactFlow,
} from 'reactflow';
import {
Button,
IconButtonGroup,
IconLock,
IconLockOpen,
IconMaximize,
@ -20,17 +26,8 @@ import {
IconPlus,
IconX,
} from 'twenty-ui';
import { SettingsDataModelOverviewEffect } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect';
import { SettingsDataModelOverviewObject } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject';
import { SettingsDataModelOverviewRelationMarkers } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers';
import { calculateHandlePosition } from '@/settings/data-model/graph-overview/utils/calculateHandlePosition';
import { Button } from '@/ui/input/button/components/Button';
import { IconButtonGroup } from '@/ui/input/button/components/IconButtonGroup';
import { isDefined } from '~/utils/isDefined';
import 'reactflow/dist/style.css';
const NodeTypes = {
object: SettingsDataModelOverviewObject,
};

View File

@ -4,9 +4,9 @@ import {
IconEye,
IconPencil,
IconTextSize,
LightIconButton,
} from 'twenty-ui';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -4,9 +4,9 @@ import {
IconEye,
IconPencil,
IconTrash,
LightIconButton,
} from 'twenty-ui';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -1,22 +1,11 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useMemo } from 'react';
import { IconMinus, IconPlus, isDefined, useIcons } from 'twenty-ui';
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
import { isFieldTypeSupportedInSettings } from '@/settings/data-model/utils/isFieldTypeSupportedInSettings';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { RELATION_TYPES } from '../../constants/RelationTypes';
import { LABEL_IDENTIFIER_FIELD_METADATA_TYPES } from '@/object-metadata/constants/LabelIdentifierFieldMetadataTypes';
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getFieldSlug } from '@/object-metadata/utils/getFieldSlug';
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
import { useDeleteRecordFromCache } from '@/object-record/cache/hooks/useDeleteRecordFromCache';
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
@ -24,13 +13,26 @@ import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
import { SettingsObjectFieldActiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown';
import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown';
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { isFieldTypeSupportedInSettings } from '@/settings/data-model/utils/isFieldTypeSupportedInSettings';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
import { View } from '@/views/types/View';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import {
IconMinus,
IconPlus,
LightIconButton,
isDefined,
useIcons,
} from 'twenty-ui';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { SettingsObjectDetailTableItem } from '~/pages/settings/data-model/types/SettingsObjectDetailTableItem';
import { RELATION_TYPES } from '../../constants/RelationTypes';
import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType';
type SettingsObjectFieldItemTableRowProps = {

View File

@ -1,6 +1,12 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconArchive, IconDotsVertical, IconPencil, useIcons } from 'twenty-ui';
import {
IconArchive,
IconDotsVertical,
IconPencil,
LightIconButton,
useIcons,
} from 'twenty-ui';
import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem';
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
@ -8,7 +14,6 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag';
import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -1,7 +1,6 @@
import styled from '@emotion/styled';
import { IconEye } from 'twenty-ui';
import { FloatingButton, IconEye } from 'twenty-ui';
import { FloatingButton } from '@/ui/input/button/components/FloatingButton';
import { Card } from '@/ui/layout/card/components/Card';
import { SettingsPath } from '@/types/SettingsPath';

View File

@ -1,6 +1,10 @@
import { IconArchiveOff, IconDotsVertical, IconTrash } from 'twenty-ui';
import {
IconArchiveOff,
IconDotsVertical,
IconTrash,
LightIconButton,
} from 'twenty-ui';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -1,10 +1,9 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconCopy } from 'twenty-ui';
import { Button, IconCopy } from 'twenty-ui';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Button } from '@/ui/input/button/components/Button';
import { TextInput } from '@/ui/input/components/TextInput';
const StyledContainer = styled.div`

View File

@ -1,6 +1,4 @@
import { IconBook2 } from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { Button, IconBook2 } from 'twenty-ui';
export const SettingsReadDocumentationButton = () => {
return (

View File

@ -1,11 +1,10 @@
import { Link } from 'react-router-dom';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { IconArrowUpRight, IconBolt, IconPlus, Pill } from 'twenty-ui';
import { Link } from 'react-router-dom';
import { Button, IconArrowUpRight, IconBolt, IconPlus, Pill } from 'twenty-ui';
import { SettingsIntegration } from '@/settings/integrations/types/SettingsIntegration';
import { Status } from '@/ui/display/status/components/Status';
import { Button } from '@/ui/input/button/components/Button';
import { isDefined } from '~/utils/isDefined';
interface SettingsIntegrationComponentProps {

View File

@ -1,8 +1,7 @@
import { FetchResult } from '@apollo/client';
import styled from '@emotion/styled';
import { IconReload } from 'twenty-ui';
import { Button, IconReload } from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { SyncRemoteTableSchemaChangesMutation } from '~/generated-metadata/graphql';
const StyledText = styled.h3`

View File

@ -1,19 +1,18 @@
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
import { SettingsIntegrationDatabaseConnectionSyncStatus } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus';
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 { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import styled from '@emotion/styled';
import {
IconDotsVertical,
IconPencil,
IconTrash,
LightIconButton,
UndecoratedLink,
} from 'twenty-ui';
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
import { SettingsIntegrationDatabaseConnectionSyncStatus } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
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 { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
type SettingsIntegrationDatabaseConnectionSummaryCardProps = {
databaseLogoUrl: string;
connectionId: string;

View File

@ -1,11 +1,10 @@
import { useNavigate } from 'react-router-dom';
import styled from '@emotion/styled';
import { IconChevronRight } from 'twenty-ui';
import { useNavigate } from 'react-router-dom';
import { IconChevronRight, LightIconButton } from 'twenty-ui';
import { SettingsListCard } from '@/settings/components/SettingsListCard';
import { SettingsIntegrationDatabaseConnectionSyncStatus } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus';
import { SettingsIntegration } from '@/settings/integrations/types/SettingsIntegration';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { RemoteServer } from '~/generated-metadata/graphql';
type SettingsIntegrationDatabaseConnectionsListCardProps = {

View File

@ -1,10 +1,9 @@
import { useRecoilValue } from 'recoil';
import { H2Title } from 'twenty-ui';
import { Button, H2Title } from 'twenty-ui';
import { currentUserState } from '@/auth/states/currentUserState';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Button } from '@/ui/input/button/components/Button';
import { useEmailPasswordResetLinkMutation } from '~/generated/graphql';
export const ChangePassword = () => {

View File

@ -1,10 +1,9 @@
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { H2Title } from 'twenty-ui';
import { Button, H2Title } from 'twenty-ui';
import { useAuth } from '@/auth/hooks/useAuth';
import { currentUserState } from '@/auth/states/currentUserState';
import { Button } from '@/ui/input/button/components/Button';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useDeleteUserAccountMutation } from '~/generated/graphql';

View File

@ -1,12 +1,11 @@
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { H2Title, IconTrash } from 'twenty-ui';
import { Button, H2Title, IconTrash } from 'twenty-ui';
import { useAuth } from '@/auth/hooks/useAuth';
import { currentUserState } from '@/auth/states/currentUserState';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useDeleteCurrentWorkspaceMutation } from '~/generated/graphql';
import { Button } from '@/ui/input/button/components/Button';
export const DeleteWorkspace = () => {
const [isDeleteWorkSpaceModalOpen, setIsDeleteWorkSpaceModalOpen] =
useState(false);

View File

@ -1,14 +1,12 @@
/* @license Enterprise */
import styled from '@emotion/styled';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { Button } from '@/ui/input/button/components/Button';
import { Card } from '@/ui/layout/card/components/Card';
import { CardContent } from '@/ui/layout/card/components/CardContent';
import { CardHeader } from '@/ui/layout/card/components/CardHeader';
import { IconKey } from 'twenty-ui';
import styled from '@emotion/styled';
import { Button, IconKey } from 'twenty-ui';
const StyledHeader = styled(CardHeader)`
align-items: center;

View File

@ -2,13 +2,12 @@
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Button } from '@/ui/input/button/components/Button';
import { TextInput } from '@/ui/input/components/TextInput';
import { Section } from '@/ui/layout/section/components/Section';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { Controller, useFormContext } from 'react-hook-form';
import { H2Title, IconCopy } from 'twenty-ui';
import { Button, H2Title, IconCopy } from 'twenty-ui';
const StyledInputsContainer = styled.div`
display: flex;

View File

@ -4,7 +4,6 @@ import { HorizontalSeparator } from '@/auth/sign-in-up/components/HorizontalSepa
import { parseSAMLMetadataFromXMLFile } from '@/settings/security/utils/parseSAMLMetadataFromXMLFile';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Button } from '@/ui/input/button/components/Button';
import { TextInput } from '@/ui/input/components/TextInput';
import { Section } from '@/ui/layout/section/components/Section';
import { useTheme } from '@emotion/react';
@ -12,6 +11,7 @@ import styled from '@emotion/styled';
import { ChangeEvent, useRef } from 'react';
import { useFormContext } from 'react-hook-form';
import {
Button,
H2Title,
IconCheck,
IconCopy,

View File

@ -1,13 +1,17 @@
/* @license Enterprise */
import { IconArchive, IconDotsVertical, IconTrash } from 'twenty-ui';
import {
IconArchive,
IconDotsVertical,
IconTrash,
LightIconButton,
} from 'twenty-ui';
import { useDeleteSSOIdentityProvider } from '@/settings/security/hooks/useDeleteSSOIdentityProvider';
import { useUpdateSSOIdentityProvider } from '@/settings/security/hooks/useUpdateSSOIdentityProvider';
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProviders.state';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';

View File

@ -1,6 +1,5 @@
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { Button } from '@/ui/input/button/components/Button';
import styled from '@emotion/styled';
import {
AnimatedPlaceholder,
@ -8,6 +7,7 @@ import {
AnimatedPlaceholderEmptySubTitle,
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
Button,
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
IconPlus,
} from 'twenty-ui';

View File

@ -6,7 +6,6 @@ import { SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/settings/s
import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { Button } from '@/ui/input/button/components/Button';
import { CoreEditorHeader } from '@/ui/input/code-editor/components/CodeEditorHeader';
import { Section } from '@/ui/layout/section/components/Section';
import { TabList } from '@/ui/layout/tab/components/TabList';
@ -16,7 +15,13 @@ import styled from '@emotion/styled';
import { useNavigate } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { H2Title, IconGitCommit, IconPlayerPlay, IconRestore } from 'twenty-ui';
import {
Button,
H2Title,
IconGitCommit,
IconPlayerPlay,
IconRestore,
} from 'twenty-ui';
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
const StyledTabList = styled(TabList)`

View File

@ -4,14 +4,13 @@ import { ServerlessFunctionFormValues } from '@/settings/serverless-functions/ho
import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { Button } from '@/ui/input/button/components/Button';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { Section } from '@/ui/layout/section/components/Section';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Key } from 'ts-key-enum';
import { H2Title } from 'twenty-ui';
import { Button, H2Title } from 'twenty-ui';
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
import { SettingsServerlessFunctionTabEnvironmentVariablesSection } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariablesSection';

View File

@ -1,23 +1,23 @@
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { EnvironmentVariable } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariablesSection';
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
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';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import styled from '@emotion/styled';
import { useState } from 'react';
import {
IconCheck,
IconDotsVertical,
IconPencil,
IconTrash,
IconX,
LightIconButton,
OverflowingTextWithTooltip,
} from 'twenty-ui';
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 { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import React, { useState } from 'react';
import styled from '@emotion/styled';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { EnvironmentVariable } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariablesSection';
const StyledEditModeTableRow = styled(TableRow)`
grid-template-columns: 180px auto 56px;

View File

@ -1,16 +1,21 @@
import dotenv from 'dotenv';
import { H2Title, IconPlus, IconSearch, MOBILE_VIEWPORT } from 'twenty-ui';
import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { Section } from '@/ui/layout/section/components/Section';
import { TextInput } from '@/ui/input/components/TextInput';
import styled from '@emotion/styled';
import React, { useMemo, useState } from 'react';
import { TableBody } from '@/ui/layout/table/components/TableBody';
import { Button } from '@/ui/input/button/components/Button';
import { ServerlessFunctionFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { SettingsServerlessFunctionTabEnvironmentVariableTableRow } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariableTableRow';
import { ServerlessFunctionFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { TextInput } from '@/ui/input/components/TextInput';
import { Section } from '@/ui/layout/section/components/Section';
import { Table } from '@/ui/layout/table/components/Table';
import { TableBody } from '@/ui/layout/table/components/TableBody';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import dotenv from 'dotenv';
import { useMemo, useState } from 'react';
import {
Button,
H2Title,
IconPlus,
IconSearch,
MOBILE_VIEWPORT,
} from 'twenty-ui';
import { v4 } from 'uuid';
const StyledSearchInput = styled(TextInput)`

View File

@ -1,5 +1,5 @@
import { Section } from '@/ui/layout/section/components/Section';
import { H2Title, IconPlayerPlay } from 'twenty-ui';
import { Button, H2Title, IconPlayerPlay } from 'twenty-ui';
import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
import { SettingsServerlessFunctionCodeEditorContainer } from '@/settings/serverless-functions/components/SettingsServerlessFunctionCodeEditorContainer';
@ -10,7 +10,6 @@ import { settingsServerlessFunctionOutputState } from '@/settings/serverless-fun
import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { Button } from '@/ui/input/button/components/Button';
import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor';
import { CoreEditorHeader } from '@/ui/input/code-editor/components/CodeEditorHeader';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';

View File

@ -1,10 +1,9 @@
import styled from '@emotion/styled';
import { IconX } from 'twenty-ui';
import { IconButton, IconX } from 'twenty-ui';
import { useSpreadsheetImportInitialStep } from '@/spreadsheet-import/hooks/useSpreadsheetImportInitialStep';
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { useStepBar } from '@/ui/navigation/step-bar/hooks/useStepBar';
const StyledCloseButtonContainer = styled.div`

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import { CircularProgressBar } from '@/ui/feedback/progress-bar/components/CircularProgressBar';
import { MainButton } from '@/ui/input/button/components/MainButton';
import { MainButton } from 'twenty-ui';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';

View File

@ -7,7 +7,7 @@ import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpre
import { readFileAsync } from '@/spreadsheet-import/utils/readFilesAsync';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { MainButton } from '@/ui/input/button/components/MainButton';
import { MainButton } from 'twenty-ui';
const StyledContainer = styled.div`
align-items: center;

View File

@ -1,3 +1,20 @@
import { Heading } from '@/spreadsheet-import/components/Heading';
import { SpreadsheetImportTable } from '@/spreadsheet-import/components/SpreadsheetImportTable';
import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton';
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
import {
ColumnType,
Columns,
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';
import {
ImportValidationResult,
ImportedStructuredRow,
} from '@/spreadsheet-import/types';
import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations';
import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
import { Modal } from '@/ui/layout/modal/components/Modal';
import styled from '@emotion/styled';
import {
Dispatch,
@ -8,28 +25,8 @@ import {
} from 'react';
// @ts-expect-error Todo: remove usage of react-data-grid`
import { RowsChangeData } from 'react-data-grid';
import { IconTrash, Toggle } from 'twenty-ui';
import { Heading } from '@/spreadsheet-import/components/Heading';
import { SpreadsheetImportTable } from '@/spreadsheet-import/components/SpreadsheetImportTable';
import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton';
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
import {
Columns,
ColumnType,
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
import {
ImportedStructuredRow,
ImportValidationResult,
} from '@/spreadsheet-import/types';
import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations';
import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
import { Button } from '@/ui/input/button/components/Button';
import { Button, IconTrash, Toggle } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined';
import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { generateColumns } from './components/columns';
import { ImportedStructuredRowMetadata } from './types';

View File

@ -1,9 +1,8 @@
import styled from '@emotion/styled';
import { IconHelpCircle } from 'twenty-ui';
import { Button, IconHelpCircle } from 'twenty-ui';
import { SupportButtonSkeletonLoader } from '@/support/components/SupportButtonSkeletonLoader';
import { useSupportChat } from '@/support/hooks/useSupportChat';
import { Button } from '@/ui/input/button/components/Button';
const StyledButtonContainer = styled.div`
display: flex;

View File

@ -1,11 +1,10 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconInfoCircle } from 'twenty-ui';
import React from 'react';
import { Link } from 'react-router-dom';
import { Button, IconInfoCircle } from 'twenty-ui';
import { AppPath } from '@/types/AppPath';
import { Button } from '@/ui/input/button/components/Button';
export type InfoAccent = 'blue' | 'danger';
export type InfoProps = {

View File

@ -3,8 +3,8 @@ import { motion } from 'framer-motion';
import { useCallback } from 'react';
import { Key } from 'ts-key-enum';
import { Button } from '@/ui/input/button/components/Button';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { Button } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined';
import { DialogHotkeyScope } from '../types/DialogHotkeyScope';

View File

@ -7,13 +7,13 @@ import {
IconInfoCircle,
IconSquareRoundedCheck,
IconX,
LightButton,
LightIconButton,
MOBILE_VIEWPORT,
} from 'twenty-ui';
import { ProgressBar } from '@/ui/feedback/progress-bar/components/ProgressBar';
import { useProgressAnimation } from '@/ui/feedback/progress-bar/hooks/useProgressAnimation';
import { LightButton } from '@/ui/input/button/components/LightButton';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { isDefined } from '~/utils/isDefined';
export enum SnackBarVariant {

View File

@ -1,406 +0,0 @@
import isPropValid from '@emotion/is-prop-valid';
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import React from 'react';
import { Link } from 'react-router-dom';
import { IconComponent, Pill } from 'twenty-ui';
export type ButtonSize = 'medium' | 'small';
export type ButtonPosition = 'standalone' | 'left' | 'middle' | 'right';
export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
export type ButtonAccent = 'default' | 'blue' | 'danger';
export type ButtonProps = {
className?: string;
Icon?: IconComponent;
title?: string;
fullWidth?: boolean;
variant?: ButtonVariant;
inverted?: boolean;
size?: ButtonSize;
position?: ButtonPosition;
accent?: ButtonAccent;
soon?: boolean;
justify?: 'center' | 'flex-start' | 'flex-end';
disabled?: boolean;
focus?: boolean;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
to?: string;
target?: string;
dataTestId?: string;
} & React.ComponentProps<'button'>;
const StyledButton = styled('button', {
shouldForwardProp: (prop) =>
!['fullWidth'].includes(prop) && isPropValid(prop),
})<
Pick<
ButtonProps,
| 'fullWidth'
| 'variant'
| 'inverted'
| 'size'
| 'position'
| 'accent'
| 'focus'
| 'justify'
| 'to'
| 'target'
>
>`
align-items: center;
${({ theme, variant, inverted, accent, disabled, focus }) => {
switch (variant) {
case 'primary':
switch (accent) {
case 'default':
return css`
background: ${!inverted
? theme.background.secondary
: theme.background.primary};
border-color: ${!inverted
? focus
? theme.color.blue
: theme.background.transparent.light
: theme.background.transparent.light};
border-width: 1px 1px 1px 1px !important;
opacity: ${disabled ? 0.24 : 1};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${
!inverted
? theme.accent.tertiary
: theme.background.transparent.medium
}`
: 'none'};
color: ${!inverted
? !disabled
? theme.font.color.secondary
: theme.font.color.extraLight
: theme.font.color.secondary};
&:hover {
background: ${!inverted
? theme.background.tertiary
: theme.background.secondary};
}
&:active {
background: ${!inverted
? theme.background.quaternary
: theme.background.tertiary};
}
`;
case 'blue':
return css`
background: ${!inverted
? theme.color.blue
: theme.background.primary};
border-color: ${!inverted
? focus
? theme.color.blue
: theme.background.transparent.light
: theme.background.transparent.light};
border-width: 1px 1px 1px 1px !important;
box-shadow: ${!disabled && focus
? `0 0 0 3px ${
!inverted
? theme.accent.tertiary
: theme.background.transparent.medium
}`
: 'none'};
color: ${!inverted ? theme.grayScale.gray0 : theme.color.blue};
opacity: ${disabled ? 0.24 : 1};
${disabled
? ''
: css`
&:hover {
background: ${!inverted
? theme.color.blue50
: theme.background.secondary};
}
&:active {
background: ${!inverted
? theme.color.blue60
: theme.background.tertiary};
}
`}
`;
case 'danger':
return css`
background: ${!inverted
? theme.color.red
: theme.background.primary};
border-color: ${!inverted
? focus
? theme.color.red
: theme.background.transparent.light
: theme.background.transparent.light};
border-width: 1px 1px !important;
box-shadow: ${!disabled && focus
? `0 0 0 3px ${
!inverted
? theme.color.red10
: theme.background.transparent.medium
}`
: 'none'};
color: ${!inverted ? theme.background.primary : theme.color.red};
opacity: ${disabled ? 0.24 : 1};
${disabled
? ''
: css`
&:hover {
background: ${!inverted
? theme.color.red40
: theme.background.secondary};
}
&:active {
background: ${!inverted
? theme.color.red50
: theme.background.tertiary};
}
`}
`;
}
break;
case 'secondary':
case 'tertiary':
switch (accent) {
case 'default':
return css`
background: transparent;
border-color: ${!inverted
? variant === 'secondary'
? !disabled && focus
? theme.color.blue
: theme.background.transparent.medium
: focus
? theme.color.blue
: 'transparent'
: variant === 'secondary'
? focus || disabled
? theme.grayScale.gray0
: theme.background.transparent.primary
: focus
? theme.grayScale.gray0
: 'transparent'};
border-width: 1px 1px 1px 1px !important;
box-shadow: ${!disabled && focus
? `0 0 0 3px ${
!inverted
? theme.accent.tertiary
: theme.background.transparent.medium
}`
: 'none'};
opacity: ${disabled ? 0.24 : 1};
color: ${!inverted
? !disabled
? theme.font.color.secondary
: theme.font.color.extraLight
: theme.font.color.inverted};
&:hover {
background: ${!inverted
? !disabled
? theme.background.transparent.light
: 'transparent'
: theme.background.transparent.light};
}
&:active {
background: ${!inverted
? !disabled
? theme.background.transparent.light
: 'transparent'
: theme.background.transparent.medium};
}
`;
case 'blue':
return css`
background: transparent;
border-color: ${!inverted
? variant === 'secondary'
? focus
? theme.color.blue
: theme.accent.primary
: focus
? theme.color.blue
: 'transparent'
: variant === 'secondary'
? focus || disabled
? theme.grayScale.gray0
: theme.background.transparent.primary
: focus
? theme.grayScale.gray0
: 'transparent'};
border-width: 1px 1px 1px 1px !important;
box-shadow: ${!disabled && focus
? `0 0 0 3px ${
!inverted
? theme.accent.tertiary
: theme.background.transparent.medium
}`
: 'none'};
opacity: ${disabled ? 0.24 : 1};
color: ${!inverted
? !disabled
? theme.color.blue
: theme.accent.accent4060
: theme.font.color.inverted};
&:hover {
background: ${!inverted
? !disabled
? theme.accent.tertiary
: 'transparent'
: theme.background.transparent.light};
}
&:active {
background: ${!inverted
? !disabled
? theme.accent.secondary
: 'transparent'
: theme.background.transparent.medium};
}
`;
case 'danger':
return css`
background: transparent;
border-color: ${!inverted
? variant === 'secondary'
? focus
? theme.color.red
: theme.border.color.danger
: focus
? theme.color.red
: 'transparent'
: variant === 'secondary'
? focus || disabled
? theme.grayScale.gray0
: theme.background.transparent.primary
: focus
? theme.grayScale.gray0
: 'transparent'};
border-width: 1px 1px 1px 1px !important;
box-shadow: ${!disabled && focus
? `0 0 0 3px ${
!inverted
? theme.color.red10
: theme.background.transparent.medium
}`
: 'none'};
opacity: ${disabled ? 0.24 : 1};
color: ${!inverted
? !disabled
? theme.font.color.danger
: theme.color.red20
: theme.font.color.inverted};
&:hover {
background: ${!inverted
? !disabled
? theme.background.danger
: 'transparent'
: theme.background.transparent.light};
}
&:active {
background: ${!inverted
? !disabled
? theme.background.danger
: 'transparent'
: theme.background.transparent.medium};
}
`;
}
}
}}
text-decoration: none;
border-radius: ${({ position, theme }) => {
switch (position) {
case 'left':
return `${theme.border.radius.sm} 0px 0px ${theme.border.radius.sm}`;
case 'right':
return `0px ${theme.border.radius.sm} ${theme.border.radius.sm} 0px`;
case 'middle':
return '0px';
case 'standalone':
return theme.border.radius.sm;
}
}};
border-style: solid;
border-width: ${({ variant, position }) => {
switch (variant) {
case 'primary':
case 'secondary':
return position === 'middle' ? '1px 0px' : '1px';
case 'tertiary':
return '0';
}
}};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: 500;
font-size: ${({ theme }) => theme.font.size.md};
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
justify-content: ${({ justify }) => justify};
padding: ${({ theme }) => {
return `0 ${theme.spacing(2)}`;
}};
transition: background 0.1s ease;
white-space: nowrap;
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
&:focus {
outline: none;
}
`;
const StyledSoonPill = styled(Pill)`
margin-left: auto;
`;
export const Button = ({
className,
Icon,
title,
fullWidth = false,
variant = 'primary',
inverted = false,
size = 'medium',
accent = 'default',
position = 'standalone',
soon = false,
disabled = false,
justify = 'flex-start',
focus = false,
onClick,
to,
target,
dataTestId,
}: ButtonProps) => {
const theme = useTheme();
return (
<StyledButton
fullWidth={fullWidth}
variant={variant}
inverted={inverted}
size={size}
position={position}
disabled={soon || disabled}
focus={focus}
justify={justify}
accent={accent}
className={className}
onClick={onClick}
to={to}
as={to ? Link : 'button'}
target={target}
data-testid={dataTestId}
>
{Icon && <Icon size={theme.icon.size.sm} />}
{title}
{soon && <StyledSoonPill label="Soon" />}
</StyledButton>
);
};

View File

@ -1,59 +0,0 @@
import React, { ReactNode } from 'react';
import styled from '@emotion/styled';
import { isDefined } from '~/utils/isDefined';
import { ButtonPosition, ButtonProps } from './Button';
const StyledButtonGroupContainer = styled.div`
border-radius: ${({ theme }) => theme.border.radius.md};
display: flex;
`;
export type ButtonGroupProps = Pick<
ButtonProps,
'variant' | 'size' | 'accent'
> & {
className?: string;
children: ReactNode[];
};
export const ButtonGroup = ({
className,
children,
variant,
size,
accent,
}: ButtonGroupProps) => (
<StyledButtonGroupContainer className={className}>
{React.Children.map(children, (child, index) => {
if (!React.isValidElement(child)) return null;
let position: ButtonPosition;
if (index === 0) {
position = 'left';
} else if (index === children.length - 1) {
position = 'right';
} else {
position = 'middle';
}
const additionalProps: any = { position, variant, accent, size };
if (isDefined(variant)) {
additionalProps.variant = variant;
}
if (isDefined(accent)) {
additionalProps.variant = variant;
}
if (isDefined(size)) {
additionalProps.size = size;
}
return React.cloneElement(child, additionalProps);
})}
</StyledButtonGroupContainer>
);

View File

@ -1,41 +0,0 @@
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { ColorSample, ColorSampleProps } from 'twenty-ui';
import {
LightIconButton,
LightIconButtonProps,
} from '@/ui/input/button/components/LightIconButton';
type ColorPickerButtonProps = Pick<ColorSampleProps, 'colorName'> &
Pick<LightIconButtonProps, 'onClick'> & {
isSelected?: boolean;
};
const StyledButton = styled(LightIconButton)<{
isSelected?: boolean;
}>`
${({ isSelected, theme }) =>
isSelected
? css`
background-color: ${theme.background.transparent.medium};
&:hover {
background-color: ${theme.background.transparent.medium};
}
`
: ''}
`;
export const ColorPickerButton = ({
colorName,
isSelected,
onClick,
}: ColorPickerButtonProps) => (
<StyledButton
size="medium"
isSelected={isSelected}
Icon={() => <ColorSample colorName={colorName} />}
onClick={onClick}
/>
);

View File

@ -1,134 +0,0 @@
import isPropValid from '@emotion/is-prop-valid';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { Link } from 'react-router-dom';
import { IconComponent } from 'twenty-ui';
export type FloatingButtonSize = 'small' | 'medium';
export type FloatingButtonPosition = 'standalone' | 'left' | 'middle' | 'right';
export type FloatingButtonProps = {
className?: string;
Icon?: IconComponent;
title?: string;
size?: FloatingButtonSize;
position?: FloatingButtonPosition;
applyShadow?: boolean;
applyBlur?: boolean;
disabled?: boolean;
focus?: boolean;
to?: string;
};
const StyledButton = styled('button', {
shouldForwardProp: (prop) =>
!['applyBlur', 'applyShadow', 'focus', 'position', 'size'].includes(prop) &&
isPropValid(prop),
})<
Pick<
FloatingButtonProps,
| 'size'
| 'focus'
| 'position'
| 'applyBlur'
| 'applyShadow'
| 'position'
| 'to'
>
>`
align-items: center;
backdrop-filter: ${({ applyBlur }) => (applyBlur ? 'blur(20px)' : 'none')};
background: ${({ theme }) => theme.background.primary};
border: ${({ focus, theme }) =>
focus ? `1px solid ${theme.color.blue}` : 'none'};
border-radius: ${({ position, theme }) => {
switch (position) {
case 'left':
return `${theme.border.radius.sm} 0px 0px ${theme.border.radius.sm}`;
case 'right':
return `0px ${theme.border.radius.sm} ${theme.border.radius.sm} 0px`;
case 'middle':
return '0px';
case 'standalone':
return theme.border.radius.sm;
}
}};
box-shadow: ${({ theme, applyShadow, focus }) =>
applyShadow
? `0px 2px 4px 0px ${
theme.background.transparent.light
}, 0px 0px 4px 0px ${theme.background.transparent.medium}${
focus ? `,0 0 0 3px ${theme.color.blue10}` : ''
}`
: focus
? `0 0 0 3px ${theme.color.blue10}`
: 'none'};
color: ${({ theme, disabled, focus }) => {
return !disabled
? focus
? theme.color.blue
: theme.font.color.secondary
: theme.font.color.extraLight;
}};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: ${({ theme }) => theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
padding: ${({ theme }) => {
return `0 ${theme.spacing(2)}`;
}};
transition: background 0.1s ease;
white-space: nowrap;
&:hover {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.lighter : 'transparent'};
}
&:active {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.medium : 'transparent'};
}
&:focus {
outline: none;
}
text-decoration: none;
`;
export const FloatingButton = ({
className,
Icon,
title,
size = 'small',
position = 'standalone',
applyBlur = true,
applyShadow = true,
disabled = false,
focus = false,
to,
}: FloatingButtonProps) => {
const theme = useTheme();
return (
<StyledButton
disabled={disabled}
focus={focus && !disabled}
size={size}
applyBlur={applyBlur}
applyShadow={applyShadow}
position={position}
className={className}
to={to}
as={to ? Link : 'button'}
>
{Icon && <Icon size={theme.icon.size.sm} />}
{title}
</StyledButton>
);
};

View File

@ -1,52 +0,0 @@
import React from 'react';
import styled from '@emotion/styled';
import { isDefined } from '~/utils/isDefined';
import { FloatingButtonPosition, FloatingButtonProps } from './FloatingButton';
const StyledFloatingButtonGroupContainer = styled.div`
backdrop-filter: blur(20px);
border-radius: ${({ theme }) => theme.border.radius.md};
box-shadow: ${({ theme }) =>
`0px 2px 4px 0px ${theme.background.transparent.light}, 0px 0px 4px 0px ${theme.background.transparent.medium}`};
display: inline-flex;
`;
export type FloatingButtonGroupProps = Pick<FloatingButtonProps, 'size'> & {
children: React.ReactElement[];
className?: string;
};
export const FloatingButtonGroup = ({
children,
size,
className,
}: FloatingButtonGroupProps) => (
<StyledFloatingButtonGroupContainer className={className}>
{React.Children.map(children, (child, index) => {
let position: FloatingButtonPosition;
if (index === 0) {
position = 'left';
} else if (index === children.length - 1) {
position = 'right';
} else {
position = 'middle';
}
const additionalProps: any = {
position,
size,
applyShadow: false,
applyBlur: false,
};
if (isDefined(size)) {
additionalProps.size = size;
}
return React.cloneElement(child, additionalProps);
})}
</StyledFloatingButtonGroupContainer>
);

View File

@ -1,146 +0,0 @@
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import React from 'react';
import { IconComponent } from 'twenty-ui';
export type FloatingIconButtonSize = 'small' | 'medium';
export type FloatingIconButtonPosition =
| 'standalone'
| 'left'
| 'middle'
| 'right';
export type FloatingIconButtonProps = {
className?: string;
Icon?: IconComponent;
size?: FloatingIconButtonSize;
position?: FloatingIconButtonPosition;
applyShadow?: boolean;
applyBlur?: boolean;
disabled?: boolean;
focus?: boolean;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
isActive?: boolean;
};
const shouldForwardProp = (prop: string) =>
![
'applyBlur',
'applyShadow',
'isActive',
'focus',
'position',
'size',
].includes(prop);
const StyledButton = styled('button', { shouldForwardProp })<
Pick<
FloatingIconButtonProps,
'size' | 'position' | 'applyShadow' | 'applyBlur' | 'focus' | 'isActive'
>
>`
align-items: center;
backdrop-filter: ${({ theme, applyBlur }) =>
applyBlur ? theme.blur.medium : 'none'};
background: ${({ theme, isActive }) =>
isActive ? theme.background.transparent.medium : theme.background.primary};
border: ${({ focus, theme }) =>
focus
? `1px solid ${theme.color.blue}`
: `1px solid ${theme.border.color.strong}`};
border-radius: ${({ position, theme }) => {
switch (position) {
case 'left':
return `${theme.border.radius.sm} 0px 0px ${theme.border.radius.sm}`;
case 'right':
return `0px ${theme.border.radius.sm} ${theme.border.radius.sm} 0px`;
case 'middle':
return '0px';
case 'standalone':
return theme.border.radius.sm;
}
}};
box-shadow: ${({ theme, applyShadow, focus }) =>
applyShadow
? theme.boxShadow.light
: focus
? `0 0 0 3px ${theme.color.blue10}`
: 'none'};
box-sizing: border-box;
color: ${({ theme, disabled, focus }) => {
return !disabled
? focus
? theme.color.blue
: theme.font.color.tertiary
: theme.font.color.extraLight;
}};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: ${({ theme }) => theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(1)};
justify-content: center;
padding: 0;
position: relative;
transition: background ${({ theme }) => theme.animation.duration.instant}s
ease;
white-space: nowrap;
${({ position, size }) => {
const sizeInPx =
(size === 'small' ? 24 : 32) - (position === 'standalone' ? 0 : 4);
return `
height: ${sizeInPx}px;
width: ${sizeInPx}px;
`;
}}
${({ theme, isActive }) =>
isActive &&
css`
&:hover {
background: ${theme.background.transparent.lighter};
}
`}
&:active {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.medium : 'transparent'};
}
&:focus {
outline: none;
}
`;
export const FloatingIconButton = ({
className,
Icon,
size = 'small',
position = 'standalone',
applyShadow = true,
applyBlur = true,
disabled = false,
focus = false,
onClick,
isActive,
}: FloatingIconButtonProps) => {
const theme = useTheme();
return (
<StyledButton
disabled={disabled}
focus={focus && !disabled}
size={size}
applyShadow={applyShadow}
applyBlur={applyBlur}
className={className}
position={position}
onClick={onClick}
isActive={isActive}
>
{Icon && <Icon size={theme.icon.size.md} />}
</StyledButton>
);
};

View File

@ -1,63 +0,0 @@
import { MouseEvent } from 'react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
import {
FloatingIconButton,
FloatingIconButtonPosition,
FloatingIconButtonProps,
} from './FloatingIconButton';
const StyledFloatingIconButtonGroupContainer = styled.div`
backdrop-filter: blur(20px);
background-color: ${({ theme }) => theme.background.primary};
border-radius: ${({ theme }) => theme.border.radius.sm};
box-shadow: ${({ theme }) =>
`0px 2px 4px 0px ${theme.background.transparent.light}, 0px 0px 4px 0px ${theme.background.transparent.medium}`};
display: inline-flex;
gap: 2px;
padding: 2px;
`;
export type FloatingIconButtonGroupProps = Pick<
FloatingIconButtonProps,
'className' | 'size'
> & {
iconButtons: {
Icon: IconComponent;
onClick?: (event: MouseEvent<any>) => void;
isActive?: boolean;
}[];
};
export const FloatingIconButtonGroup = ({
iconButtons,
size,
className,
}: FloatingIconButtonGroupProps) => (
<StyledFloatingIconButtonGroupContainer className={className}>
{iconButtons.map(({ Icon, onClick, isActive }, index) => {
const position: FloatingIconButtonPosition =
iconButtons.length === 1
? 'standalone'
: index === 0
? 'left'
: index === iconButtons.length - 1
? 'right'
: 'middle';
return (
<FloatingIconButton
key={`floating-icon-button-${index}`}
applyBlur={false}
applyShadow={false}
Icon={Icon}
onClick={onClick}
position={position}
size={size}
isActive={isActive}
/>
);
})}
</StyledFloatingIconButtonGroupContainer>
);

View File

@ -1,271 +0,0 @@
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import React from 'react';
import { IconComponent } from 'twenty-ui';
export type IconButtonSize = 'medium' | 'small';
export type IconButtonPosition = 'standalone' | 'left' | 'middle' | 'right';
export type IconButtonVariant = 'primary' | 'secondary' | 'tertiary';
export type IconButtonAccent = 'default' | 'blue' | 'danger';
export type IconButtonProps = {
className?: string;
Icon?: IconComponent;
variant?: IconButtonVariant;
size?: IconButtonSize;
position?: IconButtonPosition;
accent?: IconButtonAccent;
disabled?: boolean;
focus?: boolean;
dataTestId?: string;
ariaLabel?: string;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
};
const StyledButton = styled.button<
Pick<IconButtonProps, 'variant' | 'size' | 'position' | 'accent' | 'focus'>
>`
align-items: center;
${({ theme, variant, accent, disabled, focus }) => {
switch (variant) {
case 'primary':
switch (accent) {
case 'default':
return css`
background: ${theme.background.secondary};
border-color: ${focus
? theme.color.blue
: theme.background.transparent.light};
border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${theme.accent.tertiary}`
: 'none'};
color: ${!disabled
? theme.font.color.secondary
: theme.font.color.extraLight};
&:hover {
background: ${!disabled
? theme.background.tertiary
: theme.background.secondary};
}
&:active {
background: ${!disabled
? theme.background.quaternary
: theme.background.secondary};
}
`;
case 'blue':
return css`
background: ${theme.color.blue};
border-color: ${!disabled
? focus
? theme.color.blue
: theme.background.transparent.light
: 'transparent'};
border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${theme.accent.tertiary}`
: 'none'};
color: ${theme.grayScale.gray0};
opacity: ${disabled ? 0.24 : 1};
${disabled
? ''
: css`
&:hover {
background: ${theme.color.blue50};
}
&:active {
background: ${theme.color.blue60};
}
`}
`;
case 'danger':
return css`
background: ${theme.color.red};
border-color: ${!disabled
? focus
? theme.color.red
: theme.background.transparent.light
: 'transparent'};
border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${theme.color.red10}`
: 'none'};
color: ${theme.grayScale.gray0};
opacity: ${disabled ? 0.24 : 1};
${disabled
? ''
: css`
&:hover,
&:active {
background: ${theme.color.red50};
}
`}
`;
}
break;
case 'secondary':
case 'tertiary':
switch (accent) {
case 'default':
return css`
background: ${focus
? theme.background.transparent.primary
: 'transparent'};
border-color: ${variant === 'secondary'
? !disabled && focus
? theme.color.blue
: theme.background.transparent.light
: focus
? theme.color.blue
: 'transparent'};
border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${theme.accent.tertiary}`
: 'none'};
color: ${!disabled
? theme.font.color.tertiary
: theme.font.color.extraLight};
&:hover {
background: ${!disabled
? theme.background.transparent.light
: 'transparent'};
}
&:active {
background: ${!disabled
? theme.background.transparent.light
: 'transparent'};
}
`;
case 'blue':
return css`
background: ${focus
? theme.background.transparent.primary
: 'transparent'};
border-color: ${variant === 'secondary'
? !disabled
? theme.color.blue
: theme.color.blue20
: focus
? theme.color.blue
: 'transparent'};
border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${theme.accent.tertiary}`
: 'none'};
color: ${!disabled ? theme.color.blue : theme.accent.accent4060};
&:hover {
background: ${!disabled
? theme.accent.tertiary
: 'transparent'};
}
&:active {
background: ${!disabled
? theme.accent.secondary
: 'transparent'};
}
`;
case 'danger':
return css`
background: transparent;
border-color: ${variant === 'secondary'
? theme.border.color.danger
: focus
? theme.color.red
: 'transparent'};
border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${!disabled && focus
? `0 0 0 3px ${theme.color.red10}`
: 'none'};
color: ${!disabled ? theme.font.color.danger : theme.color.red20};
&:hover {
background: ${!disabled
? theme.background.danger
: 'transparent'};
}
&:active {
background: ${!disabled
? theme.background.danger
: 'transparent'};
}
`;
}
}
}}
border-radius: ${({ position, theme }) => {
switch (position) {
case 'left':
return `${theme.border.radius.sm} 0px 0px ${theme.border.radius.sm}`;
case 'right':
return `0px ${theme.border.radius.sm} ${theme.border.radius.sm} 0px`;
case 'middle':
return '0px';
case 'standalone':
return theme.border.radius.sm;
}
}};
border-style: solid;
border-width: ${({ variant, position }) => {
switch (variant) {
case 'primary':
case 'secondary':
return position === 'middle' ? '1px 0px' : '1px';
case 'tertiary':
return '0';
}
}};
box-sizing: content-box;
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: 500;
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
justify-content: center;
padding: 0;
transition: background 0.1s ease;
white-space: nowrap;
min-width: ${({ size }) => (size === 'small' ? '24px' : '32px')};
&:focus {
outline: none;
}
`;
export const IconButton = ({
className,
Icon,
variant = 'primary',
size = 'medium',
accent = 'default',
position = 'standalone',
disabled = false,
focus = false,
dataTestId,
ariaLabel,
onClick,
}: IconButtonProps) => {
const theme = useTheme();
return (
<StyledButton
data-testid={dataTestId}
variant={variant}
size={size}
position={position}
disabled={disabled}
focus={focus}
accent={accent}
className={className}
onClick={onClick}
aria-label={ariaLabel}
>
{Icon && <Icon size={theme.icon.size.md} />}
</StyledButton>
);
};

View File

@ -1,51 +0,0 @@
import { MouseEvent } from 'react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
import { IconButton, IconButtonPosition, IconButtonProps } from './IconButton';
const StyledIconButtonGroupContainer = styled.div`
border-radius: ${({ theme }) => theme.border.radius.md};
display: flex;
`;
export type IconButtonGroupProps = Pick<
IconButtonProps,
'accent' | 'size' | 'variant'
> & {
iconButtons: {
Icon: IconComponent;
onClick?: (event: MouseEvent<any>) => void;
}[];
className?: string;
};
export const IconButtonGroup = ({
accent,
iconButtons,
size,
variant,
className,
}: IconButtonGroupProps) => (
<StyledIconButtonGroupContainer className={className}>
{iconButtons.map(({ Icon, onClick }, index) => {
const position: IconButtonPosition =
index === 0
? 'left'
: index === iconButtons.length - 1
? 'right'
: 'middle';
return (
<IconButton
accent={accent}
Icon={Icon}
onClick={onClick}
position={position}
size={size}
variant={variant}
/>
);
})}
</StyledIconButtonGroupContainer>
);

View File

@ -1,102 +0,0 @@
import { MouseEvent } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
export type LightButtonAccent = 'secondary' | 'tertiary';
export type LightButtonProps = {
className?: string;
Icon?: IconComponent;
title?: string;
accent?: LightButtonAccent;
active?: boolean;
disabled?: boolean;
focus?: boolean;
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
};
const StyledButton = styled.button<
Pick<LightButtonProps, 'accent' | 'active' | 'focus'>
>`
align-items: center;
background: transparent;
border: ${({ theme, focus }) =>
focus ? `1px solid ${theme.color.blue}` : 'none'};
border-radius: ${({ theme }) => theme.border.radius.sm};
box-shadow: ${({ theme, focus }) =>
focus ? `0 0 0 3px ${theme.color.blue10}` : 'none'};
color: ${({ theme, accent, active, disabled, focus }) => {
switch (accent) {
case 'secondary':
return active || focus
? theme.color.blue
: !disabled
? theme.font.color.secondary
: theme.font.color.extraLight;
case 'tertiary':
return active || focus
? theme.color.blue
: !disabled
? theme.font.color.tertiary
: theme.font.color.extraLight;
}
}};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: ${({ theme }) => theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(1)};
height: 24px;
padding: ${({ theme }) => {
return `0 ${theme.spacing(2)}`;
}};
transition: background 0.1s ease;
white-space: nowrap;
&:hover {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.light : 'transparent'};
}
&:focus {
outline: none;
}
&:active {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.medium : 'transparent'};
}
`;
export const LightButton = ({
className,
Icon,
title,
active = false,
accent = 'secondary',
disabled = false,
focus = false,
onClick,
}: LightButtonProps) => {
const theme = useTheme();
return (
<StyledButton
onClick={onClick}
disabled={disabled}
focus={focus && !disabled}
accent={accent}
className={className}
active={active}
>
{!!Icon && <Icon size={theme.icon.size.md} />}
{title}
</StyledButton>
);
};

View File

@ -1,111 +0,0 @@
import { ComponentProps, MouseEvent } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
export type LightIconButtonAccent = 'secondary' | 'tertiary';
export type LightIconButtonSize = 'small' | 'medium';
export type LightIconButtonProps = {
className?: string;
testId?: string;
Icon?: IconComponent;
title?: string;
size?: LightIconButtonSize;
accent?: LightIconButtonAccent;
active?: boolean;
disabled?: boolean;
focus?: boolean;
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
} & Pick<ComponentProps<'button'>, 'aria-label' | 'title'>;
const StyledButton = styled.button<
Pick<LightIconButtonProps, 'accent' | 'active' | 'size' | 'focus'>
>`
align-items: center;
background: transparent;
border: none;
border: ${({ disabled, theme, focus }) =>
!disabled && focus ? `1px solid ${theme.color.blue}` : 'none'};
border-radius: ${({ theme }) => theme.border.radius.sm};
box-shadow: ${({ disabled, theme, focus }) =>
!disabled && focus ? `0 0 0 3px ${theme.color.blue10}` : 'none'};
color: ${({ theme, accent, active, disabled, focus }) => {
switch (accent) {
case 'secondary':
return active || focus
? theme.color.blue
: !disabled
? theme.font.color.secondary
: theme.font.color.extraLight;
case 'tertiary':
return active || focus
? theme.color.blue
: !disabled
? theme.font.color.tertiary
: theme.font.color.extraLight;
}
}};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: ${({ theme }) => theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
justify-content: center;
padding: 0;
transition: background 0.1s ease;
white-space: nowrap;
width: ${({ size }) => (size === 'small' ? '24px' : '32px')};
min-width: ${({ size }) => (size === 'small' ? '24px' : '32px')};
&:hover {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.light : 'transparent'};
}
&:focus {
outline: none;
}
&:active {
background: ${({ theme, disabled }) =>
!disabled ? theme.background.transparent.medium : 'transparent'};
}
`;
export const LightIconButton = ({
'aria-label': ariaLabel,
className,
testId,
Icon,
active = false,
size = 'small',
accent = 'secondary',
disabled = false,
focus = false,
onClick,
title,
}: LightIconButtonProps) => {
const theme = useTheme();
return (
<StyledButton
data-testid={testId}
aria-label={ariaLabel}
onClick={onClick}
disabled={disabled}
focus={focus && !disabled}
accent={accent}
className={className}
size={size}
active={active}
title={title}
>
{Icon && <Icon size={theme.icon.size.sm} />}
</StyledButton>
);
};

View File

@ -1,53 +0,0 @@
import { FunctionComponent, MouseEvent, ReactElement } from 'react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
import { LightIconButton, LightIconButtonProps } from './LightIconButton';
const StyledLightIconButtonGroupContainer = styled.div`
display: inline-flex;
gap: 2px;
`;
export type LightIconButtonGroupProps = Pick<
LightIconButtonProps,
'className' | 'size'
> & {
iconButtons: {
Wrapper?: FunctionComponent<{ iconButton: ReactElement }>;
Icon: IconComponent;
accent?: LightIconButtonProps['accent'];
onClick?: (event: MouseEvent<any>) => void;
disabled?: boolean;
}[];
};
export const LightIconButtonGroup = ({
iconButtons,
size,
className,
}: LightIconButtonGroupProps) => (
<StyledLightIconButtonGroupContainer className={className}>
{iconButtons.map(({ Wrapper, Icon, accent, onClick }, index) => {
const iconButton = (
<LightIconButton
key={`light-icon-button-${index}`}
Icon={Icon}
accent={accent}
disabled={!onClick}
onClick={onClick}
size={size}
/>
);
return Wrapper ? (
<Wrapper
key={`light-icon-button-wrapper-${index}`}
iconButton={iconButton}
/>
) : (
iconButton
);
})}
</StyledLightIconButtonGroupContainer>
);

View File

@ -1,130 +0,0 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import React from 'react';
import { IconComponent } from 'twenty-ui';
export type MainButtonVariant = 'primary' | 'secondary';
type Props = {
title: string;
fullWidth?: boolean;
width?: number;
variant?: MainButtonVariant;
soon?: boolean;
} & React.ComponentProps<'button'>;
const StyledButton = styled.button<
Pick<Props, 'fullWidth' | 'width' | 'variant'>
>`
align-items: center;
background: ${({ theme, variant, disabled }) => {
if (disabled === true) {
return theme.background.secondary;
}
switch (variant) {
case 'primary':
return theme.background.primaryInverted;
case 'secondary':
return theme.background.primary;
default:
return theme.background.primary;
}
}};
border: 1px solid;
border-color: ${({ theme, disabled, variant }) => {
if (disabled === true) {
return theme.background.transparent.lighter;
}
switch (variant) {
case 'primary':
return theme.background.transparent.strong;
case 'secondary':
return theme.border.color.medium;
default:
return theme.background.primary;
}
}};
border-radius: ${({ theme }) => theme.border.radius.md};
${({ theme, disabled }) => {
if (disabled === true) {
return '';
}
return `box-shadow: ${theme.boxShadow.light};`;
}}
color: ${({ theme, variant, disabled }) => {
if (disabled === true) {
return theme.font.color.light;
}
switch (variant) {
case 'primary':
return theme.font.color.inverted;
case 'secondary':
return theme.font.color.primary;
default:
return theme.font.color.primary;
}
}};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
flex-direction: row;
font-family: ${({ theme }) => theme.font.family};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
gap: ${({ theme }) => theme.spacing(2)};
justify-content: center;
outline: none;
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)};
max-height: ${({ theme }) => theme.spacing(8)};
width: ${({ fullWidth, width }) =>
fullWidth ? '100%' : width ? `${width}px` : 'auto'};
${({ theme, variant, disabled }) => {
switch (variant) {
case 'secondary':
return `
&:hover {
background: ${theme.background.tertiary};
}
`;
default:
return `
&:hover {
background: ${
!disabled
? theme.background.primaryInvertedHover
: theme.background.secondary
};};
}
`;
}
}};
`;
type MainButtonProps = Props & {
Icon?: IconComponent;
};
export const MainButton = ({
Icon,
title,
width,
fullWidth = false,
variant = 'primary',
type,
onClick,
disabled,
className,
}: MainButtonProps) => {
const theme = useTheme();
return (
<StyledButton
className={className}
{...{ disabled, fullWidth, width, onClick, type, variant }}
>
{Icon && <Icon size={theme.icon.size.sm} />}
{title}
</StyledButton>
);
};

View File

@ -1,50 +0,0 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
const StyledIconButton = styled.button`
align-items: center;
background: ${({ theme }) => theme.color.blue};
border: none;
border-radius: 50%;
color: ${({ theme }) => theme.font.color.inverted};
cursor: pointer;
display: flex;
height: 20px;
justify-content: center;
outline: none;
padding: 0;
transition:
color 0.1s ease-in-out,
background 0.1s ease-in-out;
&:disabled {
background: ${({ theme }) => theme.background.quaternary};
color: ${({ theme }) => theme.font.color.tertiary};
cursor: default;
}
width: 20px;
`;
type RoundedIconButtonProps = {
Icon: IconComponent;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
export const RoundedIconButton = ({
Icon,
onClick,
disabled,
className,
}: RoundedIconButtonProps) => {
const theme = useTheme();
return (
<StyledIconButton className={className} {...{ disabled, onClick }}>
{<Icon size={theme.icon.size.md} />}
</StyledIconButton>
);
};

View File

@ -1,27 +0,0 @@
{/* Button.mdx */}
import { Meta, Controls, Story } from '@storybook/blocks';
import * as ButtonStories from './Button.stories';
<Meta of={ButtonStories} />
Button is a clickable interactive element that triggers a response.
You can place text and icons inside of a button.
Buttons are often used for form submissions and to toggle elements into view.
<Story of={ButtonStories.Default} />
<br />
## Properties
<Controls />
## Usage
```js
import { Button } from '@/ui/button/components/Button';
<Button title="Click me" />;
```

View File

@ -1,281 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconSearch,
} from 'twenty-ui';
import {
Button,
ButtonAccent,
ButtonPosition,
ButtonSize,
ButtonVariant,
} from '../Button';
const meta: Meta<typeof Button> = {
title: 'UI/Input/Button/Button',
component: Button,
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Default: Story = {
argTypes: {
Icon: { control: false },
},
args: {
title: 'Button',
size: 'small',
variant: 'primary',
inverted: false,
accent: 'danger',
disabled: false,
focus: false,
fullWidth: false,
soon: false,
position: 'standalone',
Icon: IconSearch,
className: '',
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof Button> = {
args: { title: 'Filter', Icon: IconSearch },
argTypes: {
size: { control: false },
variant: { control: false },
accent: { control: false },
disabled: { control: false },
focus: { control: false },
fullWidth: { control: false },
soon: { control: false },
position: { control: false },
className: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies ButtonSize[],
props: (size: ButtonSize) => ({ size }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { focus: true, disabled: true };
default:
return {};
}
},
},
{
name: 'accents',
values: ['default', 'blue', 'danger'] satisfies ButtonAccent[],
props: (accent: ButtonAccent) => ({ accent }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies ButtonVariant[],
props: (variant: ButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};
export const SoonCatalog: CatalogStory<Story, typeof Button> = {
args: { title: 'Filter', Icon: IconSearch, soon: true },
argTypes: {
size: { control: false },
variant: { control: false },
accent: { control: false },
disabled: { control: false },
focus: { control: false },
fullWidth: { control: false },
soon: { control: false },
position: { control: false },
className: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies ButtonSize[],
props: (size: ButtonSize) => ({ size }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { focus: true, disabled: true };
default:
return {};
}
},
},
{
name: 'accents',
values: ['default', 'blue', 'danger'] satisfies ButtonAccent[],
props: (accent: ButtonAccent) => ({ accent }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies ButtonVariant[],
props: (variant: ButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};
export const PositionCatalog: CatalogStory<Story, typeof Button> = {
args: { title: 'Filter', Icon: IconSearch },
argTypes: {
size: { control: false },
variant: { control: false },
accent: { control: false },
disabled: { control: false },
focus: { control: false },
fullWidth: { control: false },
soon: { control: false },
position: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
catalog: {
dimensions: [
{
name: 'positions',
values: [
'standalone',
'left',
'middle',
'right',
] satisfies ButtonPosition[],
props: (position: ButtonPosition) => ({ position }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { focus: true, disabled: true };
default:
return {};
}
},
},
{
name: 'sizes',
values: ['small', 'medium'] satisfies ButtonSize[],
props: (size: ButtonSize) => ({ size }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies ButtonVariant[],
props: (variant: ButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};
export const FullWidth: Story = {
args: { title: 'Filter', Icon: IconSearch, fullWidth: true },
argTypes: {
size: { control: false },
variant: { control: false },
accent: { control: false },
focus: { control: false },
disabled: { control: false },
fullWidth: { control: false },
soon: { control: false },
position: { control: false },
className: { control: false },
Icon: { control: false },
},
decorators: [ComponentDecorator],
};

View File

@ -1,80 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconCheckbox,
IconNotes,
IconTimelineEvent,
} from 'twenty-ui';
import { Button, ButtonAccent, ButtonSize, ButtonVariant } from '../Button';
import { ButtonGroup } from '../ButtonGroup';
const meta: Meta<typeof ButtonGroup> = {
title: 'UI/Input/Button/ButtonGroup',
component: ButtonGroup,
};
export default meta;
type Story = StoryObj<typeof ButtonGroup>;
export const Default: Story = {
args: {
size: 'small',
variant: 'primary',
accent: 'danger',
children: [
<Button Icon={IconNotes} title="Note" />,
<Button Icon={IconCheckbox} title="Task" />,
<Button Icon={IconTimelineEvent} title="Activity" />,
],
},
argTypes: {
children: { control: false },
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof ButtonGroup> = {
args: {
children: [
<Button Icon={IconNotes} title="Note" />,
<Button Icon={IconCheckbox} title="Task" />,
<Button Icon={IconTimelineEvent} title="Activity" />,
],
},
argTypes: {
size: { control: false },
variant: { control: false },
accent: { control: false },
children: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies ButtonSize[],
props: (size: ButtonSize) => ({ size }),
},
{
name: 'accents',
values: ['default', 'blue', 'danger'] satisfies ButtonAccent[],
props: (accent: ButtonAccent) => ({ accent }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies ButtonVariant[],
props: (variant: ButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,18 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { ColorPickerButton } from '../ColorPickerButton';
const meta: Meta<typeof ColorPickerButton> = {
title: 'UI/Input/Button/ColorPickerButton',
component: ColorPickerButton,
decorators: [ComponentDecorator],
args: { colorName: 'green' },
};
export default meta;
type Story = StoryObj<typeof ColorPickerButton>;
export const Default: Story = {};
export const Selected: Story = { args: { isSelected: true } };

View File

@ -1,85 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconSearch,
} from 'twenty-ui';
import { FloatingButton, FloatingButtonSize } from '../FloatingButton';
const meta: Meta<typeof FloatingButton> = {
title: 'UI/Input/Button/FloatingButton',
component: FloatingButton,
};
export default meta;
type Story = StoryObj<typeof FloatingButton>;
export const Default: Story = {
args: {
title: 'Filter',
size: 'small',
disabled: false,
focus: false,
applyBlur: true,
applyShadow: true,
position: 'standalone',
Icon: IconSearch,
},
argTypes: {
Icon: { control: false },
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof FloatingButton> = {
args: { title: 'Filter', Icon: IconSearch },
argTypes: {
size: { control: false },
disabled: { control: false },
position: { control: false },
focus: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies FloatingButtonSize[],
props: (size: FloatingButtonSize) => ({ size }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'disabled+focus':
return { disabled: true, focus: true };
default:
return {};
}
},
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,62 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconCheckbox,
IconNotes,
IconTimelineEvent,
} from 'twenty-ui';
import { FloatingButton, FloatingButtonSize } from '../FloatingButton';
import { FloatingButtonGroup } from '../FloatingButtonGroup';
const meta: Meta<typeof FloatingButtonGroup> = {
title: 'UI/Input/Button/FloatingButtonGroup',
component: FloatingButtonGroup,
};
export default meta;
type Story = StoryObj<typeof FloatingButtonGroup>;
export const Default: Story = {
args: {
size: 'small',
children: [
<FloatingButton Icon={IconNotes} />,
<FloatingButton Icon={IconCheckbox} />,
<FloatingButton Icon={IconTimelineEvent} />,
],
},
argTypes: {
children: { control: false },
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof FloatingButtonGroup> = {
args: {
children: [
<FloatingButton Icon={IconNotes} />,
<FloatingButton Icon={IconCheckbox} />,
<FloatingButton Icon={IconTimelineEvent} />,
],
},
argTypes: {
size: { control: false },
children: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies FloatingButtonSize[],
props: (size: FloatingButtonSize) => ({ size }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,86 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconSearch,
} from 'twenty-ui';
import {
FloatingIconButton,
FloatingIconButtonSize,
} from '../FloatingIconButton';
const meta: Meta<typeof FloatingIconButton> = {
title: 'UI/Input/Button/FloatingIconButton',
component: FloatingIconButton,
};
export default meta;
type Story = StoryObj<typeof FloatingIconButton>;
export const Default: Story = {
args: {
size: 'small',
disabled: false,
focus: false,
applyBlur: true,
applyShadow: true,
position: 'standalone',
Icon: IconSearch,
},
argTypes: {
Icon: { control: false },
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof FloatingIconButton> = {
args: { Icon: IconSearch },
argTypes: {
size: { control: false },
disabled: { control: false },
focus: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies FloatingIconButtonSize[],
props: (size: FloatingIconButtonSize) => ({ size }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'disabled+focus':
return { disabled: true, focus: true };
default:
return {};
}
},
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,56 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconCheckbox,
IconNotes,
IconTimelineEvent,
} from 'twenty-ui';
import { FloatingIconButtonSize } from '../FloatingIconButton';
import { FloatingIconButtonGroup } from '../FloatingIconButtonGroup';
const meta: Meta<typeof FloatingIconButtonGroup> = {
title: 'UI/Input/Button/FloatingIconButtonGroup',
component: FloatingIconButtonGroup,
args: {
iconButtons: [
{ Icon: IconNotes },
{ Icon: IconCheckbox },
{ Icon: IconTimelineEvent },
],
},
argTypes: {
iconButtons: { control: false },
},
};
export default meta;
type Story = StoryObj<typeof FloatingIconButtonGroup>;
export const Default: Story = {
args: {
size: 'small',
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof FloatingIconButtonGroup> = {
argTypes: {
size: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies FloatingIconButtonSize[],
props: (size: FloatingIconButtonSize) => ({ size }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,181 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconSearch,
} from 'twenty-ui';
import {
IconButton,
IconButtonAccent,
IconButtonPosition,
IconButtonSize,
IconButtonVariant,
} from '../IconButton';
const meta: Meta<typeof IconButton> = {
title: 'UI/Input/Button/IconButton',
component: IconButton,
};
export default meta;
type Story = StoryObj<typeof IconButton>;
export const Default: Story = {
args: {
size: 'small',
variant: 'primary',
accent: 'danger',
disabled: false,
focus: false,
position: 'standalone',
Icon: IconSearch,
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof IconButton> = {
args: { Icon: IconSearch },
argTypes: {
size: { control: false },
variant: { control: false },
focus: { control: false },
accent: { control: false },
disabled: { control: false },
Icon: { control: false },
position: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'] },
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies IconButtonSize[],
props: (size: IconButtonSize) => ({ size }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { focus: true, disabled: true };
default:
return {};
}
},
},
{
name: 'accents',
values: ['default', 'blue', 'danger'] satisfies IconButtonAccent[],
props: (accent: IconButtonAccent) => ({ accent }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies IconButtonVariant[],
props: (variant: IconButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};
export const PositionCatalog: CatalogStory<Story, typeof IconButton> = {
args: { Icon: IconSearch },
argTypes: {
size: { control: false },
variant: { control: false },
focus: { control: false },
accent: { control: false },
disabled: { control: false },
position: { control: false },
Icon: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'] },
catalog: {
dimensions: [
{
name: 'positions',
values: [
'standalone',
'left',
'middle',
'right',
] satisfies IconButtonPosition[],
props: (position: IconButtonPosition) => ({ position }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'focus',
'disabled+focus',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { focus: true, disabled: true };
default:
return {};
}
},
},
{
name: 'sizes',
values: ['small', 'medium'] satisfies IconButtonSize[],
props: (size: IconButtonSize) => ({ size }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies IconButtonVariant[],
props: (variant: IconButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,77 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconCheckbox,
IconNotes,
IconTimelineEvent,
} from 'twenty-ui';
import {
IconButtonAccent,
IconButtonSize,
IconButtonVariant,
} from '../IconButton';
import { IconButtonGroup } from '../IconButtonGroup';
const meta: Meta<typeof IconButtonGroup> = {
title: 'UI/Input/Button/IconButtonGroup',
component: IconButtonGroup,
args: {
iconButtons: [
{ Icon: IconNotes },
{ Icon: IconCheckbox },
{ Icon: IconTimelineEvent },
],
},
argTypes: {
iconButtons: { control: false },
},
};
export default meta;
type Story = StoryObj<typeof IconButtonGroup>;
export const Default: Story = {
args: {
size: 'small',
variant: 'primary',
accent: 'danger',
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof IconButtonGroup> = {
argTypes: {
size: { control: false },
variant: { control: false },
accent: { control: false },
},
parameters: {
catalog: {
dimensions: [
{
name: 'sizes',
values: ['small', 'medium'] satisfies IconButtonSize[],
props: (size: IconButtonSize) => ({ size }),
},
{
name: 'accents',
values: ['default', 'blue', 'danger'] satisfies IconButtonAccent[],
props: (accent: IconButtonAccent) => ({ accent }),
},
{
name: 'variants',
values: [
'primary',
'secondary',
'tertiary',
] satisfies IconButtonVariant[],
props: (variant: IconButtonVariant) => ({ variant }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,89 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconSearch,
} from 'twenty-ui';
import { LightButton, LightButtonAccent } from '../LightButton';
const meta: Meta<typeof LightButton> = {
title: 'UI/Input/Button/LightButton',
component: LightButton,
};
export default meta;
type Story = StoryObj<typeof LightButton>;
export const Default: Story = {
args: {
title: 'Filter',
accent: 'secondary',
disabled: false,
active: false,
focus: false,
Icon: IconSearch,
},
argTypes: {
Icon: { control: false },
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof LightButton> = {
args: { title: 'Filter', Icon: IconSearch },
argTypes: {
accent: { control: false },
disabled: { control: false },
active: { control: false },
focus: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'] },
catalog: {
dimensions: [
{
name: 'accents',
values: ['secondary', 'tertiary'] satisfies LightButtonAccent[],
props: (accent: LightButtonAccent) => ({ accent }),
},
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'active',
'focus',
'disabled+focus',
'disabled+active',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { disabled: true, focus: true };
case 'disabled+active':
return { disabled: true, active: true };
default:
return {};
}
},
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,98 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconSearch,
} from 'twenty-ui';
import {
LightIconButton,
LightIconButtonAccent,
LightIconButtonSize,
} from '../LightIconButton';
const meta: Meta<typeof LightIconButton> = {
title: 'UI/Input/Button/LightIconButton',
component: LightIconButton,
};
export default meta;
type Story = StoryObj<typeof LightIconButton>;
export const Default: Story = {
args: {
title: 'Filter',
accent: 'secondary',
disabled: false,
active: false,
focus: false,
Icon: IconSearch,
},
argTypes: {
Icon: { control: false },
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof LightIconButton> = {
args: { title: 'Filter', Icon: IconSearch },
argTypes: {
accent: { control: false },
disabled: { control: false },
active: { control: false },
focus: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'] },
catalog: {
dimensions: [
{
name: 'states',
values: [
'default',
'hover',
'pressed',
'disabled',
'active',
'focus',
'disabled+focus',
'disabled+active',
],
props: (state: string) => {
switch (state) {
case 'default':
return {};
case 'hover':
case 'pressed':
return { className: state };
case 'focus':
return { focus: true };
case 'disabled':
return { disabled: true };
case 'active':
return { active: true };
case 'disabled+focus':
return { disabled: true, focus: true };
case 'disabled+active':
return { disabled: true, active: true };
default:
return {};
}
},
},
{
name: 'accents',
values: ['secondary', 'tertiary'] satisfies LightIconButtonAccent[],
props: (accent: LightIconButtonAccent) => ({ accent }),
},
{
name: 'sizes',
values: ['small', 'medium'] satisfies LightIconButtonSize[],
props: (size: LightIconButtonSize) => ({ size }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,61 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentDecorator, IconBrandGoogle } from 'twenty-ui';
import { MainButton } from '../MainButton';
const clickJestFn = fn();
const meta: Meta<typeof MainButton> = {
title: 'UI/Input/Button/MainButton',
component: MainButton,
decorators: [ComponentDecorator],
args: { title: 'A primary Button', onClick: clickJestFn },
};
export default meta;
type Story = StoryObj<typeof MainButton>;
export const Default: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(clickJestFn).toHaveBeenCalledTimes(0);
const button = canvas.getByRole('button');
await userEvent.click(button);
expect(clickJestFn).toHaveBeenCalledTimes(1);
},
};
export const WithIcon: Story = {
args: { Icon: IconBrandGoogle },
};
export const DisabledWithIcon: Story = {
args: { ...WithIcon.args, disabled: true },
};
export const FullWidth: Story = {
args: { fullWidth: true },
};
export const Width: Story = {
args: { width: 200 },
};
export const Secondary: Story = {
args: { title: 'A secondary Button', variant: 'secondary' },
};
export const SecondaryWithIcon: Story = {
args: { ...Secondary.args, ...WithIcon.args },
};
export const SecondaryDisabledWithIcon: Story = {
args: { ...SecondaryWithIcon.args, disabled: true },
};
export const SecondaryFullWidth: Story = {
args: { ...Secondary.args, ...FullWidth.args },
};

View File

@ -1,30 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentDecorator, IconArrowRight } from 'twenty-ui';
import { RoundedIconButton } from '../RoundedIconButton';
const clickJestFn = fn();
const meta: Meta<typeof RoundedIconButton> = {
title: 'UI/Input/Button/RoundedIconButton',
component: RoundedIconButton,
};
export default meta;
type Story = StoryObj<typeof RoundedIconButton>;
export const Default: Story = {
decorators: [ComponentDecorator],
argTypes: { Icon: { control: false } },
args: { onClick: clickJestFn, Icon: IconArrowRight },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(clickJestFn).toHaveBeenCalledTimes(0);
const button = canvas.getByRole('button');
await userEvent.click(button);
expect(clickJestFn).toHaveBeenCalledTimes(1);
},
};

Some files were not shown because too many files have changed in this diff Show More