import { App, DebugFlag, debugFlags, featureFlags, hardResetApp, TLShapePartial, uniqueId, useApp, } from '@tldraw/editor' import * as React from 'react' import { track, useValue } from 'signia-react' import { useDialogs } from '../hooks/useDialogsProvider' import { useToasts } from '../hooks/useToastsProvider' import { useTranslation } from '../hooks/useTranslation/useTranslation' import { Button } from './primitives/Button' import * as Dialog from './primitives/Dialog' import * as DropdownMenu from './primitives/DropdownMenu' let t = 0 function createNShapes(app: App, n: number) { const shapesToCreate: TLShapePartial[] = Array(n) const cols = Math.floor(Math.sqrt(n)) for (let i = 0; i < n; i++) { t++ shapesToCreate[i] = { id: app.createShapeId('box' + t), type: 'geo', x: (i % cols) * 132, y: Math.floor(i / cols) * 132, } } app.batch(() => { app.createShapes(shapesToCreate).setSelectedIds(shapesToCreate.map((s) => s.id)) }) } /** @public */ export const DebugPanel = React.memo(function DebugPanel({ renderDebugMenuItems, }: { renderDebugMenuItems: (() => React.ReactNode) | null }) { const msg = useTranslation() return (
) }) const CurrentState = track(function CurrentState() { const app = useApp() return
{app.root.path.value}
}) const ShapeCount = function ShapeCount() { const app = useApp() const count = useValue('rendering shapes count', () => app.renderingShapes.length, [app]) return
{count} Shapes
} const DebugMenuContent = track(function DebugMenuContent({ renderDebugMenuItems, }: { renderDebugMenuItems: (() => React.ReactNode) | null }) { const app = useApp() const { addToast } = useToasts() const { addDialog } = useDialogs() const [error, setError] = React.useState(false) return ( <> { addToast({ id: uniqueId(), title: 'Something happened', description: 'Hey, attend to this thing over here. It might be important!', // icon?: string // title?: string // description?: string // actions?: TLToastAction[] }) }} > Show toast { addDialog({ component: ({ onClose }) => ( { onClose() }} onContinue={() => { onClose() }} /> ), onClose: () => { void null }, }) }} > Show dialog createNShapes(app, 100)}> Create 100 shapes { function countDescendants({ children }: HTMLElement) { let count = 0 if (!children.length) return 0 for (const el of [...(children as any)]) { count++ count += countDescendants(el) } return count } const { selectedShapes } = app const shapes = selectedShapes.length === 0 ? app.renderingShapes : selectedShapes const elms = shapes.map( (shape) => (document.getElementById(shape.id) as HTMLElement)!.parentElement! ) let descendants = elms.length for (const elm of elms) { descendants += countDescendants(elm) } window.alert(`Shapes ${shapes.length}, DOM nodes:${descendants}`) }} > Count shapes and nodes {(() => { if (error) throw Error('oh no!') })()} { setError(true) }} > Throw error { hardResetApp() }} > Hard reset app.setReadOnly(r)} /> { if (enabled) { const MAX_COLUMNS = 5 const partials = CURSOR_NAMES.map((name, i) => { return { id: app.createShapeId(), type: 'geo', x: (i % MAX_COLUMNS) * 175, y: Math.floor(i / MAX_COLUMNS) * 175, props: { text: name, w: 150, h: 150, fill: 'semi', }, } }) app.createShapes(partials) } }} /> {Object.values(featureFlags).map((flag) => { return })} {renderDebugMenuItems?.()} ) }) function Toggle({ label, value, onChange, }: { label: string value: boolean onChange: (newValue: boolean) => void }) { return ( onChange(!value)}> {label} ) } const DebugFlagToggle = track(function DebugFlagToggle({ flag, onChange, }: { flag: DebugFlag onChange?: (newValue: boolean) => void }) { return ( `${m[0]} ${m[1].toLowerCase()}`) .replace(/^[a-z]/, (m) => m.toUpperCase())} value={flag.value} onChange={(newValue) => { flag.set(newValue) onChange?.(newValue) }} /> ) }) const CURSOR_NAMES = [ 'none', 'default', 'pointer', 'cross', 'move', 'grab', 'grabbing', 'text', 'resize-edge', 'resize-corner', 'ew-resize', 'ns-resize', 'nesw-resize', 'nwse-resize', 'rotate', 'nwse-rotate', 'nesw-rotate', 'senw-rotate', 'swne-rotate', 'zoom-in', 'zoom-out', ] function ExampleDialog({ title = 'title', body = 'hello hello hello', cancel = 'Cancel', confirm = 'Continue', displayDontShowAgain = false, onCancel, onContinue, }: { title?: string body?: string cancel?: string confirm?: string displayDontShowAgain?: boolean onCancel: () => void onContinue: () => void }) { const [dontShowAgain, setDontShowAgain] = React.useState(false) return ( <> {title} {body} {displayDontShowAgain && ( )} ) }