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:
parent
a9236bcbb0
commit
9c1dc00740
10 changed files with 95 additions and 135 deletions
|
@ -84,7 +84,7 @@ export const allExamples: Example[] = [
|
|||
element: <ScrollExample />,
|
||||
},
|
||||
{
|
||||
title: 'Custom config',
|
||||
title: 'Custom shapes / tools',
|
||||
path: '/custom-config',
|
||||
element: <CustomConfigExample />,
|
||||
},
|
||||
|
|
|
@ -282,9 +282,9 @@ export const CAMERA_SLIDE_FRICTION = 0.09;
|
|||
export function canonicalizeRotation(a: number): number;
|
||||
|
||||
// @public (undocumented)
|
||||
export const Canvas: React_2.MemoExoticComponent<({ className }: {
|
||||
className?: string | undefined;
|
||||
}) => JSX.Element>;
|
||||
export function Canvas({ className }: {
|
||||
className?: string;
|
||||
}): JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export class Circle2d extends Geometry2d {
|
||||
|
@ -411,11 +411,12 @@ export const debugFlags: {
|
|||
elementRemovalLogging: DebugFlag<boolean>;
|
||||
debugSvg: DebugFlag<boolean>;
|
||||
throwToBlob: DebugFlag<boolean>;
|
||||
logMessages: DebugFlag<never[]>;
|
||||
logMessages: DebugFlag<any[]>;
|
||||
resetConnectionEveryPing: DebugFlag<boolean>;
|
||||
debugCursors: DebugFlag<boolean>;
|
||||
forceSrgb: DebugFlag<boolean>;
|
||||
debugGeometry: DebugFlag<boolean>;
|
||||
hideShapes: DebugFlag<boolean>;
|
||||
};
|
||||
|
||||
// @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;
|
||||
|
||||
// @internal (undocumented)
|
||||
export const featureFlags: {
|
||||
peopleMenu: DebugFlag<boolean>;
|
||||
highlighterTool: DebugFlag<boolean>;
|
||||
};
|
||||
export const featureFlags: Record<string, DebugFlag<boolean>>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type GapsSnapLine = {
|
||||
|
|
|
@ -213,7 +213,6 @@ input,
|
|||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--color-background);
|
||||
color: var(--color-text);
|
||||
z-index: var(--layer-canvas);
|
||||
cursor: var(--tl-cursor);
|
||||
|
@ -275,7 +274,6 @@ input,
|
|||
.tl-background {
|
||||
position: absolute;
|
||||
inset: 0px;
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
/* --------------------- Grid Layer --------------------- */
|
||||
|
|
|
@ -21,7 +21,7 @@ import { Shape } from './Shape'
|
|||
import { ShapeIndicator } from './ShapeIndicator'
|
||||
|
||||
/** @public */
|
||||
export const Canvas = track(function Canvas({ className }: { className?: string }) {
|
||||
export function Canvas({ className }: { className?: string }) {
|
||||
const editor = useEditor()
|
||||
|
||||
const { Background, SvgDefs } = useEditorComponents()
|
||||
|
@ -81,9 +81,12 @@ export const Canvas = track(function Canvas({ className }: { className?: string
|
|||
[editor]
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
rCanvas.current?.focus()
|
||||
}, [])
|
||||
const hideShapes = useValue('debug_shapes', () => debugFlags.hideShapes.value, [debugFlags])
|
||||
const debugSvg = useValue('debug_svg', () => debugFlags.debugSvg.value, [debugFlags])
|
||||
const debugGeometry = useValue('debug_geometry', () => debugFlags.debugGeometry.value, [
|
||||
debugFlags,
|
||||
])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={rCanvas}
|
||||
|
@ -107,11 +110,11 @@ export const Canvas = track(function Canvas({ className }: { className?: string
|
|||
</svg>
|
||||
<div ref={rHtmlLayer} className="tl-html-layer tl-shapes" draggable={false}>
|
||||
<SelectionBackgroundWrapper />
|
||||
<ShapesToDisplay />
|
||||
{hideShapes ? null : debugSvg ? <ShapesWithSVGs /> : <ShapesToDisplay />}
|
||||
</div>
|
||||
<div className="tl-fixed-layer tl-overlays">
|
||||
<div ref={rHtmlLayer2} className="tl-html-layer">
|
||||
{debugFlags.debugGeometry.value && <GeometryDebuggingView />}
|
||||
{debugGeometry ? <GeometryDebuggingView /> : null}
|
||||
<HandlesWrapper />
|
||||
<BrushWrapper />
|
||||
<ScribbleWrapper />
|
||||
|
@ -126,7 +129,7 @@ export const Canvas = track(function Canvas({ className }: { className?: string
|
|||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function GridWrapper() {
|
||||
const editor = useEditor()
|
||||
|
@ -278,24 +281,27 @@ function HandleWrapper({
|
|||
)
|
||||
}
|
||||
|
||||
const ShapesToDisplay = track(function ShapesToDisplay() {
|
||||
function ShapesWithSVGs() {
|
||||
const editor = useEditor()
|
||||
|
||||
const { renderingShapes } = editor
|
||||
const renderingShapes = useValue('rendering shapes', () => editor.renderingShapes, [editor])
|
||||
|
||||
const debugSvg = debugFlags.debugSvg.value
|
||||
if (debugSvg) {
|
||||
return (
|
||||
<>
|
||||
{renderingShapes.map((result) => (
|
||||
<React.Fragment key={result.id + '_fragment'}>
|
||||
<Shape {...result} />
|
||||
<DebugSvgCopy id={result.id} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{renderingShapes.map((result) => (
|
||||
<React.Fragment key={result.id + '_fragment'}>
|
||||
<Shape {...result} />
|
||||
<DebugSvgCopy id={result.id} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ShapesToDisplay() {
|
||||
const editor = useEditor()
|
||||
|
||||
const renderingShapes = useValue('rendering shapes', () => editor.renderingShapes, [editor])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -304,7 +310,7 @@ const ShapesToDisplay = track(function ShapesToDisplay() {
|
|||
))}
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function SelectedIdIndicators() {
|
||||
const editor = useEditor()
|
||||
|
@ -455,12 +461,14 @@ const DebugSvgCopy = track(function DupSvg({ id }: { id: TLShapeId }) {
|
|||
)
|
||||
})
|
||||
|
||||
const UiLogger = track(() => {
|
||||
const logMessages = debugFlags.logMessages.value
|
||||
function UiLogger() {
|
||||
const uiLog = useValue('debugging ui log', () => debugFlags.logMessages.value, [debugFlags])
|
||||
|
||||
if (!uiLog.length) return null
|
||||
|
||||
return (
|
||||
<div className="debug__ui-logger">
|
||||
{logMessages.map((message, messageIndex) => {
|
||||
{uiLog.map((message, messageIndex) => {
|
||||
const text = typeof message === 'string' ? message : JSON.stringify(message)
|
||||
|
||||
return (
|
||||
|
@ -471,7 +479,7 @@ const UiLogger = track(() => {
|
|||
})}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function SelectionForegroundWrapper() {
|
||||
const editor = useEditor()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { track } from '@tldraw/state'
|
||||
import { modulate } from '@tldraw/utils'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { HIT_TEST_MARGIN } from '../constants'
|
||||
import { useEditor } from '../hooks/useEditor'
|
||||
|
||||
function useTick(isEnabled = true) {
|
||||
|
@ -27,6 +26,7 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
|
|||
showClosestPointOnOutline?: boolean
|
||||
}) {
|
||||
const editor = useEditor()
|
||||
|
||||
useTick(showClosestPointOnOutline)
|
||||
|
||||
const {
|
||||
|
@ -56,18 +56,25 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
|
|||
|
||||
const pointInShapeSpace = editor.getPointInShapeSpace(shape, currentPagePoint)
|
||||
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
|
||||
|
||||
return (
|
||||
<g key={result.id + '_outline'} transform={pageTransform.toCssString()}>
|
||||
<g
|
||||
key={result.id + '_outline'}
|
||||
transform={pageTransform.toCssString()}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
{showStroke && (
|
||||
<path
|
||||
stroke="red"
|
||||
strokeWidth={2}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
opacity={0.5}
|
||||
opacity="1"
|
||||
d={geometry.toSimpleSvgPath()}
|
||||
/>
|
||||
)}
|
||||
|
@ -77,20 +84,21 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
|
|||
key={`v${i}`}
|
||||
cx={v.x}
|
||||
cy={v.y}
|
||||
r={2}
|
||||
fill={`hsl(${modulate(i, [0, vertices.length - 1], [120, 0])}, 100%, 50%)`}
|
||||
r="2"
|
||||
fill={`hsl(${modulate(i, [0, vertices.length - 1], [120, 200])}, 100%, 50%)`}
|
||||
stroke="black"
|
||||
strokeWidth="1"
|
||||
/>
|
||||
))}
|
||||
{distanceToPoint > 0 && showClosestPointOnOutline && (
|
||||
{showClosestPointOnOutline && dist < 150 && (
|
||||
<line
|
||||
x1={nearestPointOnShape.x}
|
||||
y1={nearestPointOnShape.y}
|
||||
x2={pointInShapeSpace.x}
|
||||
y2={pointInShapeSpace.y}
|
||||
strokeWidth={2}
|
||||
stroke={distanceToPoint < HIT_TEST_MARGIN / zoomLevel ? 'red' : 'pink'}
|
||||
opacity={1 - dist / 150}
|
||||
stroke={hitInside ? 'goldenrod' : 'dodgerblue'}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
)}
|
||||
</g>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import { createContext, useContext, useMemo } from 'react'
|
||||
import { ShapeIndicator, TLShapeIndicatorComponent } from '../components/ShapeIndicator'
|
||||
import {
|
||||
DefaultBackground,
|
||||
TLBackgroundComponent,
|
||||
} from '../components/default-components/DefaultBackground'
|
||||
import { TLBackgroundComponent } from '../components/default-components/DefaultBackground'
|
||||
import { DefaultBrush, TLBrushComponent } from '../components/default-components/DefaultBrush'
|
||||
import {
|
||||
DefaultCollaboratorHint,
|
||||
|
@ -91,7 +88,7 @@ export function EditorComponentsProvider({ overrides, children }: ComponentsCont
|
|||
<EditorComponentsContext.Provider
|
||||
value={useMemo(
|
||||
() => ({
|
||||
Background: DefaultBackground,
|
||||
Background: null,
|
||||
SvgDefs: DefaultSvgDefs,
|
||||
Brush: DefaultBrush,
|
||||
ZoomBrush: DefaultBrush,
|
||||
|
|
|
@ -7,12 +7,10 @@ import { Atom, atom, react } from '@tldraw/state'
|
|||
// development. Use `createFeatureFlag` to create a boolean flag which will be
|
||||
// `true` by default in development and staging, and `false` in production.
|
||||
/** @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
|
||||
// wanted an example :(
|
||||
peopleMenu: createFeatureFlag('peopleMenu'),
|
||||
highlighterTool: createFeatureFlag('highlighterTool', { all: true }),
|
||||
} satisfies Record<string, DebugFlag<boolean>>
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const debugFlags = {
|
||||
|
@ -44,7 +42,7 @@ export const debugFlags = {
|
|||
throwToBlob: createDebugValue('throwToBlob', {
|
||||
defaults: { all: false },
|
||||
}),
|
||||
logMessages: createDebugValue('uiLog', { defaults: { all: [] } }),
|
||||
logMessages: createDebugValue('uiLog', { defaults: { all: [] as any[] } }),
|
||||
resetConnectionEveryPing: createDebugValue('resetConnectionEveryPing', {
|
||||
defaults: { all: false },
|
||||
}),
|
||||
|
@ -53,6 +51,7 @@ export const debugFlags = {
|
|||
}),
|
||||
forceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),
|
||||
debugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }),
|
||||
hideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -109,16 +108,17 @@ function createDebugValue<T>(
|
|||
shouldStoreForSession,
|
||||
})
|
||||
}
|
||||
function createFeatureFlag(
|
||||
name: string,
|
||||
defaults: Defaults<boolean> = { all: true, production: false }
|
||||
) {
|
||||
return createDebugValueBase({
|
||||
name,
|
||||
defaults,
|
||||
shouldStoreForSession: true,
|
||||
})
|
||||
}
|
||||
|
||||
// function createFeatureFlag(
|
||||
// name: string,
|
||||
// defaults: Defaults<boolean> = { all: true, production: false }
|
||||
// ) {
|
||||
// return createDebugValueBase({
|
||||
// name,
|
||||
// defaults,
|
||||
// shouldStoreForSession: true,
|
||||
// })
|
||||
// }
|
||||
|
||||
function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
|
||||
const defaultValue = getDefaultValue(def)
|
||||
|
|
|
@ -184,30 +184,7 @@ const DebugMenuContent = track(function DebugMenuContent({
|
|||
<DebugFlagToggle flag={debugFlags.debugSvg} />
|
||||
<DebugFlagToggle flag={debugFlags.forceSrgb} />
|
||||
<DebugFlagToggle flag={debugFlags.debugGeometry} />
|
||||
<DebugFlagToggle
|
||||
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)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<DebugFlagToggle flag={debugFlags.hideShapes} />
|
||||
</DropdownMenu.Group>
|
||||
<DropdownMenu.Group>
|
||||
{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({
|
||||
title = 'title',
|
||||
body = 'hello hello hello',
|
||||
|
|
|
@ -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 { TLUiToolItem, TLUiToolsContextType, useTools } from './useTools'
|
||||
|
||||
|
@ -41,7 +41,6 @@ export function ToolbarSchemaProvider({ overrides, children }: TLUiToolbarSchema
|
|||
const editor = useEditor()
|
||||
|
||||
const tools = useTools()
|
||||
const highlighterEnabled = useValue(featureFlags.highlighterTool)
|
||||
|
||||
const toolbarSchema = React.useMemo<TLUiToolbarSchemaContextType>(() => {
|
||||
const schema: TLUiToolbarSchemaContextType = compact([
|
||||
|
@ -72,7 +71,7 @@ export function ToolbarSchemaProvider({ overrides, children }: TLUiToolbarSchema
|
|||
toolbarItem(tools['arrow-right']),
|
||||
toolbarItem(tools.frame),
|
||||
toolbarItem(tools.line),
|
||||
highlighterEnabled ? toolbarItem(tools.highlight) : null,
|
||||
toolbarItem(tools.highlight),
|
||||
toolbarItem(tools.laser),
|
||||
])
|
||||
|
||||
|
@ -81,7 +80,7 @@ export function ToolbarSchemaProvider({ overrides, children }: TLUiToolbarSchema
|
|||
}
|
||||
|
||||
return schema
|
||||
}, [editor, highlighterEnabled, overrides, tools])
|
||||
}, [editor, overrides, tools])
|
||||
|
||||
return (
|
||||
<ToolbarSchemaContext.Provider value={toolbarSchema}>{children}</ToolbarSchemaContext.Provider>
|
||||
|
|
|
@ -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 { EmbedDialog } from '../components/EmbedDialog'
|
||||
import { TLUiIconType } from '../icon-types'
|
||||
|
@ -45,8 +45,6 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
|
|||
const { addDialog } = useDialogs()
|
||||
const insertMedia = useInsertMedia()
|
||||
|
||||
const highlighterEnabled = useValue(featureFlags.highlighterTool)
|
||||
|
||||
const tools = React.useMemo<TLUiToolsContextType>(() => {
|
||||
const toolsArray: TLUiToolItem[] = [
|
||||
{
|
||||
|
@ -207,20 +205,18 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
|
|||
},
|
||||
]
|
||||
|
||||
if (highlighterEnabled) {
|
||||
toolsArray.push({
|
||||
id: 'highlight',
|
||||
label: 'tool.highlight',
|
||||
readonlyOk: true,
|
||||
icon: 'tool-highlight',
|
||||
// TODO: pick a better shortcut
|
||||
kbd: '!d',
|
||||
onSelect(source) {
|
||||
editor.setCurrentTool('highlight')
|
||||
trackEvent('select-tool', { source, id: 'highlight' })
|
||||
},
|
||||
})
|
||||
}
|
||||
toolsArray.push({
|
||||
id: 'highlight',
|
||||
label: 'tool.highlight',
|
||||
readonlyOk: true,
|
||||
icon: 'tool-highlight',
|
||||
// TODO: pick a better shortcut
|
||||
kbd: '!d',
|
||||
onSelect(source) {
|
||||
editor.setCurrentTool('highlight')
|
||||
trackEvent('select-tool', { source, id: 'highlight' })
|
||||
},
|
||||
})
|
||||
|
||||
const tools = Object.fromEntries(toolsArray.map((t) => [t.id, t]))
|
||||
|
||||
|
@ -229,7 +225,7 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
|
|||
}
|
||||
|
||||
return tools
|
||||
}, [highlighterEnabled, overrides, editor, trackEvent, insertMedia, addDialog])
|
||||
}, [overrides, editor, trackEvent, insertMedia, addDialog])
|
||||
|
||||
return <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider>
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue