[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

@ -1,8 +1,10 @@
import { DragDropContext, Droppable } from '@hello-pangea/dnd';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator, IconBell, MenuItemDraggable } from 'twenty-ui';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
import { ComponentDecorator } from 'twenty-ui/testing';
import { IconBell } from 'twenty-ui/display';
import { MenuItemDraggable } from 'twenty-ui/navigation';
const meta: Meta<typeof DraggableItem> = {
title: 'UI/Layout/DraggableList/DraggableItem',

View File

@ -2,7 +2,9 @@ import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableIt
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
import { action } from '@storybook/addon-actions';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator, IconBell, MenuItemDraggable } from 'twenty-ui';
import { ComponentDecorator } from 'twenty-ui/testing';
import { IconBell } from 'twenty-ui/display';
import { MenuItemDraggable } from 'twenty-ui/navigation';
const meta: Meta<typeof DraggableList> = {
title: 'UI/Layout/DraggableList/DraggableList',

View File

@ -1,7 +1,8 @@
import { Avatar, AvatarProps, IconComponent, LightIconButton } from 'twenty-ui';
import { MouseEvent, ReactElement } from 'react';
import styled from '@emotion/styled';
import { useTheme } from '@emotion/react';
import { Avatar, AvatarProps, IconComponent } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
const StyledNonClickableStartIcon = styled.div`
align-items: center;

View File

@ -2,10 +2,10 @@ import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { forwardRef, InputHTMLAttributes, ReactNode, useRef } from 'react';
import 'react-phone-number-input/style.css';
import { TEXT_INPUT_STYLE } from 'twenty-ui';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
import { TEXT_INPUT_STYLE } from 'twenty-ui/theme';
const StyledInput = styled.input<{
withRightComponent?: boolean;

View File

@ -1,7 +1,7 @@
import { useInputFocusWithoutScrollOnMount } from '@/ui/input/hooks/useInputFocusWithoutScrollOnMount';
import styled from '@emotion/styled';
import { forwardRef, InputHTMLAttributes } from 'react';
import { TEXT_INPUT_STYLE } from 'twenty-ui';
import { TEXT_INPUT_STYLE } from 'twenty-ui/theme';
const StyledDropdownMenuSearchInputContainer = styled.div`
align-items: center;

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import { Label } from 'twenty-ui';
import { Label } from 'twenty-ui/display';
export const StyledDropdownMenuSubheader = styled(Label)`
background-color: ${({ theme }) => theme.background.transparent.lighter};

View File

@ -3,15 +3,6 @@ import { Decorator, Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, waitFor, within } from '@storybook/test';
import { PlayFunction } from '@storybook/types';
import { useState } from 'react';
import {
Avatar,
Button,
ComponentDecorator,
IconChevronLeft,
MenuItem,
MenuItemMultiSelectAvatar,
MenuItemSelectAvatar,
} from 'twenty-ui';
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
@ -23,6 +14,14 @@ import { DropdownMenuSearchInput } from '../DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '../DropdownMenuSeparator';
import { StyledDropdownMenuSubheader } from '../StyledDropdownMenuSubheader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { Avatar, IconChevronLeft } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { ComponentDecorator } from 'twenty-ui/testing';
import {
MenuItem,
MenuItemMultiSelectAvatar,
MenuItemSelectAvatar,
} from 'twenty-ui/navigation';
const meta: Meta<typeof Dropdown> = {
title: 'UI/Layout/Dropdown/Dropdown',

View File

@ -1,19 +1,18 @@
import { Meta, StoryObj } from '@storybook/react';
import {
AVATAR_URL_MOCK,
Avatar,
ComponentDecorator,
IconChevronLeft,
IconChevronRight,
IconPlus,
MenuItem,
} from 'twenty-ui';
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { AVATAR_URL_MOCK, ComponentDecorator } from 'twenty-ui/testing';
import {
Avatar,
IconChevronLeft,
IconChevronRight,
IconPlus,
} from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
const meta: Meta<typeof DropdownMenuHeader> = {
title: 'UI/Layout/Dropdown/DropdownMenuHeader',

View File

@ -1,7 +1,7 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { DropdownMenuInput } from '../DropdownMenuInput';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof DropdownMenuInput> = {
title: 'UI/Layout/Dropdown/DropdownMenuInput',

View File

@ -1,5 +1,4 @@
import { createState } from '@ui/utilities/state/utils/createState';
import { createState } from 'twenty-ui/utilities';
export const activeDropdownFocusIdState = createState<string | null>({
key: 'activeDropdownFocusIdState',
defaultValue: null,

View File

@ -1,5 +1,4 @@
import { createState } from '@ui/utilities/state/utils/createState';
import { createState } from 'twenty-ui/utilities';
export const previousDropdownFocusIdState = createState<string | null>({
key: 'previousDropdownFocusIdState',
defaultValue: null,

View File

@ -1,14 +1,12 @@
import styled from '@emotion/styled';
import { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
import {
AnimatedContainer,
ChipSize,
OverflowingTextWithTooltip,
} from 'twenty-ui';
import { ExpandedListDropdown } from '@/ui/layout/expandable-list/components/ExpandedListDropdown';
import { isFirstOverflowingChildElement } from '@/ui/layout/expandable-list/utils/isFirstOverflowingChildElement';
import { isDefined } from 'twenty-shared/utils';
import { AnimatedContainer } from 'twenty-ui/utilities';
import { ChipSize } from 'twenty-ui/components';
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
const StyledContainer = styled.div`
align-items: center;

View File

@ -4,8 +4,10 @@ import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/test';
import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList';
import { ComponentDecorator, MAIN_COLOR_NAMES, Tag } from 'twenty-ui';
import { isDefined } from 'twenty-shared/utils';
import { Tag } from 'twenty-ui/components';
import { ComponentDecorator } from 'twenty-ui/testing';
import { MAIN_COLOR_NAMES } from 'twenty-ui/theme';
const StyledContainer = styled.div`
padding: ${({ theme }) => theme.spacing(1)};
@ -58,7 +60,7 @@ export const WithExpandedList: Story = {
const rootCanvas = within(root);
const chipCount = await rootCanvas.findByText('+3');
const chipCount = await rootCanvas.findByText(/^\+\d+$/);
await userEvent.click(chipCount);

View File

@ -8,7 +8,9 @@ import {
} from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { IconButton, IconX, useIsMobile } from 'twenty-ui';
import { IconButton } from 'twenty-ui/input';
import { IconX } from 'twenty-ui/display';
import { useIsMobile } from 'twenty-ui/utilities';
type FullScreenContainerProps = {
children: JSX.Element | JSX.Element[];

View File

@ -1,8 +1,11 @@
import { FullScreenContainer } from '@/ui/layout/fullscreen/components/FullScreenContainer';
import styled from '@emotion/styled';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator, ComponentWithRouterDecorator } from 'twenty-ui';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import {
ComponentDecorator,
ComponentWithRouterDecorator,
} from 'twenty-ui/testing';
const meta: Meta<typeof FullScreenContainer> = {
title: 'UI/Layout/FullScreenContainer',

View File

@ -1,21 +1,15 @@
import styled from '@emotion/styled';
import { AnimatePresence, LayoutGroup } from 'framer-motion';
import { ReactNode, useState } from 'react';
import {
Button,
ButtonAccent,
H1Title,
H1TitleFontColor,
Section,
SectionAlignment,
SectionFontColor,
} from 'twenty-ui';
import { useDebouncedCallback } from 'use-debounce';
import { TextInput } from '@/ui/input/components/TextInput';
import { Modal, ModalVariants } from '@/ui/layout/modal/components/Modal';
import { useLingui } from '@lingui/react/macro';
import { Button, ButtonAccent } from 'twenty-ui/input';
import { H1Title, H1TitleFontColor } from 'twenty-ui/display';
import { Section, SectionAlignment, SectionFontColor } from 'twenty-ui/layout';
export type ConfirmationModalProps = {
isOpen: boolean;

View File

@ -1,8 +1,8 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { ConfirmationModal } from '../ConfirmationModal';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof ConfirmationModal> = {
title: 'UI/Layout/Modal/ConfirmationModal',

View File

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

View File

@ -1,12 +1,3 @@
import {
AnimatedButton,
AppTooltip,
getOsControlSymbol,
TooltipDelay,
TooltipPosition,
useIsMobile,
} from 'twenty-ui';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
import { useTheme } from '@emotion/react';
@ -15,6 +6,9 @@ import { i18n } from '@lingui/core';
import { t } from '@lingui/core/macro';
import { motion } from 'framer-motion';
import { useRecoilValue } from 'recoil';
import { AnimatedButton } from 'twenty-ui/input';
import { AppTooltip, TooltipDelay, TooltipPosition } from 'twenty-ui/display';
import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities';
const StyledButtonWrapper = styled.div`
z-index: 30;

View File

@ -18,7 +18,7 @@ import { Global, css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { AnimatePresence, LayoutGroup, motion } from 'framer-motion';
import { Outlet } from 'react-router-dom';
import { useScreenSize } from 'twenty-ui';
import { useScreenSize } from 'twenty-ui/utilities';
const StyledLayout = styled.div`
background: ${({ theme }) => theme.background.noisy};

View File

@ -1,6 +1,8 @@
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { useLingui } from '@lingui/react/macro';
import { Button, IconPlus, useIsMobile } from 'twenty-ui';
import { Button } from 'twenty-ui/input';
import { IconPlus } from 'twenty-ui/display';
import { useIsMobile } from 'twenty-ui/utilities';
type PageAddButtonProps = {
onClick?: () => void;

View File

@ -1,8 +1,8 @@
import styled from '@emotion/styled';
import { ReactNode } from 'react';
import { MOBILE_VIEWPORT } from 'twenty-ui';
import { PagePanel } from './PagePanel';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
type PageBodyProps = {
children: ReactNode;

View File

@ -2,18 +2,18 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ReactNode } from 'react';
import { useRecoilValue } from 'recoil';
import {
IconComponent,
IconX,
LightIconButton,
MOBILE_VIEWPORT,
OverflowingTextWithTooltip,
} from 'twenty-ui';
import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton';
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import {
IconComponent,
IconX,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
export const PAGE_BAR_MIN_HEIGHT = 40;

View File

@ -1,5 +1,4 @@
import styled from '@emotion/styled';
import { Button, IconCheckbox, IconNotes, IconPlus, MenuItem } from 'twenty-ui';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
@ -12,6 +11,9 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { Dropdown } from '../../dropdown/components/Dropdown';
import { Button } from 'twenty-ui/input';
import { IconCheckbox, IconNotes, IconPlus } from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
const StyledContainer = styled.div`
z-index: 1;

View File

@ -5,12 +5,17 @@ import { Trans } from '@lingui/react/macro';
import { ChangeEvent, ReactNode, useRef } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { isDefined } from 'twenty-shared/utils';
import { AppTooltip, Avatar, AvatarType, IconComponent } from 'twenty-ui';
import { v4 as uuidV4 } from 'uuid';
import {
beautifyExactDateTime,
beautifyPastDateRelativeToNow,
} from '~/utils/date-utils';
import {
AppTooltip,
Avatar,
AvatarType,
IconComponent,
} from 'twenty-ui/display';
type ShowPageSummaryCardProps = {
avatarPlaceholder: string;

View File

@ -1,5 +1,4 @@
import { createState } from '@ui/utilities/state/utils/createState';
import { createState } from 'twenty-ui/utilities';
export const isDefaultLayoutAuthModalVisibleState = createState<boolean>({
key: 'isDefaultLayoutAuthModalVisibleState',
defaultValue: true,

View File

@ -4,7 +4,8 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ReactElement } from 'react';
import { Link } from 'react-router-dom';
import { Avatar, IconComponent, Pill } from 'twenty-ui';
import { Avatar, IconComponent } from 'twenty-ui/display';
import { Pill } from 'twenty-ui/components';
type TabProps = {
id: string;

View File

@ -7,8 +7,8 @@ import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/
import styled from '@emotion/styled';
import * as React from 'react';
import { useEffect } from 'react';
import { IconComponent } from 'twenty-ui';
import { Tab } from './Tab';
import { IconComponent } from 'twenty-ui/display';
export type SingleTabProps<T extends string = string> = {
title: string;

View File

@ -1,12 +1,12 @@
import { Meta, StoryObj } from '@storybook/react';
import { Tab } from '../Tab';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
IconCheckbox,
} from 'twenty-ui';
import { Tab } from '../Tab';
} from 'twenty-ui/testing';
import { IconCheckbox } from 'twenty-ui/display';
const meta: Meta<typeof Tab> = {
title: 'UI/Layout/Tab/Tab',

View File

@ -1,8 +1,9 @@
import { Meta, StoryObj } from '@storybook/react';
import { expect, within } from '@storybook/test';
import { ComponentWithRouterDecorator, IconCheckbox } from 'twenty-ui';
import { TabList } from '../TabList';
import { ComponentWithRouterDecorator } from 'twenty-ui/testing';
import { IconCheckbox } from 'twenty-ui/display';
const tabs = [
{

View File

@ -1,6 +1,6 @@
import { LayoutCard } from '@/ui/layout/tab/types/LayoutCard';
import { TabVisibilityConfig } from '@/ui/layout/tab/types/TabVisibilityConfig';
import { IconComponent } from 'twenty-ui';
import { IconComponent } from 'twenty-ui/display';
export type RecordLayoutTab = {
title: string;

View File

@ -2,7 +2,7 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { sortedFieldByTableFamilyState } from '@/ui/layout/table/states/sortedFieldByTableFamilyState';
import { TableSortValue } from '@/ui/layout/table/types/TableSortValue';
import { useRecoilState } from 'recoil';
import { IconArrowDown, IconArrowUp, IconComponent } from 'twenty-ui';
import { IconArrowDown, IconArrowUp, IconComponent } from 'twenty-ui/display';
export const SortableTableHeader = ({
tableId,

View File

@ -1,7 +1,7 @@
import isPropValid from '@emotion/is-prop-valid';
import styled from '@emotion/styled';
import { Link } from 'react-router-dom';
import { MOBILE_VIEWPORT } from 'twenty-ui';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
const StyledTableRow = styled('div', {
shouldForwardProp: (prop) =>

View File

@ -1,8 +1,8 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ReactNode, useState } from 'react';
import { IconChevronDown, IconChevronUp, Label } from 'twenty-ui';
import { TableBody } from './TableBody';
import { IconChevronDown, IconChevronUp, Label } from 'twenty-ui/display';
type TableSectionProps = {
children: ReactNode;

View File

@ -1,11 +1,11 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { Table } from '../Table';
import { TableCell } from '../TableCell';
import { TableHeader } from '../TableHeader';
import { TableRow } from '../TableRow';
import { TableSection } from '../TableSection';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof Table> = {
title: 'UI/Layout/Table/Table',

View File

@ -1,5 +1,5 @@
import { MessageDescriptor } from '@lingui/core';
import { IconComponent } from 'twenty-ui';
import { IconComponent } from 'twenty-ui/display';
export type TableFieldMetadata<ItemType> = {
fieldLabel: MessageDescriptor;