[REFACTOR] Twenty UI multi barrel (#11301)

# Introduction
closes https://github.com/twentyhq/core-team-issues/issues/591
Same than for `twenty-shared` made in
https://github.com/twentyhq/twenty/pull/11083.

## TODO
- [x] Manual migrate twenty-website twenty-ui imports

## What's next:
- Generate barrel and migration script factorization within own package
+ tests
- Refactoring using preconstruct ? TimeBox
- Lint circular dependencies
- Lint import from barrel and forbid them

### Preconstruct
We need custom rollup plugins addition, but preconstruct does not expose
its rollup configuration. It might be possible to handle this using the
babel overrides. But was a big tunnel.
We could give it a try afterwards ! ( allowing cjs interop and stuff
like that )
Stuck to vite lib app

Closed related PRs:
- https://github.com/twentyhq/twenty/pull/11294
- https://github.com/twentyhq/twenty/pull/11203
This commit is contained in:
Paul Rastoin
2025-04-03 11:47:55 +02:00
committed by GitHub
parent 8c9fcfe5a4
commit 4a4e65fe4a
1009 changed files with 5757 additions and 2828 deletions

View File

@ -3,12 +3,13 @@ import { useRef, useState } from 'react';
import { HotkeysEvent } from 'react-hotkeys-hook/dist/types';
import TextareaAutosize from 'react-textarea-autosize';
import { Key } from 'ts-key-enum';
import { Button, IconArrowRight, RoundedIconButton } from 'twenty-ui';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { InputHotkeyScope } from '../types/InputHotkeyScope';
import { Button, RoundedIconButton } from 'twenty-ui/input';
import { IconArrowRight } from 'twenty-ui/display';
const MAX_ROWS = 5;

View File

@ -1,15 +1,6 @@
import styled from '@emotion/styled';
import { useMemo, useState } from 'react';
import { useRecoilValue } from 'recoil';
import {
IconApps,
IconButton,
IconButtonSize,
IconButtonVariant,
IconComponent,
LightIconButton,
useIcons,
} from 'twenty-ui';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
@ -24,6 +15,13 @@ import { arrayToChunks } from '~/utils/array/arrayToChunks';
import { t } from '@lingui/core/macro';
import { IconPickerHotkeyScope } from '../types/IconPickerHotkeyScope';
import { IconApps, IconComponent, useIcons } from 'twenty-ui/display';
import {
IconButton,
IconButtonSize,
IconButtonVariant,
LightIconButton,
} from 'twenty-ui/input';
export type IconPickerProps = {
disabled?: boolean;

View File

@ -4,9 +4,10 @@ import { Trans, useLingui } from '@lingui/react/macro';
import { isNonEmptyString } from '@sniptt/guards';
import React from 'react';
import { Button, IconPhotoUp, IconTrash, IconUpload, IconX } from 'twenty-ui';
import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { getImageAbsoluteURI, isDefined } from 'twenty-shared/utils';
import { Button } from 'twenty-ui/input';
import { IconPhotoUp, IconTrash, IconUpload, IconX } from 'twenty-ui/display';
const StyledContainer = styled.div`
display: flex;

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { HTMLAttributes } from 'react';
import { Label } from 'twenty-ui';
import { Label } from 'twenty-ui/display';
type InputLabelProps = HTMLAttributes<HTMLLabelElement> & {
htmlFor?: string;

View File

@ -1,11 +1,5 @@
import styled from '@emotion/styled';
import { MouseEvent, useMemo, useRef, useState } from 'react';
import {
IconComponent,
MenuItem,
MenuItemSelect,
SelectOption,
} from 'twenty-ui';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@ -17,6 +11,9 @@ import { SelectControl } from '@/ui/input/components/SelectControl';
import { DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
import { isDefined } from 'twenty-shared/utils';
import { SelectHotkeyScope } from '../types/SelectHotkeyScope';
import { IconComponent } from 'twenty-ui/display';
import { MenuItem, MenuItemSelect } from 'twenty-ui/navigation';
import { SelectOption } from 'twenty-ui/input';
export type SelectSizeVariant = 'small' | 'default';

View File

@ -2,11 +2,8 @@ import { SelectSizeVariant } from '@/ui/input/components/Select';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
import {
IconChevronDown,
OverflowingTextWithTooltip,
SelectOption,
} from 'twenty-ui';
import { IconChevronDown, OverflowingTextWithTooltip } from 'twenty-ui/display';
import { SelectOption } from 'twenty-ui/input';
export type SelectControlTextAccent = 'default' | 'placeholder';

View File

@ -7,7 +7,9 @@ import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useLis
import { useEffect, useMemo, useRef, useState } from 'react';
import { Key } from 'ts-key-enum';
import { isDefined } from 'twenty-shared/utils';
import { MenuItemSelectTag, SelectOption, TagColor } from 'twenty-ui';
import { MenuItemSelectTag } from 'twenty-ui/navigation';
import { SelectOption } from 'twenty-ui/input';
import { TagColor } from 'twenty-ui/components';
interface SelectInputProps {
onOptionSelected: (selectedOption: SelectOption) => void;

View File

@ -3,10 +3,9 @@ import { FocusEventHandler, useId } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { RGBA } from 'twenty-ui';
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { InputHotkeyScope } from '../types/InputHotkeyScope';
import { RGBA } from 'twenty-ui/theme';
const MAX_ROWS = 5;

View File

@ -11,9 +11,10 @@ import {
useRef,
useState,
} from 'react';
import { AutogrowWrapper, IconComponent, IconEye, IconEyeOff } from 'twenty-ui';
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { AutogrowWrapper } from 'twenty-ui/utilities';
import { IconComponent, IconEye, IconEyeOff } from 'twenty-ui/display';
const StyledContainer = styled.div<
Pick<TextInputV2ComponentProps, 'fullWidth'>

View File

@ -8,7 +8,7 @@ import { isDefined } from 'twenty-shared/utils';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import styled from '@emotion/styled';
import { OverflowingTextWithTooltip } from 'twenty-ui';
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
type InputProps = {
value?: string;

View File

@ -1,10 +1,14 @@
import { Meta, StoryObj } from '@storybook/react';
import { CatalogDecorator, CatalogStory, ComponentDecorator } from 'twenty-ui';
import {
AutosizeTextInput,
AutosizeTextInputVariant,
} from '../AutosizeTextInput';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
} from 'twenty-ui/testing';
const meta: Meta<typeof AutosizeTextInput> = {
title: 'UI/Input/AutosizeTextInput/AutosizeTextInput',

View File

@ -1,12 +1,12 @@
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from 'twenty-ui';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
import { sleep } from '~/utils/sleep';
import { IconPicker, IconPickerProps } from '../IconPicker';
import { ComponentDecorator } from 'twenty-ui/testing';
type RenderProps = IconPickerProps;
const Render = (args: RenderProps) => {

View File

@ -1,10 +1,10 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { workspaceLogoUrl } from '~/testing/mock-data/users';
import { ImageInput } from '../ImageInput';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof ImageInput> = {
title: 'UI/Input/ImageInput/ImageInput',

View File

@ -1,9 +1,10 @@
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/test';
import { useState } from 'react';
import { ComponentDecorator, IconPlus } from 'twenty-ui';
import { Select, SelectProps } from '../Select';
import { ComponentDecorator } from 'twenty-ui/testing';
import { IconPlus } from 'twenty-ui/display';
type RenderProps = SelectProps<string | number | boolean | null>;

View File

@ -1,10 +1,10 @@
import { Meta, StoryObj } from '@storybook/react';
import { useState } from 'react';
import { ComponentDecorator } from 'twenty-ui';
import { expect } from '@storybook/jest';
import { userEvent, within } from '@storybook/test';
import { TextArea, TextAreaProps } from '../TextArea';
import { ComponentDecorator } from 'twenty-ui/testing';
type RenderProps = TextAreaProps;

View File

@ -1,8 +1,8 @@
import { Meta, StoryObj } from '@storybook/react';
import { useState } from 'react';
import { ComponentDecorator } from 'twenty-ui';
import { TextInput, TextInputProps } from '../TextInput';
import { ComponentDecorator } from 'twenty-ui/testing';
type RenderProps = TextInputProps;

View File

@ -1,11 +1,11 @@
import { Meta, StoryObj } from '@storybook/react';
import { useState } from 'react';
import { ComponentDecorator } from 'twenty-ui';
import {
TextInputV2,
TextInputV2ComponentProps,
} from '@/ui/input/components/TextInputV2';
import { ComponentDecorator } from 'twenty-ui/testing';
type RenderProps = TextInputV2ComponentProps;

View File

@ -1,7 +1,7 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { TitleInput } from '@/ui/input/components/TitleInput';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof TitleInput> = {
title: 'UI/Input/TitleInput',

View File

@ -1,9 +1,10 @@
import { useMemo } from 'react';
import { IconCircleOff, IconComponentProps, SelectOption } from 'twenty-ui';
import { SELECT_COUNTRY_DROPDOWN_ID } from '@/ui/input/components/internal/country/constants/SelectCountryDropdownId';
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
import { Select } from '@/ui/input/components/Select';
import { IconCircleOff, IconComponentProps } from 'twenty-ui/display';
import { SelectOption } from 'twenty-ui/input';
export const CountrySelect = ({
label,

View File

@ -1,6 +1,5 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconChevronDown } from 'twenty-ui';
import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
@ -9,6 +8,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { CurrencyPickerHotkeyScope } from '../types/CurrencyPickerHotkeyScope';
import { CurrencyPickerDropdownSelect } from './CurrencyPickerDropdownSelect';
import { IconChevronDown } from 'twenty-ui/display';
const StyledDropdownButtonContainer = styled.div`
align-items: center;

View File

@ -4,9 +4,8 @@ import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui';
import { Currency } from './CurrencyPickerDropdownButton';
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation';
export const CurrencyPickerDropdownSelect = ({
currencies,

View File

@ -1,6 +1,5 @@
import styled from '@emotion/styled';
import { DateTime } from 'luxon';
import { IconChevronLeft, IconChevronRight, LightIconButton } from 'twenty-ui';
import { Select } from '@/ui/input/components/Select';
import { DateTimeInput } from '@/ui/input/components/internal/date/components/DateTimeInput';
@ -10,6 +9,8 @@ import {
MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID,
MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID,
} from './InternalDatePicker';
import { IconChevronLeft, IconChevronRight } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
const StyledCustomDatePickerHeader = styled.div`
align-items: center;

View File

@ -1,11 +1,6 @@
import styled from '@emotion/styled';
import { DateTime } from 'luxon';
import ReactDatePicker from 'react-datepicker';
import {
IconCalendarX,
MenuItemLeftContent,
StyledHoverableMenuItemBase,
} from 'twenty-ui';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
@ -22,6 +17,11 @@ import { t } from '@lingui/core/macro';
import { useContext } from 'react';
import 'react-datepicker/dist/react-datepicker.css';
import { isDefined } from 'twenty-shared/utils';
import { IconCalendarX } from 'twenty-ui/display';
import {
MenuItemLeftContent,
StyledHoverableMenuItemBase,
} from 'twenty-ui/navigation';
export const MONTH_AND_YEAR_DROPDOWN_ID = 'date-picker-month-and-year-dropdown';
export const MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID =

View File

@ -1,9 +1,9 @@
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from 'twenty-ui';
import { DateTimePicker } from '../InternalDatePicker';
import { isDefined } from 'twenty-shared/utils';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof DateTimePicker> = {
title: 'UI/Input/Internal/InternalDatePicker',

View File

@ -5,7 +5,6 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useEffect, useState } from 'react';
import { IconChevronDown, IconWorld } from 'twenty-ui';
import { CountryPickerHotkeyScope } from '../types/CountryPickerHotkeyScope';
@ -13,6 +12,7 @@ import { PhoneCountryPickerDropdownSelect } from './PhoneCountryPickerDropdownSe
import 'react-phone-number-input/style.css';
import { isDefined } from 'twenty-shared/utils';
import { IconChevronDown, IconWorld } from 'twenty-ui/display';
type StyledDropdownButtonProps = {
isUnfolded: boolean;

View File

@ -7,7 +7,7 @@ import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/Dropdow
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import 'react-phone-number-input/style.css';
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui';
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation';
const StyledIconContainer = styled.div`
align-items: center;

View File

@ -10,7 +10,7 @@ import {
SideMenuController,
} from '@blocknote/react';
import styled from '@emotion/styled';
import { IconColorSwatch, IconPlus, IconTrash } from 'twenty-ui';
import { IconColorSwatch, IconPlus, IconTrash } from 'twenty-ui/display';
type CustomSideMenuProps = {
editor: typeof BLOCK_SCHEMA.BlockNoteEditor;

View File

@ -1,6 +1,6 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui';
import { IconComponent } from 'twenty-ui/display';
const StyledContainer = styled.div<{ Variant: Variants }>`
color: ${({ theme, Variant }) =>

View File

@ -1,12 +1,13 @@
import { SuggestionMenuProps } from '@blocknote/react';
import styled from '@emotion/styled';
import { IconComponent, MenuItemSuggestion } from 'twenty-ui';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
import { useFloating } from '@floating-ui/react';
import { createPortal } from 'react-dom';
import { IconComponent } from 'twenty-ui/display';
import { MenuItemSuggestion } from 'twenty-ui/navigation';
export type SuggestionItem = {
title: string;

View File

@ -1,9 +1,9 @@
import { act } from 'react-dom/test-utils';
import { renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { Icon123, IconApps } from 'twenty-ui';
import { useIconPicker } from '@/ui/input/hooks/useIconPicker';
import { Icon123, IconApps } from 'twenty-ui/display';
describe('useIconPicker', () => {
it('should return correct iconPickerState', async () => {

View File

@ -1,6 +1,6 @@
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { MenuItem } from 'twenty-ui';
import { MenuItem } from 'twenty-ui/navigation';
const StyledCreateNewButton = styled(MenuItem)<{ hovered?: boolean }>`
${({ hovered, theme }) =>

View File

@ -1,4 +1,5 @@
import { createState, IconApps, IconComponent } from 'twenty-ui';
import { createState } from 'twenty-ui/utilities';
import { IconApps, IconComponent } from 'twenty-ui/display';
type IconPickerState = {
Icon: IconComponent;