Migrate twenty ui to jotai (#17900)
## Remove Recoil from twenty-ui Completely removes the `recoil` dependency from `twenty-ui` by converting all atoms, hooks, and providers to Jotai equivalents. ### twenty-ui - `createState` now returns a Jotai `PrimitiveAtom` instead of a Recoil atom - `iconsState`, `IconsProvider`, `useIcons` converted to Jotai (`useSetAtom`, `useAtomValue`) - `RecoilRootDecorator` now uses Jotai `Provider` (name kept for compat) - Deleted unused `invalidAvatarUrlsState` (Avatar already uses `invalidAvatarUrlsAtomV2`) - Removed `recoil` from `package.json` ### twenty-front - Created local Recoil `createState` at `@/ui/utilities/state/utils/createState` for ~112 state files still on Recoil - Updated all imports accordingly - Removed `iconsState` from Recoil snapshot preservation in `useAuth` (lives in Jotai store now)
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const invalidAvatarUrlsState = atom<string[]>({
|
||||
key: 'invalidAvatarUrlsState',
|
||||
default: [],
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import * as recoil from 'recoil';
|
||||
import * as jotai from 'jotai';
|
||||
|
||||
import {
|
||||
Icon123,
|
||||
@@ -15,10 +15,10 @@ describe('useIcons', () => {
|
||||
IconBuildingSkyscraper,
|
||||
};
|
||||
jest
|
||||
.spyOn(recoil, 'useRecoilValue')
|
||||
.spyOn(jotai, 'useAtomValue')
|
||||
.mockImplementationOnce(() => mockedStateIcons);
|
||||
const { result } = renderHook(() => useIcons(), {
|
||||
wrapper: recoil.RecoilRoot,
|
||||
wrapper: jotai.Provider,
|
||||
});
|
||||
|
||||
it('returns default icon when no icon key is provided', () => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useAtomValue } from 'jotai';
|
||||
|
||||
import { Icon123 } from '@ui/display/icon/components/TablerIcons';
|
||||
import { iconsState } from '@ui/display/icon/states/iconsState';
|
||||
|
||||
export const useIcons = () => {
|
||||
const icons = useRecoilValue(iconsState);
|
||||
const icons = useAtomValue(iconsState);
|
||||
const defaultIcon = Icon123;
|
||||
|
||||
const getIcons = () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { iconsState } from '@ui/display/icon/states/iconsState';
|
||||
|
||||
@@ -8,7 +8,7 @@ export type IconsProviderProps = {
|
||||
};
|
||||
|
||||
export const IconsProvider = ({ children }: IconsProviderProps) => {
|
||||
const setIcons = useSetRecoilState(iconsState);
|
||||
const setIcons = useSetAtom(iconsState);
|
||||
|
||||
useEffect(() => {
|
||||
import('./internal/AllIcons').then(({ ALL_ICONS }) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { type IconComponent } from '@ui/display/icon/types/IconComponent';
|
||||
import { createState } from '@ui/utilities/state/utils/createState';
|
||||
import { atom } from 'jotai';
|
||||
|
||||
export const iconsState = createState<Record<string, IconComponent>>({
|
||||
key: 'iconsState',
|
||||
defaultValue: {},
|
||||
});
|
||||
import { type IconComponent } from '@ui/display/icon/types/IconComponent';
|
||||
|
||||
export const iconsState = atom<Record<string, IconComponent>>({});
|
||||
iconsState.debugLabel = 'iconsState';
|
||||
|
||||
@@ -12,7 +12,6 @@ export { Avatar } from './avatar/components/Avatar';
|
||||
export type { AvatarGroupProps } from './avatar/components/AvatarGroup';
|
||||
export { AvatarGroup } from './avatar/components/AvatarGroup';
|
||||
export { invalidAvatarUrlsAtomV2 } from './avatar/components/states/invalidAvatarUrlsAtomV2';
|
||||
export { invalidAvatarUrlsState } from './avatar/components/states/isInvalidAvatarUrlState';
|
||||
export { AVATAR_PROPERTIES_BY_SIZE } from './avatar/constants/AvatarPropertiesBySize';
|
||||
export type { AvatarSize } from './avatar/types/AvatarSize';
|
||||
export type { AvatarType } from './avatar/types/AvatarType';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { type Decorator } from '@storybook/react-vite';
|
||||
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
|
||||
// Kept as RecoilRootDecorator name for backward compatibility during migration
|
||||
export const RecoilRootDecorator: Decorator = (Story, _context) => (
|
||||
<RecoilRoot>
|
||||
<JotaiProvider>
|
||||
<Story />
|
||||
</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
);
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import { atom, type AtomEffect } from 'recoil';
|
||||
import { atom, type PrimitiveAtom } from 'jotai';
|
||||
|
||||
export const createState = <ValueType>({
|
||||
key,
|
||||
defaultValue,
|
||||
effects,
|
||||
}: {
|
||||
key: string;
|
||||
defaultValue: ValueType;
|
||||
effects?: ReadonlyArray<AtomEffect<ValueType>>;
|
||||
}) => {
|
||||
const recoilState = atom<ValueType>({
|
||||
key,
|
||||
default: defaultValue,
|
||||
effects,
|
||||
});
|
||||
return recoilState;
|
||||
}): PrimitiveAtom<ValueType> => {
|
||||
const jotaiAtom = atom<ValueType>(defaultValue);
|
||||
jotaiAtom.debugLabel = key;
|
||||
return jotaiAtom;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user