import { DebugFlag, Editor, TLShapePartial, createShapeId, debugFlags, featureFlags, hardResetEditor, track, uniqueId, useEditor, } from '@tldraw/editor' import React from 'react' import { useDialogs } from '../../context/dialogs' import { useToasts } from '../../context/toasts' import { untranslated } from '../../hooks/useTranslation/useTranslation' import { TldrawUiButton } from '../primitives/Button/TldrawUiButton' import { TldrawUiButtonCheck } from '../primitives/Button/TldrawUiButtonCheck' import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel' import { TldrawUiMenuCheckboxItem } from '../primitives/menus/TldrawUiMenuCheckboxItem' import { TldrawUiMenuGroup } from '../primitives/menus/TldrawUiMenuGroup' import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem' import { TldrawUiMenuSubmenu } from '../primitives/menus/TldrawUiMenuSubmenu' import { TldrawUiDialogBody, TldrawUiDialogCloseButton, TldrawUiDialogFooter, TldrawUiDialogHeader, TldrawUiDialogTitle, } from '../primitives/TldrawUiDialog' /** @public */ export interface CustomDebugFlags { customDebugFlags?: Record> customFeatureFlags?: Record> } /** @public @react */ export function DefaultDebugMenuContent({ customDebugFlags, customFeatureFlags, }: CustomDebugFlags) { const editor = useEditor() const { addToast } = useToasts() const { addDialog } = useDialogs() const [error, setError] = React.useState(false) return ( <> { addToast({ id: uniqueId(), title: 'Something good happened', description: 'Hey, attend to this thing over here. It might be important!', keepOpen: true, severity: 'success', }) addToast({ id: uniqueId(), title: 'Something happened', description: 'Hey, attend to this thing over here. It might be important!', keepOpen: true, severity: 'info', actions: [ { label: 'Primary', type: 'primary', onClick: () => { void null }, }, { label: 'Normal', type: 'normal', onClick: () => { void null }, }, { label: 'Danger', type: 'danger', onClick: () => { void null }, }, ], }) addToast({ id: uniqueId(), title: 'Something maybe bad happened', description: 'Hey, attend to this thing over here. It might be important!', keepOpen: true, severity: 'warning', actions: [ { label: 'Primary', type: 'primary', onClick: () => { void null }, }, { label: 'Normal', type: 'normal', onClick: () => { void null }, }, { label: 'Danger', type: 'danger', onClick: () => { void null }, }, ], }) addToast({ id: uniqueId(), title: 'Something bad happened', severity: 'error', keepOpen: true, }) }} label={untranslated('Show toast')} /> { addDialog({ component: ({ onClose }) => ( onClose()} onContinue={() => onClose()} /> ), onClose: () => { void null }, }) }} /> createNShapes(editor, 100)} /> { const selectedShapes = editor.getSelectedShapes() const shapes = selectedShapes.length === 0 ? editor.getRenderingShapes() : selectedShapes window.alert( `Shapes ${shapes.length}, DOM nodes:${editor.getContainerDocument().querySelector('.tl-shapes')!.querySelectorAll('*')?.length}` ) }} /> {(() => { if (error) throw Error('oh no!') return null })()} setError(true)} label={'Throw error'} /> ) } /** @public */ export interface DebugFlagsProps { customDebugFlags?: Record> | undefined } /** @public @react */ export function DebugFlags(props: DebugFlagsProps) { const items = Object.values(props.customDebugFlags ?? debugFlags) if (!items.length) return null return ( {items.map((flag) => ( ))} ) } /** @public */ export interface FeatureFlagsProps { customFeatureFlags?: Record> | undefined } /** @public @react */ export function FeatureFlags(props: FeatureFlagsProps) { const items = Object.values(props.customFeatureFlags ?? featureFlags) if (!items.length) return null return ( {items.map((flag) => ( ))} ) } /** @public */ export interface ExampleDialogProps { title?: string body?: React.ReactNode cancel?: string confirm?: string displayDontShowAgain?: boolean maxWidth?: string onCancel(): void onContinue(): void } /** @public @react */ export function ExampleDialog({ title = 'title', body = 'hello hello hello', cancel = 'Cancel', confirm = 'Continue', displayDontShowAgain = false, maxWidth = '350', onCancel, onContinue, }: ExampleDialogProps) { const [dontShowAgain, setDontShowAgain] = React.useState(false) return ( <> {title} {body} {displayDontShowAgain && ( setDontShowAgain(!dontShowAgain)} style={{ marginRight: 'auto' }} > Don’t show again )} {cancel} onContinue()}> {confirm} ) } const DebugFlagToggle = track(function DebugFlagToggle({ flag, onChange, }: { flag: DebugFlag onChange?(newValue: boolean): void }) { const value = flag.get() return ( `${m[0]} ${m[1].toLowerCase()}`) .replace(/^[a-z]/, (m) => m.toUpperCase())} checked={value} onSelect={() => { flag.set(!value) onChange?.(!value) }} /> ) }) let t = 0 function createNShapes(editor: Editor, n: number) { const gap = editor.options.adjacentShapeMargin const shapesToCreate: TLShapePartial[] = Array(n) const cols = Math.floor(Math.sqrt(n)) for (let i = 0; i < n; i++) { t++ shapesToCreate[i] = { id: createShapeId('box' + t), type: 'geo', x: (i % cols) * (100 + gap), y: Math.floor(i / cols) * (100 + gap), } } editor.run(() => { // allow this to trigger the max shapes alert editor.createShapes(shapesToCreate).setSelectedShapes(shapesToCreate.map((s) => s.id)) }) }