[fix] remove CSS radius calculations (#1823)
This PR fixes some creative use of CSS in setting the radius property of various SVGs. While this use is supported in all browsers, it was confusing CSS processors. Moving these out of CSS and into JavaScript seems to be a pretty minor trade. Closes https://github.com/tldraw/tldraw/issues/1775. ### Change Type - [x] `patch` — Bug fix ### Test Plan 1. Ensure that borders and handles adjust their radii correctly when zoomed in or out.
This commit is contained in:
parent
162f68b71a
commit
b203967341
6 changed files with 44 additions and 21 deletions
|
@ -2173,6 +2173,8 @@ export type TLGridComponent = ComponentType<{
|
||||||
export type TLHandleComponent = ComponentType<{
|
export type TLHandleComponent = ComponentType<{
|
||||||
shapeId: TLShapeId;
|
shapeId: TLShapeId;
|
||||||
handle: TLHandle;
|
handle: TLHandle;
|
||||||
|
zoom: number;
|
||||||
|
isCoarse: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
|
@ -478,7 +478,6 @@ input,
|
||||||
|
|
||||||
.tl-mobile-rotate__bg {
|
.tl-mobile-rotate__bg {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
r: calc(max(calc(14px * var(--tl-scale)), 20px / max(1, var(--tl-zoom))));
|
|
||||||
cursor: var(--tl-cursor-grab);
|
cursor: var(--tl-cursor-grab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,14 +504,12 @@ input,
|
||||||
stroke: transparent;
|
stroke: transparent;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
cursor: var(--tl-cursor-grabbing);
|
cursor: var(--tl-cursor-grabbing);
|
||||||
r: calc(12px / var(--tl-zoom));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-handle__fg {
|
.tl-handle__fg {
|
||||||
fill: var(--color-background);
|
fill: var(--color-background);
|
||||||
stroke: var(--color-selection-stroke);
|
stroke: var(--color-selection-stroke);
|
||||||
stroke-width: calc(1.5px * var(--tl-scale));
|
stroke-width: calc(1.5px * var(--tl-scale));
|
||||||
r: calc(4px * var(--tl-scale));
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,10 +537,6 @@ input,
|
||||||
.tl-handle__create {
|
.tl-handle__create {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-handle__create > .tl-handle__fg {
|
|
||||||
r: calc(3px * var(--tl-scale));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------ Bounds Detail ----------------- */
|
/* ------------------ Bounds Detail ----------------- */
|
||||||
|
@ -554,14 +547,16 @@ input,
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-image-container,
|
.tl-image-container,
|
||||||
|
.tl-video-container,
|
||||||
.tl-embed-container {
|
.tl-embed-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
/* background-color: var(--color-background); */
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -573,7 +568,6 @@ input,
|
||||||
top: calc(var(--scale) * 8px);
|
top: calc(var(--scale) * 8px);
|
||||||
right: calc(var(--scale) * 8px);
|
right: calc(var(--scale) * 8px);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
scale: var(--scale);
|
|
||||||
transform-origin: top right;
|
transform-origin: top right;
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
|
@ -1095,7 +1089,7 @@ input,
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-text-label[data-isediting='true'] {
|
.tl-text-label[data-isediting='true'] {
|
||||||
background-color: none;
|
background-color: transparent;
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1504,7 +1498,7 @@ it from receiving any pointer events or affecting the cursor. */
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0px;
|
inset: 0px;
|
||||||
z-index: 600;
|
z-index: 600;
|
||||||
pointer-events: auto;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-error-boundary__content {
|
.tl-error-boundary__content {
|
||||||
|
@ -1618,10 +1612,6 @@ it from receiving any pointer events or affecting the cursor. */
|
||||||
.tl-canvas__mobile .tl-handle__hint {
|
.tl-canvas__mobile .tl-handle__hint {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-canvas__mobile .tl-handle__bg {
|
|
||||||
r: calc(20px / var(--tl-zoom));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-hidden {
|
.tl-hidden {
|
||||||
|
|
|
@ -185,6 +185,7 @@ function HandlesWrapper() {
|
||||||
const { Handles } = useEditorComponents()
|
const { Handles } = useEditorComponents()
|
||||||
|
|
||||||
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor])
|
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor])
|
||||||
|
const isCoarse = useValue('coarse pointer', () => editor.instanceState.isCoarsePointer, [editor])
|
||||||
const onlySelectedShape = useValue('onlySelectedShape', () => editor.onlySelectedShape, [editor])
|
const onlySelectedShape = useValue('onlySelectedShape', () => editor.onlySelectedShape, [editor])
|
||||||
const isChangingStyle = useValue('isChangingStyle', () => editor.instanceState.isChangingStyle, [
|
const isChangingStyle = useValue('isChangingStyle', () => editor.instanceState.isChangingStyle, [
|
||||||
editor,
|
editor,
|
||||||
|
@ -229,14 +230,32 @@ function HandlesWrapper() {
|
||||||
<Handles>
|
<Handles>
|
||||||
<g transform={Matrix2d.toCssString(transform)}>
|
<g transform={Matrix2d.toCssString(transform)}>
|
||||||
{handlesToDisplay.map((handle) => {
|
{handlesToDisplay.map((handle) => {
|
||||||
return <HandleWrapper key={handle.id} shapeId={onlySelectedShape.id} handle={handle} />
|
return (
|
||||||
|
<HandleWrapper
|
||||||
|
key={handle.id}
|
||||||
|
shapeId={onlySelectedShape.id}
|
||||||
|
handle={handle}
|
||||||
|
zoom={zoomLevel}
|
||||||
|
isCoarse={isCoarse}
|
||||||
|
/>
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
</g>
|
</g>
|
||||||
</Handles>
|
</Handles>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function HandleWrapper({ shapeId, handle }: { shapeId: TLShapeId; handle: TLHandle }) {
|
function HandleWrapper({
|
||||||
|
shapeId,
|
||||||
|
handle,
|
||||||
|
zoom,
|
||||||
|
isCoarse,
|
||||||
|
}: {
|
||||||
|
shapeId: TLShapeId
|
||||||
|
handle: TLHandle
|
||||||
|
zoom: number
|
||||||
|
isCoarse: boolean
|
||||||
|
}) {
|
||||||
const events = useHandleEvents(shapeId, handle.id)
|
const events = useHandleEvents(shapeId, handle.id)
|
||||||
const { Handle } = useEditorComponents()
|
const { Handle } = useEditorComponents()
|
||||||
|
|
||||||
|
@ -244,7 +263,7 @@ function HandleWrapper({ shapeId, handle }: { shapeId: TLShapeId; handle: TLHand
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g aria-label="handle" transform={`translate(${handle.x}, ${handle.y})`} {...events}>
|
<g aria-label="handle" transform={`translate(${handle.x}, ${handle.y})`} {...events}>
|
||||||
<Handle shapeId={shapeId} handle={handle} />
|
<Handle shapeId={shapeId} handle={handle} zoom={zoom} isCoarse={isCoarse} />
|
||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,16 @@ import { ComponentType } from 'react'
|
||||||
export type TLHandleComponent = ComponentType<{
|
export type TLHandleComponent = ComponentType<{
|
||||||
shapeId: TLShapeId
|
shapeId: TLShapeId
|
||||||
handle: TLHandle
|
handle: TLHandle
|
||||||
|
zoom: number
|
||||||
|
isCoarse: boolean
|
||||||
className?: string
|
className?: string
|
||||||
}>
|
}>
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export const DefaultHandle: TLHandleComponent = ({ handle, className }) => {
|
export const DefaultHandle: TLHandleComponent = ({ handle, isCoarse, className, zoom }) => {
|
||||||
|
const bgRadius = (isCoarse ? 20 : 12) / zoom
|
||||||
|
const fgRadius = (handle.type === 'create' && isCoarse ? 3 : 4) / zoom
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g
|
<g
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -22,8 +27,8 @@ export const DefaultHandle: TLHandleComponent = ({ handle, className }) => {
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<circle className="tl-handle__bg" />
|
<circle className="tl-handle__bg" r={bgRadius} />
|
||||||
<circle className="tl-handle__fg" />
|
<circle className="tl-handle__fg" r={fgRadius} />
|
||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useEditor } from './useEditor'
|
import { useEditor } from './useEditor'
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
export function useCoarsePointer() {
|
export function useCoarsePointer() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
useEditor,
|
useEditor,
|
||||||
useSelectionEvents,
|
useSelectionEvents,
|
||||||
useTransform,
|
useTransform,
|
||||||
|
useValue,
|
||||||
} from '@tldraw/editor'
|
} from '@tldraw/editor'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
@ -500,6 +501,10 @@ export const MobileRotateHandle = function RotateHandle({
|
||||||
}) {
|
}) {
|
||||||
const events = useSelectionEvents('mobile_rotate')
|
const events = useSelectionEvents('mobile_rotate')
|
||||||
|
|
||||||
|
const editor = useEditor()
|
||||||
|
const zoom = useValue('zoom level', () => editor.zoomLevel, [editor])
|
||||||
|
const bgRadius = Math.max(14 * (1 / zoom), 20 / Math.max(1, zoom))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g>
|
<g>
|
||||||
<circle
|
<circle
|
||||||
|
@ -508,6 +513,7 @@ export const MobileRotateHandle = function RotateHandle({
|
||||||
className={classNames('tl-transparent', 'tl-mobile-rotate__bg', { 'tl-hidden': isHidden })}
|
className={classNames('tl-transparent', 'tl-mobile-rotate__bg', { 'tl-hidden': isHidden })}
|
||||||
cx={cx}
|
cx={cx}
|
||||||
cy={cy}
|
cy={cy}
|
||||||
|
r={bgRadius}
|
||||||
{...events}
|
{...events}
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue