diff --git a/app/react-components/devtools.module.css b/app/react-components/devtools.module.css index 27f57dc..a671109 100644 --- a/app/react-components/devtools.module.css +++ b/app/react-components/devtools.module.css @@ -7,7 +7,17 @@ .devtools { background-color: #444444; color: white; - max-height: 100%; - overflow-y: auto; + height: 100%; + overflow: hidden; padding: 16px; + width: 100%; } + +.devtools > :global(.react-tabs) { + display: flex; + flex-direction: column; + height: 100%; + > :global(.react-tabs__tab-panel) { + overflow-y: auto; + } +} \ No newline at end of file diff --git a/app/react-components/devtools/tiles.jsx b/app/react-components/devtools/tiles.jsx index 859b856..3cfaa7d 100644 --- a/app/react-components/devtools/tiles.jsx +++ b/app/react-components/devtools/tiles.jsx @@ -1,6 +1,7 @@ import {useRef, useState} from 'react'; import {useEcs} from '@/context/ecs.js'; +import useRect from '@/util/react-hooks/use-rect.js'; import styles from './tiles.module.css'; @@ -11,8 +12,10 @@ export default function Tiles({ setLayer, setStamp, }) { - const offsetRef = useRef(); - const [selection, setSelection] = useState({x: 0, y: 0, w: 2, h: 2}); + const wrapperRef = useRef(); + const imageRef = useRef(); + const imageRect = useRect(imageRef); + const [selection, setSelection] = useState({x: 0, y: 0, w: 1, h: 1}); const [moveStart, setMoveStart] = useState(); const [ecs] = useEcs(); if (!ecs) { @@ -25,6 +28,7 @@ export default function Tiles({ const {TileLayers} = master; const {sourceJson, tileSize} = TileLayers.layer(0); const {w, h} = sourceJson.meta.size; + const factor = (imageRect?.width ?? 1) / w; return (
@@ -57,7 +61,7 @@ export default function Tiles({ Brush:
- + {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
{ - if (!offsetRef.current) { - return; - } - const {left, top} = offsetRef.current.getBoundingClientRect(); + const wrapperRect = wrapperRef.current.getBoundingClientRect(); + const {left, top} = wrapperRect; if ( - event.clientX - left >= w - || event.clientY - top >= h + event.clientX - left >= (w * factor) + || event.clientY - top >= (h * factor) ) { return; } - const x = Math.floor((event.clientX - left) / tileSize.x); - const y = Math.floor((event.clientY - top) / tileSize.y); + const x = Math.floor((event.clientX - left) / (tileSize.x * factor)); + const y = Math.floor((event.clientY - top) / (tileSize.y * factor)); setMoveStart({x, y}); setSelection({x, y, w: 1, h: 1}); }} onMouseMove={(event) => { - if (!offsetRef.current) { - return; - } if (!moveStart) { return; } const {x: sx, y: sy} = moveStart; - const {left, top} = offsetRef.current.getBoundingClientRect(); + const wrapperRect = wrapperRef.current.getBoundingClientRect(); + const {left, top} = wrapperRect; const x = Math.floor( - Math.max(0, Math.min(w - 1, (event.clientX - left)) / tileSize.x), + Math.max(0, Math.min((w * factor) - 1, (event.clientX - left)) / (tileSize.x * factor)), ); const y = Math.floor( - Math.max(0, Math.min(h - 1, (event.clientY - top)) / tileSize.y), + Math.max(0, Math.min((h * factor) - 1, (event.clientY - top)) / (tileSize.y * factor)), ); const mx = Math.min(sx, x); const my = Math.min(sy, y); @@ -119,19 +119,20 @@ export default function Tiles({ setStamp(stamp); }} className={styles.selectionWrapper} - ref={offsetRef} + ref={wrapperRef} >
tileset
diff --git a/app/react-components/devtools/tiles.module.css b/app/react-components/devtools/tiles.module.css index 9a7db77..5ed1869 100644 --- a/app/react-components/devtools/tiles.module.css +++ b/app/react-components/devtools/tiles.module.css @@ -10,6 +10,7 @@ .selectionWrapper img { user-select: none; + width: 100%; } .selection { diff --git a/app/util/react-hooks/use-rect.js b/app/util/react-hooks/use-rect.js new file mode 100644 index 0000000..b4d5bf6 --- /dev/null +++ b/app/util/react-hooks/use-rect.js @@ -0,0 +1,16 @@ +import {useLayoutEffect, useState} from 'react' +import useResizeObserver from '@react-hook/resize-observer' + +export default function useRect(target) { + const [rect, setRect] = useState(); + useLayoutEffect(() => { + setRect(target.current.getBoundingClientRect()) + }, [target]); + useResizeObserver( + target, + (entry) => { + setRect(entry.target.getBoundingClientRect()); + }, + ); + return rect; +} diff --git a/package-lock.json b/package-lock.json index f29334b..3986b5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@pixi/react": "^7.1.2", "@pixi/spritesheet": "^7.4.2", "@pixi/tilemap": "^4.1.0", + "@react-hook/resize-observer": "^2.0.1", "@remix-run/express": "^2.9.2", "@remix-run/node": "^2.9.2", "@remix-run/react": "^2.9.2", @@ -3020,6 +3021,11 @@ "integrity": "sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==", "dev": true }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" + }, "node_modules/@leodeslf/simplex-noise": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@leodeslf/simplex-noise/-/simplex-noise-1.0.0.tgz", @@ -3971,6 +3977,35 @@ } } }, + "node_modules/@react-hook/latest": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz", + "integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@react-hook/passive-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz", + "integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@react-hook/resize-observer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@react-hook/resize-observer/-/resize-observer-2.0.1.tgz", + "integrity": "sha512-9PCX9grWfxdPizY8ohr+X4IkV1JhGMWr2Nm4ngbg6IcAIv0WBs7YoJcNBqYl22OqPHr5eOMItGcStZrmj2mbmQ==", + "dependencies": { + "@juggle/resize-observer": "^3.3.1", + "@react-hook/latest": "^1.0.2", + "@react-hook/passive-layout-effect": "^1.2.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, "node_modules/@remix-run/dev": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.9.2.tgz", diff --git a/package.json b/package.json index d0aedbe..53f4ded 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@pixi/react": "^7.1.2", "@pixi/spritesheet": "^7.4.2", "@pixi/tilemap": "^4.1.0", + "@react-hook/resize-observer": "^2.0.1", "@remix-run/express": "^2.9.2", "@remix-run/node": "^2.9.2", "@remix-run/react": "^2.9.2",