Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 19 upgrade #1026 #1031

Merged
merged 8 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion browser/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = {
'create-template/tsconfig.json',
],
},
plugins: ['react', '@typescript-eslint', 'prettier', 'react-hooks', 'jsx-a11y'],
plugins: ['react', '@typescript-eslint', 'prettier', 'react-hooks', 'jsx-a11y', 'eslint-plugin-react-compiler'],
settings: {
react: {
version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
Expand Down Expand Up @@ -114,5 +114,6 @@ module.exports = {
"@typescript-eslint/no-shadow": ["error"],
"@typescript-eslint/member-ordering": "error",
"react/no-unknown-property": ["error", { "ignore": ["about"] }],
'react-compiler/react-compiler': 'error',
},
};
6 changes: 5 additions & 1 deletion browser/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ This changelog covers all five packages, as they are (for now) updated as a whol

### @tomic/react

- Add cjs build.
- BREAKING CHANGE: `useCanWrite` now only returns a boolean. There is no longer a message returned.
- BREAKING CHANGE: `useCanWrite` does not take an agent as argument any more and only checks the agent set in the store. If you need to explicitly check a different agent, use `await resource.canWrite(agent)`.
- BREAKING CHANGE: `useDebounce` and `useDebouncedCallback` are no longer exported.
- Added `useDebouncedSave` hook.
- Add a cjs build.

### @tomic/cli

Expand Down
1 change: 1 addition & 0 deletions browser/data-browser/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<link color="#1e43a3" href="/app_data/images/mask-icon.svg" rel="mask-icon" />
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="yes" name="mobile-web-app-capable" />
<link rel="preconnect" crossorigin="anonymous" href="https://atomicdata.dev">
<!-- Custom fonts -->
<link rel="preconnect" crossorigin="anonymous" href="https://fonts.googleapis.com">
<link rel="preconnect" crossorigin="anonymous" href="https://fonts.gstatic.com">
Expand Down
25 changes: 12 additions & 13 deletions browser/data-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-tabs": "^1.1.1",
"@tanstack/react-router": "^1.95.1",
"@tiptap/extension-image": "^2.9.1",
"@tiptap/extension-link": "^2.9.1",
"@tiptap/extension-placeholder": "^2.9.1",
Expand All @@ -31,38 +32,36 @@
"prismjs": "^1.29.0",
"query-string": "^7.1.3",
"quick-score": "^0.2.0",
"react": "^18.3.1",
"react": "^19.0.0",
"react-colorful": "^5.6.1",
"react-dom": "^18.3.1",
"react-dom": "^19.0.0",
"react-dropzone": "^11.7.1",
"react-helmet-async": "^1.3.0",
"react-hot-toast": "^2.4.1",
"react-hotkeys-hook": "^3.4.7",
"react-icons": "^4.12.0",
"react-intersection-observer": "^9.13.1",
"react-is": "^18.3.1",
"react-markdown": "^8.0.7",
"react-is": "^19.0.0",
"react-markdown": "^9.0.3",
"react-pdf": "^9.1.1",
"react-router": "^6.27.0",
"react-router-dom": "^6.27.0",
"react-virtualized-auto-sizer": "^1.0.24",
"react-window": "^1.8.10",
"reactflow": "^11.11.4",
"remark-gfm": "^3.0.1",
"remark-gfm": "^4.0.0",
"styled-components": "^6.1.13",
"stylis": "4.3.0",
"tippy.js": "^6.3.7",
"tiptap-markdown": "^0.8.10"
},
"devDependencies": {
"@swc/plugin-styled-components": "^2.0.12",
"@tanstack/router-devtools": "^1.95.1",
"@types/prismjs": "^1.26.5",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@types/react-pdf": "^7.0.0",
"@types/react-router-dom": "^5.3.3",
"@types/react-window": "^1.8.8",
"@vitejs/plugin-react-swc": "^3.7.1",
"@vitejs/plugin-react": "^4.3.4",
"babel-plugin-react-compiler": "19.0.0-beta-37ed2a7-20241206",
"babel-plugin-styled-components": "^2.1.4",
"csstype": "^3.1.3",
"gh-pages": "^5.0.0",
"lint-staged": "^10.5.4",
Expand Down
83 changes: 5 additions & 78 deletions browser/data-browser/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import { StoreContext, Store } from '@tomic/react';
import { StyleSheetManager, type ShouldForwardProp } from 'styled-components';

import { GlobalStyle, ThemeWrapper } from './styling';
import { AppRoutes } from './routes/Routes';
import { NavWrapper } from './components/Navigation';
import { MetaSetter } from './components/MetaSetter';
import { Toaster } from './components/Toaster';
import { isDev } from './config';
import { initBugsnag } from './helpers/loggingHandlers';
import HotKeysWrapper from './components/HotKeyWrapper';
import { AppSettingsContextProvider } from './helpers/AppSettings';
import CrashPage from './views/CrashPage';
import { DialogGlobalContextProvider } from './components/Dialog/DialogGlobalContextProvider';
import { registerHandlers } from './handlers';
import { ErrorBoundary } from './views/ErrorPage';
import { NetworkIndicator } from './components/NetworkIndicator';
import { getAgentFromLocalStorage } from './helpers/agentStorage';
import { DropdownContainer } from './components/Dropdown/DropdownContainer';
import { PopoverContainer } from './components/Popover';
import { SkipNav } from './components/SkipNav';
import { ControlLockProvider } from './hooks/useControlLock';
import { FormValidationContextProvider } from './components/forms/formValidation/FormValidationContextProvider';
import { registerCustomCreateActions } from './components/forms/NewForm/CustomCreateActions';
import isPropValid from '@emotion/is-prop-valid';
import { NewResourceUIProvider } from './components/forms/NewForm/useNewResourceUI';
import { serverURLStorage } from './helpers/serverURLStorage';

import type { JSX } from 'react';
import { RouterProvider } from '@tanstack/react-router';
import { router } from './routes/Router';

function fixDevUrl(url: string) {
if (isDev()) {
return url.replace('5173', '9883');
Expand Down Expand Up @@ -57,10 +39,6 @@ declare global {
bugsnagApiKey: string;
}
}
// Setup bugsnag for error handling, but only if there's an API key
const ErrBoundary = window.bugsnagApiKey
? initBugsnag(window.bugsnagApiKey)
: ErrorBoundary;

// Fetch all the Properties and Classes - this helps speed up the app.
store.preloadPropsAndClasses();
Expand All @@ -74,62 +52,11 @@ if (isDev()) {
window.store = store;
}

// This implements the default behavior from styled-components v5
const shouldForwardProp: ShouldForwardProp<'web'> = (propName, target) => {
if (typeof target === 'string') {
// For HTML elements, forward the prop if it is a valid HTML attribute
return isPropValid(propName);
}

// For other elements, forward all props
return true;
};

/** Entrypoint of the application. This is where providers go. */
function App(): JSX.Element {
return (
<StoreContext.Provider value={store}>
<AppSettingsContextProvider>
<HelmetProvider>
{/* Basename is for hosting on GitHub pages */}
<BrowserRouter basename='/'>
<ControlLockProvider>
<HotKeysWrapper>
<StyleSheetManager shouldForwardProp={shouldForwardProp}>
<ThemeWrapper>
<GlobalStyle />
{/* @ts-ignore fallback component type too strict */}
<ErrBoundary FallbackComponent={CrashPage}>
{/* Default form validation provider. Does not do anything on its own but will make sure useValidation works without context*/}
<FormValidationContextProvider
onValidationChange={() => undefined}
>
<Toaster />
<MetaSetter />
<DropdownContainer>
<DialogGlobalContextProvider>
<PopoverContainer>
<DropdownContainer>
<NewResourceUIProvider>
<SkipNav />
<NavWrapper>
<AppRoutes />
</NavWrapper>
</NewResourceUIProvider>
</DropdownContainer>
</PopoverContainer>
<NetworkIndicator />
</DialogGlobalContextProvider>
</DropdownContainer>
</FormValidationContextProvider>
</ErrBoundary>
</ThemeWrapper>
</StyleSheetManager>
</HotKeysWrapper>
</ControlLockProvider>
</BrowserRouter>
</HelmetProvider>
</AppSettingsContextProvider>
<RouterProvider router={router}></RouterProvider>
</StoreContext.Provider>
);
}
Expand Down
76 changes: 76 additions & 0 deletions browser/data-browser/src/Providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Toaster } from 'react-hot-toast';
import { StyleSheetManager, type ShouldForwardProp } from 'styled-components';
import { DialogGlobalContextProvider } from './components/Dialog/DialogGlobalContextProvider';
import { DropdownContainer } from './components/Dropdown/DropdownContainer';
import { FormValidationContextProvider } from './components/forms/formValidation/FormValidationContextProvider';
import { NewResourceUIProvider } from './components/forms/NewForm/useNewResourceUI';
import HotKeysWrapper from './components/HotKeyWrapper';
import { MetaSetter } from './components/MetaSetter';
import { NavWrapper } from './components/Navigation';
import { NetworkIndicator } from './components/NetworkIndicator';
import { PopoverContainer } from './components/Popover';
import { SkipNav } from './components/SkipNav';
import { ControlLockProvider } from './hooks/useControlLock';
import { ThemeWrapper, GlobalStyle } from './styling';
import isPropValid from '@emotion/is-prop-valid';
import { initBugsnag } from './helpers/loggingHandlers';
import { ErrorBoundary } from './views/ErrorPage';
import CrashPage from './views/CrashPage';
import { AppSettingsContextProvider } from './helpers/AppSettings';
import { NavStateProvider } from './components/NavState';

// Setup bugsnag for error handling, but only if there's an API key
const ErrBoundary = window.bugsnagApiKey
? initBugsnag(window.bugsnagApiKey)
: ErrorBoundary;

// This implements the default behavior from styled-components v5
const shouldForwardProp: ShouldForwardProp<'web'> = (propName, target) => {
if (typeof target === 'string') {
// For HTML elements, forward the prop if it is a valid HTML attribute
return isPropValid(propName);
}

// For other elements, forward all props
return true;
};

export const Providers: React.FC<React.PropsWithChildren> = ({ children }) => {
return (
<NavStateProvider>
<AppSettingsContextProvider>
<ControlLockProvider>
<HotKeysWrapper>
<StyleSheetManager shouldForwardProp={shouldForwardProp}>
<ThemeWrapper>
<GlobalStyle />
<ErrBoundary FallbackComponent={CrashPage}>
{/* Default form validation provider. Does not do anything on its own but will make sure useValidation works without context*/}
<FormValidationContextProvider
onValidationChange={() => undefined}
>
<Toaster />
<MetaSetter />
<DropdownContainer>
<DialogGlobalContextProvider>
<PopoverContainer>
<DropdownContainer>
<NewResourceUIProvider>
<SkipNav />
<NavWrapper>{children}</NavWrapper>
</NewResourceUIProvider>
</DropdownContainer>
</PopoverContainer>
<NetworkIndicator />
</DialogGlobalContextProvider>
</DropdownContainer>
</FormValidationContextProvider>
</ErrBoundary>
</ThemeWrapper>
</StyleSheetManager>
</HotKeysWrapper>
</ControlLockProvider>
</AppSettingsContextProvider>
</NavStateProvider>
);
};
2 changes: 1 addition & 1 deletion browser/data-browser/src/chunks/EmojiInput/EmojiInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useState } from 'react';
import { useCallback, useState, type JSX } from 'react';
import Picker from '@emoji-mart/react';
import { styled } from 'styled-components';
import * as RadixPopover from '@radix-ui/react-popover';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback } from 'react';
import { useCallback, type JSX } from 'react';
import {
useStore as useFlowStore,
getBezierPath,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Resource, useStore } from '@tomic/react';
import { useCallback } from 'react';
import { useCallback, type JSX } from 'react';
import ReactFlow, {
Controls,
useReactFlow,
Expand Down
2 changes: 1 addition & 1 deletion browser/data-browser/src/chunks/PDFViewer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react';
import { useCallback, useMemo, useState, type JSX } from 'react';
import { pdfjs, Document, Page } from 'react-pdf';
import 'react-pdf/dist/esm/Page/TextLayer.css';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
Expand Down
2 changes: 2 additions & 0 deletions browser/data-browser/src/components/AllProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { styled, css } from 'styled-components';
import PropVal from './PropVal';
import { ALL_PROPS_CONTAINER } from '../helpers/containers';

import type { JSX } from 'react';

type Props = {
resource: Resource;
/** A list of property subjects (URLs) that need not be rendered */
Expand Down
2 changes: 1 addition & 1 deletion browser/data-browser/src/components/AllPropsSimple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
useSubject,
useTitle,
} from '@tomic/react';
import { useMemo } from 'react';
import { useMemo, type JSX } from 'react';
import { styled } from 'styled-components';
import { InlineFormattedResourceList } from './InlineFormattedResourceList';

Expand Down
4 changes: 2 additions & 2 deletions browser/data-browser/src/components/AtomicLink.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, forwardRef } from 'react';
import { ReactNode, forwardRef, type JSX } from 'react';
import { styled } from 'styled-components';
import { constructOpenURL, pathToURL } from '../helpers/navigation';
import { FaExternalLinkAlt } from 'react-icons/fa';
Expand Down Expand Up @@ -33,7 +33,7 @@ export const AtomicLink = forwardRef<HTMLAnchorElement, AtomicLinkProps>(
): JSX.Element => {
const navigate = useNavigateWithTransition();

if (!subject && !href && !path) {
if (subject === undefined && href === undefined && path === undefined) {
return (
<ErrorLook>
No `subject`, `path` or `href` passed to this AtomicLink.
Expand Down
2 changes: 2 additions & 0 deletions browser/data-browser/src/components/BetaBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { styled } from 'styled-components';

import type { JSX } from 'react';

export function BetaBadge(): JSX.Element {
return <Badge>BETA</Badge>;
}
Expand Down
2 changes: 1 addition & 1 deletion browser/data-browser/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef, PropsWithChildren } from 'react';
import { forwardRef, PropsWithChildren, type JSX } from 'react';
import { styled } from 'styled-components';
import { transition } from '../helpers/transition';
import { Spinner } from './Spinner';
Expand Down
2 changes: 1 addition & 1 deletion browser/data-browser/src/components/ButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useId, useState } from 'react';
import { useCallback, useId, useState, type JSX } from 'react';
import { styled } from 'styled-components';

export interface ButtonGroupOption {
Expand Down
7 changes: 4 additions & 3 deletions browser/data-browser/src/components/ClassDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import React, { type JSX } from 'react';
import { Resource, useResource } from '@tomic/react';
import { Detail } from './Detail';
import { getIconForClass } from '../helpers/iconMap';
import { InlineFormattedResourceList } from './InlineFormattedResourceList';
import { AtomicLink } from './AtomicLink';
import { Row } from './Row';

type ClassDetailProps = {
resource: Resource;
Expand All @@ -16,12 +17,12 @@ export const ClassDetail: React.FC<ClassDetailProps> = ({ resource }) => {
}

return (
<Detail>
<Row gap='1ch'>
<InlineFormattedResourceList
subjects={resource.getClasses()}
RenderComp={ClassItem}
/>
</Detail>
</Row>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, type JSX } from 'react';
import { Dialog, DialogContent, DialogTitle, useDialog } from './Dialog';
import { OutlinedSection } from './OutlinedSection';
import { useServerSearch, core, type Core, useResource } from '@tomic/react';
Expand Down
Loading
Loading