Debugging cleanup / misc cleanup (#2025)

This PR:
- removes feature flags for people menu, highlighter shape
- removes debugging for cursors
- adds a debug flag for hiding shapes
- changes Canvas to use `useValue` rather than `track`
- removes the default background color on `tl-background`
- in the editor components, makes `Background` null by default

### Change Type

- [x] `minor` — New feature
This commit is contained in:
Steve Ruiz 2023-10-06 09:57:46 +01:00 committed by GitHub
parent a9236bcbb0
commit 9c1dc00740
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 95 additions and 135 deletions

View file

@ -84,7 +84,7 @@ export const allExamples: Example[] = [
element: <ScrollExample />, element: <ScrollExample />,
}, },
{ {
title: 'Custom config', title: 'Custom shapes / tools',
path: '/custom-config', path: '/custom-config',
element: <CustomConfigExample />, element: <CustomConfigExample />,
}, },

View file

@ -282,9 +282,9 @@ export const CAMERA_SLIDE_FRICTION = 0.09;
export function canonicalizeRotation(a: number): number; export function canonicalizeRotation(a: number): number;
// @public (undocumented) // @public (undocumented)
export const Canvas: React_2.MemoExoticComponent<({ className }: { export function Canvas({ className }: {
className?: string | undefined; className?: string;
}) => JSX.Element>; }): JSX.Element;
// @public (undocumented) // @public (undocumented)
export class Circle2d extends Geometry2d { export class Circle2d extends Geometry2d {
@ -411,11 +411,12 @@ export const debugFlags: {
elementRemovalLogging: DebugFlag<boolean>; elementRemovalLogging: DebugFlag<boolean>;
debugSvg: DebugFlag<boolean>; debugSvg: DebugFlag<boolean>;
throwToBlob: DebugFlag<boolean>; throwToBlob: DebugFlag<boolean>;
logMessages: DebugFlag<never[]>; logMessages: DebugFlag<any[]>;
resetConnectionEveryPing: DebugFlag<boolean>; resetConnectionEveryPing: DebugFlag<boolean>;
debugCursors: DebugFlag<boolean>; debugCursors: DebugFlag<boolean>;
forceSrgb: DebugFlag<boolean>; forceSrgb: DebugFlag<boolean>;
debugGeometry: DebugFlag<boolean>; debugGeometry: DebugFlag<boolean>;
hideShapes: DebugFlag<boolean>;
}; };
// @internal (undocumented) // @internal (undocumented)
@ -955,10 +956,7 @@ export const EVENT_NAME_MAP: Record<Exclude<TLEventName, TLPinchEventName>, keyo
export function extractSessionStateFromLegacySnapshot(store: Record<string, UnknownRecord>): null | TLSessionStateSnapshot; export function extractSessionStateFromLegacySnapshot(store: Record<string, UnknownRecord>): null | TLSessionStateSnapshot;
// @internal (undocumented) // @internal (undocumented)
export const featureFlags: { export const featureFlags: Record<string, DebugFlag<boolean>>;
peopleMenu: DebugFlag<boolean>;
highlighterTool: DebugFlag<boolean>;
};
// @public (undocumented) // @public (undocumented)
export type GapsSnapLine = { export type GapsSnapLine = {

View file

@ -213,7 +213,6 @@ input,
left: 0px; left: 0px;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: var(--color-background);
color: var(--color-text); color: var(--color-text);
z-index: var(--layer-canvas); z-index: var(--layer-canvas);
cursor: var(--tl-cursor); cursor: var(--tl-cursor);
@ -275,7 +274,6 @@ input,
.tl-background { .tl-background {
position: absolute; position: absolute;
inset: 0px; inset: 0px;
background-color: var(--color-background);
} }
/* --------------------- Grid Layer --------------------- */ /* --------------------- Grid Layer --------------------- */

View file

@ -21,7 +21,7 @@ import { Shape } from './Shape'
import { ShapeIndicator } from './ShapeIndicator' import { ShapeIndicator } from './ShapeIndicator'
/** @public */ /** @public */
export const Canvas = track(function Canvas({ className }: { className?: string }) { export function Canvas({ className }: { className?: string }) {
const editor = useEditor() const editor = useEditor()
const { Background, SvgDefs } = useEditorComponents() const { Background, SvgDefs } = useEditorComponents()
@ -81,9 +81,12 @@ export const Canvas = track(function Canvas({ className }: { className?: string
[editor] [editor]
) )
React.useEffect(() => { const hideShapes = useValue('debug_shapes', () => debugFlags.hideShapes.value, [debugFlags])
rCanvas.current?.focus() const debugSvg = useValue('debug_svg', () => debugFlags.debugSvg.value, [debugFlags])
}, []) const debugGeometry = useValue('debug_geometry', () => debugFlags.debugGeometry.value, [
debugFlags,
])
return ( return (
<div <div
ref={rCanvas} ref={rCanvas}
@ -107,11 +110,11 @@ export const Canvas = track(function Canvas({ className }: { className?: string
</svg> </svg>
<div ref={rHtmlLayer} className="tl-html-layer tl-shapes" draggable={false}> <div ref={rHtmlLayer} className="tl-html-layer tl-shapes" draggable={false}>
<SelectionBackgroundWrapper /> <SelectionBackgroundWrapper />
<ShapesToDisplay /> {hideShapes ? null : debugSvg ? <ShapesWithSVGs /> : <ShapesToDisplay />}
</div> </div>
<div className="tl-fixed-layer tl-overlays"> <div className="tl-fixed-layer tl-overlays">
<div ref={rHtmlLayer2} className="tl-html-layer"> <div ref={rHtmlLayer2} className="tl-html-layer">
{debugFlags.debugGeometry.value && <GeometryDebuggingView />} {debugGeometry ? <GeometryDebuggingView /> : null}
<HandlesWrapper /> <HandlesWrapper />
<BrushWrapper /> <BrushWrapper />
<ScribbleWrapper /> <ScribbleWrapper />
@ -126,7 +129,7 @@ export const Canvas = track(function Canvas({ className }: { className?: string
</div> </div>
</div> </div>
) )
}) }
function GridWrapper() { function GridWrapper() {
const editor = useEditor() const editor = useEditor()
@ -278,13 +281,11 @@ function HandleWrapper({
) )
} }
const ShapesToDisplay = track(function ShapesToDisplay() { function ShapesWithSVGs() {
const editor = useEditor() const editor = useEditor()
const { renderingShapes } = editor const renderingShapes = useValue('rendering shapes', () => editor.renderingShapes, [editor])
const debugSvg = debugFlags.debugSvg.value
if (debugSvg) {
return ( return (
<> <>
{renderingShapes.map((result) => ( {renderingShapes.map((result) => (
@ -295,7 +296,12 @@ const ShapesToDisplay = track(function ShapesToDisplay() {
))} ))}
</> </>
) )
} }
function ShapesToDisplay() {
const editor = useEditor()
const renderingShapes = useValue('rendering shapes', () => editor.renderingShapes, [editor])
return ( return (
<> <>
@ -304,7 +310,7 @@ const ShapesToDisplay = track(function ShapesToDisplay() {
))} ))}
</> </>
) )
}) }
function SelectedIdIndicators() { function SelectedIdIndicators() {
const editor = useEditor() const editor = useEditor()
@ -455,12 +461,14 @@ const DebugSvgCopy = track(function DupSvg({ id }: { id: TLShapeId }) {
) )
}) })
const UiLogger = track(() => { function UiLogger() {
const logMessages = debugFlags.logMessages.value const uiLog = useValue('debugging ui log', () => debugFlags.logMessages.value, [debugFlags])
if (!uiLog.length) return null
return ( return (
<div className="debug__ui-logger"> <div className="debug__ui-logger">
{logMessages.map((message, messageIndex) => { {uiLog.map((message, messageIndex) => {
const text = typeof message === 'string' ? message : JSON.stringify(message) const text = typeof message === 'string' ? message : JSON.stringify(message)
return ( return (
@ -471,7 +479,7 @@ const UiLogger = track(() => {
})} })}
</div> </div>
) )
}) }
export function SelectionForegroundWrapper() { export function SelectionForegroundWrapper() {
const editor = useEditor() const editor = useEditor()

View file

@ -1,7 +1,6 @@
import { track } from '@tldraw/state' import { track } from '@tldraw/state'
import { modulate } from '@tldraw/utils' import { modulate } from '@tldraw/utils'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { HIT_TEST_MARGIN } from '../constants'
import { useEditor } from '../hooks/useEditor' import { useEditor } from '../hooks/useEditor'
function useTick(isEnabled = true) { function useTick(isEnabled = true) {
@ -27,6 +26,7 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
showClosestPointOnOutline?: boolean showClosestPointOnOutline?: boolean
}) { }) {
const editor = useEditor() const editor = useEditor()
useTick(showClosestPointOnOutline) useTick(showClosestPointOnOutline)
const { const {
@ -56,18 +56,25 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
const pointInShapeSpace = editor.getPointInShapeSpace(shape, currentPagePoint) const pointInShapeSpace = editor.getPointInShapeSpace(shape, currentPagePoint)
const nearestPointOnShape = geometry.nearestPoint(pointInShapeSpace) const nearestPointOnShape = geometry.nearestPoint(pointInShapeSpace)
const distanceToPoint = geometry.distanceToPoint(pointInShapeSpace) const distanceToPoint = geometry.distanceToPoint(pointInShapeSpace, true)
const dist = Math.abs(distanceToPoint) * zoomLevel
const hitInside = distanceToPoint < 0
const { vertices } = geometry const { vertices } = geometry
return ( return (
<g key={result.id + '_outline'} transform={pageTransform.toCssString()}> <g
key={result.id + '_outline'}
transform={pageTransform.toCssString()}
strokeLinecap="round"
strokeLinejoin="round"
>
{showStroke && ( {showStroke && (
<path <path
stroke="red" stroke="red"
strokeWidth={2} strokeWidth="2"
fill="none" fill="none"
opacity={0.5} opacity="1"
d={geometry.toSimpleSvgPath()} d={geometry.toSimpleSvgPath()}
/> />
)} )}
@ -77,20 +84,21 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
key={`v${i}`} key={`v${i}`}
cx={v.x} cx={v.x}
cy={v.y} cy={v.y}
r={2} r="2"
fill={`hsl(${modulate(i, [0, vertices.length - 1], [120, 0])}, 100%, 50%)`} fill={`hsl(${modulate(i, [0, vertices.length - 1], [120, 200])}, 100%, 50%)`}
stroke="black" stroke="black"
strokeWidth="1" strokeWidth="1"
/> />
))} ))}
{distanceToPoint > 0 && showClosestPointOnOutline && ( {showClosestPointOnOutline && dist < 150 && (
<line <line
x1={nearestPointOnShape.x} x1={nearestPointOnShape.x}
y1={nearestPointOnShape.y} y1={nearestPointOnShape.y}
x2={pointInShapeSpace.x} x2={pointInShapeSpace.x}
y2={pointInShapeSpace.y} y2={pointInShapeSpace.y}
strokeWidth={2} opacity={1 - dist / 150}
stroke={distanceToPoint < HIT_TEST_MARGIN / zoomLevel ? 'red' : 'pink'} stroke={hitInside ? 'goldenrod' : 'dodgerblue'}
strokeWidth="2"
/> />
)} )}
</g> </g>

View file

@ -1,9 +1,6 @@
import { createContext, useContext, useMemo } from 'react' import { createContext, useContext, useMemo } from 'react'
import { ShapeIndicator, TLShapeIndicatorComponent } from '../components/ShapeIndicator' import { ShapeIndicator, TLShapeIndicatorComponent } from '../components/ShapeIndicator'
import { import { TLBackgroundComponent } from '../components/default-components/DefaultBackground'
DefaultBackground,
TLBackgroundComponent,
} from '../components/default-components/DefaultBackground'
import { DefaultBrush, TLBrushComponent } from '../components/default-components/DefaultBrush' import { DefaultBrush, TLBrushComponent } from '../components/default-components/DefaultBrush'
import { import {
DefaultCollaboratorHint, DefaultCollaboratorHint,
@ -91,7 +88,7 @@ export function EditorComponentsProvider({ overrides, children }: ComponentsCont
<EditorComponentsContext.Provider <EditorComponentsContext.Provider
value={useMemo( value={useMemo(
() => ({ () => ({
Background: DefaultBackground, Background: null,
SvgDefs: DefaultSvgDefs, SvgDefs: DefaultSvgDefs,
Brush: DefaultBrush, Brush: DefaultBrush,
ZoomBrush: DefaultBrush, ZoomBrush: DefaultBrush,

View file

@ -7,12 +7,10 @@ import { Atom, atom, react } from '@tldraw/state'
// development. Use `createFeatureFlag` to create a boolean flag which will be // development. Use `createFeatureFlag` to create a boolean flag which will be
// `true` by default in development and staging, and `false` in production. // `true` by default in development and staging, and `false` in production.
/** @internal */ /** @internal */
export const featureFlags = { export const featureFlags: Record<string, DebugFlag<boolean>> = {
// todo: remove this. it's not used, but we only have one feature flag and i // todo: remove this. it's not used, but we only have one feature flag and i
// wanted an example :( // wanted an example :(
peopleMenu: createFeatureFlag('peopleMenu'), }
highlighterTool: createFeatureFlag('highlighterTool', { all: true }),
} satisfies Record<string, DebugFlag<boolean>>
/** @internal */ /** @internal */
export const debugFlags = { export const debugFlags = {
@ -44,7 +42,7 @@ export const debugFlags = {
throwToBlob: createDebugValue('throwToBlob', { throwToBlob: createDebugValue('throwToBlob', {
defaults: { all: false }, defaults: { all: false },
}), }),
logMessages: createDebugValue('uiLog', { defaults: { all: [] } }), logMessages: createDebugValue('uiLog', { defaults: { all: [] as any[] } }),
resetConnectionEveryPing: createDebugValue('resetConnectionEveryPing', { resetConnectionEveryPing: createDebugValue('resetConnectionEveryPing', {
defaults: { all: false }, defaults: { all: false },
}), }),
@ -53,6 +51,7 @@ export const debugFlags = {
}), }),
forceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }), forceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),
debugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }), debugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }),
hideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),
} }
declare global { declare global {
@ -109,16 +108,17 @@ function createDebugValue<T>(
shouldStoreForSession, shouldStoreForSession,
}) })
} }
function createFeatureFlag(
name: string, // function createFeatureFlag(
defaults: Defaults<boolean> = { all: true, production: false } // name: string,
) { // defaults: Defaults<boolean> = { all: true, production: false }
return createDebugValueBase({ // ) {
name, // return createDebugValueBase({
defaults, // name,
shouldStoreForSession: true, // defaults,
}) // shouldStoreForSession: true,
} // })
// }
function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> { function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
const defaultValue = getDefaultValue(def) const defaultValue = getDefaultValue(def)

View file

@ -184,30 +184,7 @@ const DebugMenuContent = track(function DebugMenuContent({
<DebugFlagToggle flag={debugFlags.debugSvg} /> <DebugFlagToggle flag={debugFlags.debugSvg} />
<DebugFlagToggle flag={debugFlags.forceSrgb} /> <DebugFlagToggle flag={debugFlags.forceSrgb} />
<DebugFlagToggle flag={debugFlags.debugGeometry} /> <DebugFlagToggle flag={debugFlags.debugGeometry} />
<DebugFlagToggle <DebugFlagToggle flag={debugFlags.hideShapes} />
flag={debugFlags.debugCursors}
onChange={(enabled) => {
if (enabled) {
const MAX_COLUMNS = 5
const partials = CURSOR_NAMES.map((name, i) => {
return {
id: createShapeId(),
type: 'geo',
x: (i % MAX_COLUMNS) * 175,
y: Math.floor(i / MAX_COLUMNS) * 175,
props: {
text: name,
w: 150,
h: 150,
fill: 'semi',
},
}
})
editor.createShapes(partials)
}
}}
/>
</DropdownMenu.Group> </DropdownMenu.Group>
<DropdownMenu.Group> <DropdownMenu.Group>
{Object.values(featureFlags).map((flag) => { {Object.values(featureFlags).map((flag) => {
@ -256,27 +233,6 @@ const DebugFlagToggle = track(function DebugFlagToggle({
) )
}) })
const CURSOR_NAMES = [
'none',
'default',
'pointer',
'cross',
'move',
'grab',
'grabbing',
'text',
'ew-resize',
'ns-resize',
'nesw-resize',
'nwse-resize',
'nwse-rotate',
'nesw-rotate',
'senw-rotate',
'swne-rotate',
'zoom-in',
'zoom-out',
]
function ExampleDialog({ function ExampleDialog({
title = 'title', title = 'title',
body = 'hello hello hello', body = 'hello hello hello',

View file

@ -1,4 +1,4 @@
import { Editor, compact, featureFlags, useEditor, useValue } from '@tldraw/editor' import { Editor, compact, useEditor } from '@tldraw/editor'
import React from 'react' import React from 'react'
import { TLUiToolItem, TLUiToolsContextType, useTools } from './useTools' import { TLUiToolItem, TLUiToolsContextType, useTools } from './useTools'
@ -41,7 +41,6 @@ export function ToolbarSchemaProvider({ overrides, children }: TLUiToolbarSchema
const editor = useEditor() const editor = useEditor()
const tools = useTools() const tools = useTools()
const highlighterEnabled = useValue(featureFlags.highlighterTool)
const toolbarSchema = React.useMemo<TLUiToolbarSchemaContextType>(() => { const toolbarSchema = React.useMemo<TLUiToolbarSchemaContextType>(() => {
const schema: TLUiToolbarSchemaContextType = compact([ const schema: TLUiToolbarSchemaContextType = compact([
@ -72,7 +71,7 @@ export function ToolbarSchemaProvider({ overrides, children }: TLUiToolbarSchema
toolbarItem(tools['arrow-right']), toolbarItem(tools['arrow-right']),
toolbarItem(tools.frame), toolbarItem(tools.frame),
toolbarItem(tools.line), toolbarItem(tools.line),
highlighterEnabled ? toolbarItem(tools.highlight) : null, toolbarItem(tools.highlight),
toolbarItem(tools.laser), toolbarItem(tools.laser),
]) ])
@ -81,7 +80,7 @@ export function ToolbarSchemaProvider({ overrides, children }: TLUiToolbarSchema
} }
return schema return schema
}, [editor, highlighterEnabled, overrides, tools]) }, [editor, overrides, tools])
return ( return (
<ToolbarSchemaContext.Provider value={toolbarSchema}>{children}</ToolbarSchemaContext.Provider> <ToolbarSchemaContext.Provider value={toolbarSchema}>{children}</ToolbarSchemaContext.Provider>

View file

@ -1,4 +1,4 @@
import { Editor, GeoShapeGeoStyle, featureFlags, useEditor, useValue } from '@tldraw/editor' import { Editor, GeoShapeGeoStyle, useEditor } from '@tldraw/editor'
import * as React from 'react' import * as React from 'react'
import { EmbedDialog } from '../components/EmbedDialog' import { EmbedDialog } from '../components/EmbedDialog'
import { TLUiIconType } from '../icon-types' import { TLUiIconType } from '../icon-types'
@ -45,8 +45,6 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
const { addDialog } = useDialogs() const { addDialog } = useDialogs()
const insertMedia = useInsertMedia() const insertMedia = useInsertMedia()
const highlighterEnabled = useValue(featureFlags.highlighterTool)
const tools = React.useMemo<TLUiToolsContextType>(() => { const tools = React.useMemo<TLUiToolsContextType>(() => {
const toolsArray: TLUiToolItem[] = [ const toolsArray: TLUiToolItem[] = [
{ {
@ -207,7 +205,6 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
}, },
] ]
if (highlighterEnabled) {
toolsArray.push({ toolsArray.push({
id: 'highlight', id: 'highlight',
label: 'tool.highlight', label: 'tool.highlight',
@ -220,7 +217,6 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
trackEvent('select-tool', { source, id: 'highlight' }) trackEvent('select-tool', { source, id: 'highlight' })
}, },
}) })
}
const tools = Object.fromEntries(toolsArray.map((t) => [t.id, t])) const tools = Object.fromEntries(toolsArray.map((t) => [t.id, t]))
@ -229,7 +225,7 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
} }
return tools return tools
}, [highlighterEnabled, overrides, editor, trackEvent, insertMedia, addDialog]) }, [overrides, editor, trackEvent, insertMedia, addDialog])
return <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider> return <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider>
} }