Skip to content

Commit

Permalink
'fix' react 19 issues... meh
Browse files Browse the repository at this point in the history
  • Loading branch information
a-type committed Dec 23, 2024
1 parent 1a50863 commit a062e8a
Show file tree
Hide file tree
Showing 7 changed files with 1,455 additions and 4,927 deletions.
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,36 @@
"author": "",
"license": "ISC",
"dependencies": {
"@a-type/utils": "^1.1.3",
"@radix-ui/react-slot": "^1.1.0",
"@react-spring/web": "^9.7.4",
"@a-type/utils": "^1.1.4",
"@radix-ui/react-slot": "^1.1.1",
"@react-spring/web": "^9.7.5",
"@use-gesture/react": "^10.3.1",
"raf": "^3.4.1",
"signia": "^0.1.5",
"signia-react": "^0.1.5",
"valtio": "^2.0.0"
"valtio": "^2.1.2"
},
"peerDependencies": {
"react": "^19",
"react-dom": "^19"
},
"devDependencies": {
"@chromatic-com/storybook": "1.9.0",
"@storybook/addon-essentials": "^8.2.9",
"@storybook/addon-interactions": "^8.2.9",
"@storybook/addon-links": "^8.2.9",
"@storybook/addon-onboarding": "^8.2.9",
"@storybook/blocks": "^8.2.9",
"@storybook/react": "^8.2.9",
"@storybook/react-vite": "^8.2.9",
"@storybook/test": "^8.2.9",
"@chromatic-com/storybook": "3.2.3",
"@storybook/addon-essentials": "^8.4.7",
"@storybook/addon-interactions": "^8.4.7",
"@storybook/addon-links": "^8.4.7",
"@storybook/addon-onboarding": "^8.4.7",
"@storybook/blocks": "^8.4.7",
"@storybook/react": "^8.4.7",
"@storybook/react-vite": "^8.4.7",
"@storybook/test": "^8.4.7",
"@types/raf": "^3.4.3",
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"clsx": "^2.1.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"storybook": "^8.2.9",
"typescript": "^5.5.4"
"storybook": "^8.4.7",
"typescript": "5.7.2"
}
}
6,254 changes: 1,388 additions & 4,866 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions src/components/Minimap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { animated, useSpring } from '@react-spring/web';
import { useGesture } from '@use-gesture/react';
import { Fragment, JSX, useEffect, useRef } from 'react';
import { react } from 'signia';
import { useObjectIds, useSurfaceEntry } from './canvas/canvasHooks.js';
import { Canvas } from '../logic/Canvas.js';
import { Viewport } from '../viewport.js';
import { useObjectIds, useSurfaceEntry } from './canvas/canvasHooks.js';
import { CanvasProvider } from './canvas/CanvasProvider.js';

const ARect = animated.rect as any;

export interface MinimapProps {
canvas: Canvas;
className?: string;
Expand Down Expand Up @@ -181,7 +183,7 @@ function MinimapViewportRect({
}, [viewport, spring]);

return (
<animated.rect
<ARect
x={x}
y={y}
width={width}
Expand Down Expand Up @@ -225,7 +227,7 @@ function MinimapLimitsRect({
}, [canvas, spring]);

return (
<animated.rect
<ARect
x={x}
y={y}
width={width}
Expand Down
6 changes: 4 additions & 2 deletions src/components/regions/BoxRegion.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { animated, useSpring } from '@react-spring/web';
import { useId, useRef } from 'react';
import { BoundsRegistryEntry } from '../../logic/BoundsRegistry.js';
import {
CanvasGestureInput,
ContainerData,
Expand All @@ -12,7 +13,8 @@ import {
GestureClaimDetail,
useClaimGesture,
} from '../gestures/useGestureState.js';
import { BoundsRegistryEntry } from '../../logic/BoundsRegistry.js';

const ARect = animated.rect as any;

export interface BoxRegionProps {
onPending?: (surfaceIds: Array<string>, info: CanvasGestureInput) => void;
Expand Down Expand Up @@ -133,7 +135,7 @@ export function BoxRegion({
);

return (
<animated.rect
<ARect
x={x}
y={y}
width={width}
Expand Down
8 changes: 5 additions & 3 deletions src/components/surface/SurfaceRoot.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { animated } from '@react-spring/web';
import {
createContext,
CSSProperties,
Expand All @@ -16,7 +17,8 @@ import { ContainerPortal } from '../container/ContainerPortal.js';
import { CONTAINER_STATE } from './private.js';
import { useLiveElementPosition } from './signalHooks.js';
import { CanvasSurface } from './useCreateSurface.js';
import { animated } from '@react-spring/web';

const ADiv = animated.div as any;

export interface SurfaceRootProps extends HTMLAttributes<HTMLDivElement> {
surface: CanvasSurface<any>;
Expand Down Expand Up @@ -77,7 +79,7 @@ export const SurfaceRoot = function SurfaceRoot({
return (
<ContainerPortal containerId={parent}>
<SurfaceContext.Provider value={value}>
<animated.div
<ADiv
ref={finalRef}
style={{
...style,
Expand All @@ -99,7 +101,7 @@ export const SurfaceRoot = function SurfaceRoot({
{children}
</div>
}
</animated.div>
</ADiv>
</SurfaceContext.Provider>
</ContainerPortal>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/viewport/viewportInternals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function noop() {}

export function useViewportGestureControls(
viewport: Viewport,
ref: RefObject<HTMLElement>,
ref: RefObject<HTMLElement | null>,
handleCursorMove?: (pos: Vector2, active: boolean) => void,
) {
const initialZoom = viewport.config.defaultZoom;
Expand Down
74 changes: 37 additions & 37 deletions src/logic/rerasterizeSignal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,42 @@ export const rerasterizeSignal = new EventTarget();
// parent layer (will-change: initial). If true, it defaults to its own compositing
// layer (will-change: transform). The rerasterize just flips on and off.
export function useRerasterize(
ref: RefObject<HTMLElement | SVGElement>,
defaultToOwnLayer = true,
ref: RefObject<HTMLElement | SVGElement | null>,
defaultToOwnLayer = true,
) {
useEffect(() => {
/**
* Dirty trick ahead - literally!
* This function forces an invalidation of the rasterized layer for
* this draggable (hence the 'dirty' joke, get it?). It does that by toggling
* off will-change: transform for one frame, then toggling it back on again. This
* effectively 'flattens' the layer which is created for this specific item back into
* the canvas (will-change: initial), then recreates the layer again (will-change: transform).
* Doing so re-rasterizes the layer at the current scale level, so that even 2x images and text
* are re-sharpened.
*
* We need this trick because just applying `will-change: transform` all the time doesn't seem
* to properly re-rasterize when the scale changes, leading to blurriness. By manually invalidating
* the layer (read: not just invalidating but trashing and re-creating - this could be less than
* desirable) we can choose to re-sharpen the contents after the user has changed the zoom of the
* viewport, which is the most logical and only necessary time to do it.
*
* TODO: if we need to optimize this even further, we could avoid re-rasterizing widgets which are
* currently offscreen!
*/
function rerasterize() {
requestAnimationFrame(() => {
if (!ref.current) return;
const el = ref.current;
el.style.willChange = defaultToOwnLayer ? 'initial' : 'transform';
requestAnimationFrame(() => {
el.style.willChange = defaultToOwnLayer ? 'transform' : 'initial';
});
});
}
rerasterizeSignal.addEventListener('rerasterize', rerasterize);
return () => {
rerasterizeSignal.removeEventListener('rerasterize', rerasterize);
};
}, [ref]);
useEffect(() => {
/**
* Dirty trick ahead - literally!
* This function forces an invalidation of the rasterized layer for
* this draggable (hence the 'dirty' joke, get it?). It does that by toggling
* off will-change: transform for one frame, then toggling it back on again. This
* effectively 'flattens' the layer which is created for this specific item back into
* the canvas (will-change: initial), then recreates the layer again (will-change: transform).
* Doing so re-rasterizes the layer at the current scale level, so that even 2x images and text
* are re-sharpened.
*
* We need this trick because just applying `will-change: transform` all the time doesn't seem
* to properly re-rasterize when the scale changes, leading to blurriness. By manually invalidating
* the layer (read: not just invalidating but trashing and re-creating - this could be less than
* desirable) we can choose to re-sharpen the contents after the user has changed the zoom of the
* viewport, which is the most logical and only necessary time to do it.
*
* TODO: if we need to optimize this even further, we could avoid re-rasterizing widgets which are
* currently offscreen!
*/
function rerasterize() {
requestAnimationFrame(() => {
if (!ref.current) return;
const el = ref.current;
el.style.willChange = defaultToOwnLayer ? 'initial' : 'transform';
requestAnimationFrame(() => {
el.style.willChange = defaultToOwnLayer ? 'transform' : 'initial';
});
});
}
rerasterizeSignal.addEventListener('rerasterize', rerasterize);
return () => {
rerasterizeSignal.removeEventListener('rerasterize', rerasterize);
};
}, [ref]);
}

0 comments on commit a062e8a

Please sign in to comment.