@tldraw/editor 3.16.0-next.df90ce0ff566 → 3.16.0-next.eafb52d15064
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +80 -9
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +2 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +8 -2
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +19 -9
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +8 -3
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
- package/dist-cjs/lib/hooks/useStateAttribute.js +35 -0
- package/dist-cjs/lib/hooks/useStateAttribute.js.map +7 -0
- package/dist-cjs/lib/options.js +1 -0
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/utils/EditorAtom.js +45 -0
- package/dist-cjs/lib/utils/EditorAtom.js.map +7 -0
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +80 -9
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +2 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +8 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +19 -9
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +8 -3
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/hooks/useStateAttribute.mjs +15 -0
- package/dist-esm/lib/hooks/useStateAttribute.mjs.map +7 -0
- package/dist-esm/lib/options.mjs +1 -0
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/utils/EditorAtom.mjs +25 -0
- package/dist-esm/lib/utils/EditorAtom.mjs.map +7 -0
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +2 -0
- package/package.json +7 -7
- package/src/index.ts +2 -0
- package/src/lib/TldrawEditor.tsx +2 -0
- package/src/lib/config/TLUserPreferences.ts +7 -0
- package/src/lib/editor/Editor.ts +33 -27
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +13 -0
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +5 -0
- package/src/lib/editor/types/misc-types.ts +54 -1
- package/src/lib/hooks/useStateAttribute.ts +15 -0
- package/src/lib/options.ts +2 -0
- package/src/lib/utils/EditorAtom.ts +37 -0
- package/src/version.ts +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/TldrawEditor.tsx"],
|
|
4
|
-
"sourcesContent": ["import { MigrationSequence, Store } from '@tldraw/store'\nimport { TLShape, TLStore, TLStoreSnapshot } from '@tldraw/tlschema'\nimport { Required, annotateError } from '@tldraw/utils'\nimport React, {\n\tReactNode,\n\tmemo,\n\tuseCallback,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\tuseSyncExternalStore,\n} from 'react'\n\nimport classNames from 'classnames'\nimport { version } from '../version'\nimport { OptionalErrorBoundary } from './components/ErrorBoundary'\nimport { DefaultErrorFallback } from './components/default-components/DefaultErrorFallback'\nimport { TLEditorSnapshot } from './config/TLEditorSnapshot'\nimport { TLStoreBaseOptions } from './config/createTLStore'\nimport { TLUser, createTLUser } from './config/createTLUser'\nimport { TLAnyBindingUtilConstructor } from './config/defaultBindings'\nimport { TLAnyShapeUtilConstructor } from './config/defaultShapes'\nimport { Editor } from './editor/Editor'\nimport { TLStateNodeConstructor } from './editor/tools/StateNode'\nimport { TLCameraOptions } from './editor/types/misc-types'\nimport { ContainerProvider, useContainer } from './hooks/useContainer'\nimport { useCursor } from './hooks/useCursor'\nimport { useDarkMode } from './hooks/useDarkMode'\nimport { EditorProvider, useEditor } from './hooks/useEditor'\nimport {\n\tEditorComponentsProvider,\n\tTLEditorComponents,\n\tuseEditorComponents,\n} from './hooks/useEditorComponents'\nimport { useEvent } from './hooks/useEvent'\nimport { useForceUpdate } from './hooks/useForceUpdate'\nimport { useShallowObjectIdentity } from './hooks/useIdentity'\nimport { useLocalStore } from './hooks/useLocalStore'\nimport { useRefState } from './hooks/useRefState'\nimport { useZoomCss } from './hooks/useZoomCss'\nimport { LicenseProvider } from './license/LicenseProvider'\nimport { Watermark } from './license/Watermark'\nimport { TldrawOptions } from './options'\nimport { TLDeepLinkOptions } from './utils/deepLinks'\nimport { stopEventPropagation } from './utils/dom'\nimport { TLTextOptions } from './utils/richText'\nimport { TLStoreWithStatus } from './utils/sync/StoreWithStatus'\n\n/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components, when passing in a\n * `TLStore` directly. If you would like tldraw to create a store for you, use\n * {@link TldrawEditorWithoutStoreProps}.\n *\n * @public\n */\nexport interface TldrawEditorWithStoreProps {\n\t/**\n\t * The store to use in the editor.\n\t */\n\tstore: TLStore | TLStoreWithStatus\n}\n\n/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components, when not passing in a\n * `TLStore` directly. If you would like to pass in a store directly, use\n * {@link TldrawEditorWithStoreProps}.\n *\n * @public\n */\nexport interface TldrawEditorWithoutStoreProps extends TLStoreBaseOptions {\n\tstore?: undefined\n\n\t/**\n\t * Additional migrations to use in the store\n\t */\n\tmigrations?: readonly MigrationSequence[]\n\n\t/**\n\t * A starting snapshot of data to pre-populate the store. Do not supply both this and\n\t * `initialData`.\n\t */\n\tsnapshot?: TLEditorSnapshot | TLStoreSnapshot\n\n\t/**\n\t * If you would like to persist the store to the browser's local IndexedDB storage and sync it\n\t * across tabs, provide a key here. Each key represents a single tldraw document.\n\t */\n\tpersistenceKey?: string\n\n\tsessionId?: string\n}\n\n/** @public */\nexport type TldrawEditorStoreProps = TldrawEditorWithStoreProps | TldrawEditorWithoutStoreProps\n\n/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components.\n *\n * @public\n **/\nexport type TldrawEditorProps = TldrawEditorBaseProps & TldrawEditorStoreProps\n\n/**\n * Base props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components.\n *\n * @public\n */\nexport interface TldrawEditorBaseProps {\n\t/**\n\t * The component's children.\n\t */\n\tchildren?: ReactNode\n\n\t/**\n\t * An array of shape utils to use in the editor.\n\t */\n\tshapeUtils?: readonly TLAnyShapeUtilConstructor[]\n\n\t/**\n\t * An array of binding utils to use in the editor.\n\t */\n\tbindingUtils?: readonly TLAnyBindingUtilConstructor[]\n\n\t/**\n\t * An array of tools to add to the editor's state chart.\n\t */\n\ttools?: readonly TLStateNodeConstructor[]\n\n\t/**\n\t * Whether to automatically focus the editor when it mounts.\n\t */\n\tautoFocus?: boolean\n\n\t/**\n\t * Overrides for the editor's components, such as handles, collaborator cursors, etc.\n\t */\n\tcomponents?: TLEditorComponents\n\n\t/**\n\t * Called when the editor has mounted.\n\t */\n\tonMount?: TLOnMountHandler\n\n\t/**\n\t * The editor's initial state (usually the id of the first active tool).\n\t */\n\tinitialState?: string\n\n\t/**\n\t * A classname to pass to the editor's container.\n\t */\n\tclassName?: string\n\n\t/**\n\t * The user interacting with the editor.\n\t */\n\tuser?: TLUser\n\n\t/**\n\t * Whether to infer dark mode from the user's OS. Defaults to false.\n\t */\n\tinferDarkMode?: boolean\n\n\t/**\n\t * Camera options for the editor.\n\t */\n\tcameraOptions?: Partial<TLCameraOptions>\n\n\t/**\n\t * Text options for the editor.\n\t */\n\ttextOptions?: TLTextOptions\n\n\t/**\n\t * Options for the editor.\n\t */\n\toptions?: Partial<TldrawOptions>\n\n\t/**\n\t * The license key.\n\t */\n\tlicenseKey?: string\n\n\t/**\n\t * Options for syncing the editor's camera state with the URL.\n\t */\n\tdeepLinks?: true | TLDeepLinkOptions\n\n\t/**\n\t * Predicate for whether or not a shape should be hidden.\n\t *\n\t * @deprecated Use {@link TldrawEditorBaseProps#getShapeVisibility} instead.\n\t */\n\tisShapeHidden?(shape: TLShape, editor: Editor): boolean\n\n\t/**\n\t * Provides a way to hide shapes.\n\t *\n\t * Hidden shapes will not render in the editor, and they will not be eligible for hit test via\n\t * {@link Editor#getShapeAtPoint} and {@link Editor#getShapesAtPoint}. But otherwise they will\n\t * remain in the store and participate in all other operations.\n\t *\n\t * @example\n\t * ```ts\n\t * getShapeVisibility={(shape, editor) => shape.meta.hidden ? 'hidden' : 'inherit'}\n\t * ```\n\t *\n\t * - `'inherit' | undefined` - (default) The shape will be visible unless its parent is hidden.\n\t * - `'hidden'` - The shape will be hidden.\n\t * - `'visible'` - The shape will be visible.\n\t *\n\t * @param shape - The shape to check.\n\t * @param editor - The editor instance.\n\t */\n\tgetShapeVisibility?(\n\t\tshape: TLShape,\n\t\teditor: Editor\n\t): 'visible' | 'hidden' | 'inherit' | null | undefined\n\n\t/**\n\t * The URLs for the fonts to use in the editor.\n\t */\n\tassetUrls?: { fonts?: { [key: string]: string | undefined } }\n}\n\n/**\n * Called when the editor has mounted.\n * @example\n * ```ts\n * <Tldraw onMount={(editor) => editor.selectAll()} />\n * ```\n * @param editor - The editor instance.\n *\n * @public\n */\nexport type TLOnMountHandler = (editor: Editor) => (() => void | undefined) | undefined | void\n\ndeclare global {\n\tinterface Window {\n\t\ttldrawReady: boolean\n\t}\n}\n\nconst EMPTY_SHAPE_UTILS_ARRAY = [] as const\nconst EMPTY_BINDING_UTILS_ARRAY = [] as const\nconst EMPTY_TOOLS_ARRAY = [] as const\n/** @internal */\nexport const TL_CONTAINER_CLASS = 'tl-container'\n\n/** @public @react */\nexport const TldrawEditor = memo(function TldrawEditor({\n\tstore,\n\tcomponents,\n\tclassName,\n\tuser: _user,\n\toptions: _options,\n\t...rest\n}: TldrawEditorProps) {\n\tconst [container, setContainer] = useState<HTMLElement | null>(null)\n\tconst user = useMemo(() => _user ?? createTLUser(), [_user])\n\n\tconst ErrorFallback =\n\t\tcomponents?.ErrorFallback === undefined ? DefaultErrorFallback : components?.ErrorFallback\n\n\t// apply defaults. if you're using the bare @tldraw/editor package, we\n\t// default these to the \"tldraw zero\" configuration. We have different\n\t// defaults applied in tldraw.\n\tconst withDefaults = {\n\t\t...rest,\n\t\tshapeUtils: rest.shapeUtils ?? EMPTY_SHAPE_UTILS_ARRAY,\n\t\tbindingUtils: rest.bindingUtils ?? EMPTY_BINDING_UTILS_ARRAY,\n\t\ttools: rest.tools ?? EMPTY_TOOLS_ARRAY,\n\t\tcomponents,\n\t\toptions: useShallowObjectIdentity(_options),\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={setContainer}\n\t\t\tdata-tldraw={version}\n\t\t\tdraggable={false}\n\t\t\tclassName={classNames(`${TL_CONTAINER_CLASS} tl-theme__light`, className)}\n\t\t\tonPointerDown={stopEventPropagation}\n\t\t\ttabIndex={-1}\n\t\t\trole=\"application\"\n\t\t\taria-label={_options?.branding ?? 'tldraw'}\n\t\t>\n\t\t\t<OptionalErrorBoundary\n\t\t\t\tfallback={ErrorFallback}\n\t\t\t\tonError={(error) => annotateError(error, { tags: { origin: 'react.tldraw-before-app' } })}\n\t\t\t>\n\t\t\t\t{container && (\n\t\t\t\t\t<LicenseProvider licenseKey={rest.licenseKey}>\n\t\t\t\t\t\t<ContainerProvider container={container}>\n\t\t\t\t\t\t\t<EditorComponentsProvider overrides={components}>\n\t\t\t\t\t\t\t\t{store ? (\n\t\t\t\t\t\t\t\t\tstore instanceof Store ? (\n\t\t\t\t\t\t\t\t\t\t// Store is ready to go, whether externally synced or not\n\t\t\t\t\t\t\t\t\t\t<TldrawEditorWithReadyStore {...withDefaults} store={store} user={user} />\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t// Store is a synced store, so handle syncing stages internally\n\t\t\t\t\t\t\t\t\t\t<TldrawEditorWithLoadingStore {...withDefaults} store={store} user={user} />\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t// We have no store (it's undefined) so create one and possibly sync it\n\t\t\t\t\t\t\t\t\t<TldrawEditorWithOwnStore {...withDefaults} store={store} user={user} />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</EditorComponentsProvider>\n\t\t\t\t\t\t</ContainerProvider>\n\t\t\t\t\t</LicenseProvider>\n\t\t\t\t)}\n\t\t\t</OptionalErrorBoundary>\n\t\t</div>\n\t)\n})\n\nfunction TldrawEditorWithOwnStore(\n\tprops: Required<\n\t\tTldrawEditorProps & { store: undefined; user: TLUser },\n\t\t'shapeUtils' | 'bindingUtils' | 'tools'\n\t>\n) {\n\tconst {\n\t\tdefaultName,\n\t\tsnapshot,\n\t\tinitialData,\n\t\tshapeUtils,\n\t\tbindingUtils,\n\t\tpersistenceKey,\n\t\tsessionId,\n\t\tuser,\n\t\tassets,\n\t\tmigrations,\n\t} = props\n\n\tconst syncedStore = useLocalStore({\n\t\tshapeUtils,\n\t\tbindingUtils,\n\t\tinitialData,\n\t\tpersistenceKey,\n\t\tsessionId,\n\t\tdefaultName,\n\t\tsnapshot,\n\t\tassets,\n\t\tmigrations,\n\t})\n\n\treturn <TldrawEditorWithLoadingStore {...props} store={syncedStore} user={user} />\n}\n\nconst TldrawEditorWithLoadingStore = memo(function TldrawEditorBeforeLoading({\n\tstore,\n\tuser,\n\t...rest\n}: Required<\n\tTldrawEditorProps & { store: TLStoreWithStatus; user: TLUser },\n\t'shapeUtils' | 'bindingUtils' | 'tools'\n>) {\n\tconst container = useContainer()\n\n\tuseLayoutEffect(() => {\n\t\tif (user.userPreferences.get().colorScheme === 'dark') {\n\t\t\tcontainer.classList.remove('tl-theme__light')\n\t\t\tcontainer.classList.add('tl-theme__dark')\n\t\t}\n\t}, [container, user])\n\n\tconst { LoadingScreen } = useEditorComponents()\n\n\tswitch (store.status) {\n\t\tcase 'error': {\n\t\t\t// for error handling, we fall back to the default error boundary.\n\t\t\t// if users want to handle this error differently, they can render\n\t\t\t// their own error screen before the TldrawEditor component\n\t\t\tthrow store.error\n\t\t}\n\t\tcase 'loading': {\n\t\t\treturn LoadingScreen ? <LoadingScreen /> : null\n\t\t}\n\t\tcase 'not-synced': {\n\t\t\tbreak\n\t\t}\n\t\tcase 'synced-local': {\n\t\t\tbreak\n\t\t}\n\t\tcase 'synced-remote': {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn <TldrawEditorWithReadyStore {...rest} store={store.store} user={user} />\n})\n\nconst noAutoFocus = () => document.location.search.includes('tldraw_preserve_focus') // || !document.hasFocus() // breaks in nextjs\n\nfunction TldrawEditorWithReadyStore({\n\tonMount,\n\tchildren,\n\tstore,\n\ttools,\n\tshapeUtils,\n\tbindingUtils,\n\tuser,\n\tinitialState,\n\tautoFocus = true,\n\tinferDarkMode,\n\tcameraOptions,\n\ttextOptions,\n\toptions,\n\tlicenseKey,\n\tdeepLinks: _deepLinks,\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tisShapeHidden,\n\tgetShapeVisibility,\n\tassetUrls,\n}: Required<\n\tTldrawEditorProps & {\n\t\tstore: TLStore\n\t\tuser: TLUser\n\t},\n\t'shapeUtils' | 'bindingUtils' | 'tools'\n>) {\n\tconst { ErrorFallback } = useEditorComponents()\n\tconst container = useContainer()\n\n\tconst [editor, setEditor] = useRefState<Editor | null>(null)\n\n\tconst canvasRef = useRef<HTMLDivElement | null>(null)\n\n\tconst deepLinks = useShallowObjectIdentity(_deepLinks === true ? {} : _deepLinks)\n\n\t// props in this ref can be changed without causing the editor to be recreated.\n\tconst editorOptionsRef = useRef({\n\t\t// for these, it's because they're only used when the editor first mounts:\n\t\tautoFocus: autoFocus && !noAutoFocus(),\n\t\tinferDarkMode,\n\t\tinitialState,\n\n\t\t// for these, it's because we keep them up to date in a separate effect:\n\t\tcameraOptions,\n\t\tdeepLinks,\n\t})\n\n\tuseLayoutEffect(() => {\n\t\teditorOptionsRef.current = {\n\t\t\tautoFocus: autoFocus && !noAutoFocus(),\n\t\t\tinferDarkMode,\n\t\t\tinitialState,\n\t\t\tcameraOptions,\n\t\t\tdeepLinks,\n\t\t}\n\t}, [autoFocus, inferDarkMode, initialState, cameraOptions, deepLinks])\n\n\tuseLayoutEffect(\n\t\t() => {\n\t\t\tconst { autoFocus, inferDarkMode, initialState, cameraOptions, deepLinks } =\n\t\t\t\teditorOptionsRef.current\n\t\t\tconst editor = new Editor({\n\t\t\t\tstore,\n\t\t\t\tshapeUtils,\n\t\t\t\tbindingUtils,\n\t\t\t\ttools,\n\t\t\t\tgetContainer: () => container,\n\t\t\t\tuser,\n\t\t\t\tinitialState,\n\t\t\t\t// we should check for some kind of query parameter that turns off autofocus\n\t\t\t\tautoFocus,\n\t\t\t\tinferDarkMode,\n\t\t\t\tcameraOptions,\n\t\t\t\ttextOptions,\n\t\t\t\toptions,\n\t\t\t\tlicenseKey,\n\t\t\t\tisShapeHidden,\n\t\t\t\tgetShapeVisibility,\n\t\t\t\tfontAssetUrls: assetUrls?.fonts,\n\t\t\t})\n\n\t\t\teditor.updateViewportScreenBounds(canvasRef.current ?? container)\n\n\t\t\t// Use the ref here because we only want to do this once when the editor is created.\n\t\t\t// We don't want changes to the urlStateSync prop to trigger creating new editors.\n\t\t\tif (deepLinks) {\n\t\t\t\tif (!deepLinks?.getUrl) {\n\t\t\t\t\t// load the state from window.location\n\t\t\t\t\teditor.navigateToDeepLink(deepLinks)\n\t\t\t\t} else {\n\t\t\t\t\t// load the state from the provided URL\n\t\t\t\t\teditor.navigateToDeepLink({ ...deepLinks, url: deepLinks.getUrl(editor) })\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsetEditor(editor)\n\n\t\t\treturn () => {\n\t\t\t\teditor.dispose()\n\t\t\t}\n\t\t},\n\t\t// if any of these change, we need to recreate the editor.\n\t\t[\n\t\t\tbindingUtils,\n\t\t\tcontainer,\n\t\t\toptions,\n\t\t\tshapeUtils,\n\t\t\tstore,\n\t\t\ttools,\n\t\t\tuser,\n\t\t\tsetEditor,\n\t\t\tlicenseKey,\n\t\t\tisShapeHidden,\n\t\t\tgetShapeVisibility,\n\t\t\ttextOptions,\n\t\t\tassetUrls,\n\t\t]\n\t)\n\n\tuseLayoutEffect(() => {\n\t\tif (!editor) return\n\t\tif (deepLinks) {\n\t\t\treturn editor.registerDeepLinkListener(deepLinks)\n\t\t}\n\t}, [editor, deepLinks])\n\n\t// keep the editor up to date with the latest camera options\n\tuseLayoutEffect(() => {\n\t\tif (editor && cameraOptions) {\n\t\t\teditor.setCameraOptions(cameraOptions)\n\t\t}\n\t}, [editor, cameraOptions])\n\n\tconst crashingError = useSyncExternalStore(\n\t\tuseCallback(\n\t\t\t(onStoreChange) => {\n\t\t\t\tif (editor) {\n\t\t\t\t\teditor.on('crash', onStoreChange)\n\t\t\t\t\treturn () => editor.off('crash', onStoreChange)\n\t\t\t\t}\n\t\t\t\treturn () => {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t},\n\t\t\t[editor]\n\t\t),\n\t\t() => editor?.getCrashingError() ?? null\n\t)\n\n\t// For our examples site, we want autoFocus to be true on the examples site, but not\n\t// when embedded in our docs site. If present, the `tldraw_preserve_focus` search param\n\t// overrides the `autoFocus` prop and prevents the editor from focusing immediately,\n\t// however here we also add some logic to focus the editor when the user clicks\n\t// on it and unfocus it when the user clicks away from it.\n\tuseEffect(\n\t\tfunction handleFocusOnPointerDownForPreserveFocusMode() {\n\t\t\tif (!editor) return\n\n\t\t\tfunction handleFocusOnPointerDown() {\n\t\t\t\tif (!editor) return\n\t\t\t\teditor.focus()\n\t\t\t}\n\n\t\t\tfunction handleBlurOnPointerDown() {\n\t\t\t\tif (!editor) return\n\t\t\t\teditor.blur()\n\t\t\t}\n\n\t\t\tif (autoFocus && noAutoFocus()) {\n\t\t\t\teditor.getContainer().addEventListener('pointerdown', handleFocusOnPointerDown)\n\t\t\t\tdocument.body.addEventListener('pointerdown', handleBlurOnPointerDown)\n\n\t\t\t\treturn () => {\n\t\t\t\t\teditor.getContainer()?.removeEventListener('pointerdown', handleFocusOnPointerDown)\n\t\t\t\t\tdocument.body.removeEventListener('pointerdown', handleBlurOnPointerDown)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, autoFocus]\n\t)\n\n\tconst [_fontLoadingState, setFontLoadingState] = useState<{\n\t\teditor: Editor\n\t\tisLoaded: boolean\n\t} | null>(null)\n\tlet fontLoadingState = _fontLoadingState\n\tif (editor !== fontLoadingState?.editor) {\n\t\tfontLoadingState = null\n\t}\n\tuseEffect(() => {\n\t\tif (!editor) return\n\t\tlet isCancelled = false\n\n\t\tsetFontLoadingState({ editor, isLoaded: false })\n\n\t\teditor.fonts\n\t\t\t.loadRequiredFontsForCurrentPage(editor.options.maxFontsToLoadBeforeRender)\n\t\t\t.finally(() => {\n\t\t\t\tif (isCancelled) return\n\t\t\t\tsetFontLoadingState({ editor, isLoaded: true })\n\t\t\t})\n\n\t\treturn () => {\n\t\t\tisCancelled = true\n\t\t}\n\t}, [editor])\n\n\tconst { Canvas, LoadingScreen } = useEditorComponents()\n\n\tif (!editor || !fontLoadingState?.isLoaded) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{LoadingScreen && <LoadingScreen />}\n\t\t\t\t<div className=\"tl-canvas\" ref={canvasRef} />\n\t\t\t</>\n\t\t)\n\t}\n\n\treturn (\n\t\t// the top-level tldraw component also renders an error boundary almost\n\t\t// identical to this one. the reason we have two is because this one has\n\t\t// access to `App`, which means that here we can enrich errors with data\n\t\t// from app for reporting, and also still attempt to render the user's\n\t\t// document in the event of an error to reassure them that their work is\n\t\t// not lost.\n\t\t<OptionalErrorBoundary\n\t\t\tfallback={ErrorFallback as any}\n\t\t\tonError={(error) =>\n\t\t\t\teditor.annotateError(error, { origin: 'react.tldraw', willCrashApp: true })\n\t\t\t}\n\t\t>\n\t\t\t{crashingError ? (\n\t\t\t\t<Crash crashingError={crashingError} />\n\t\t\t) : (\n\t\t\t\t<EditorProvider editor={editor}>\n\t\t\t\t\t<Layout onMount={onMount}>\n\t\t\t\t\t\t{children ?? (Canvas ? <Canvas key={editor.contextId} /> : null)}\n\t\t\t\t\t\t<Watermark />\n\t\t\t\t\t</Layout>\n\t\t\t\t</EditorProvider>\n\t\t\t)}\n\t\t</OptionalErrorBoundary>\n\t)\n}\n\nfunction Layout({ children, onMount }: { children: ReactNode; onMount?: TLOnMountHandler }) {\n\tuseZoomCss()\n\tuseCursor()\n\tuseDarkMode()\n\tuseForceUpdate()\n\tuseOnMount((editor) => {\n\t\tconst teardownStore = editor.store.props.onMount(editor)\n\t\tconst teardownCallback = onMount?.(editor)\n\n\t\treturn () => {\n\t\t\tteardownStore?.()\n\t\t\tteardownCallback?.()\n\t\t}\n\t})\n\n\treturn children\n}\n\nfunction Crash({ crashingError }: { crashingError: unknown }): null {\n\tthrow crashingError\n}\n\n/** @public */\nexport interface LoadingScreenProps {\n\tchildren: ReactNode\n}\n\n/** @public @react */\nexport function LoadingScreen({ children }: LoadingScreenProps) {\n\treturn (\n\t\t<div className=\"tl-loading\" aria-busy=\"true\" tabIndex={0}>\n\t\t\t{children}\n\t\t</div>\n\t)\n}\n\n/** @public @react */\nexport function ErrorScreen({ children }: LoadingScreenProps) {\n\treturn <div className=\"tl-loading\">{children}</div>\n}\n\n/** @internal */\nexport function useOnMount(onMount?: TLOnMountHandler) {\n\tconst editor = useEditor()\n\n\tconst onMountEvent = useEvent((editor: Editor) => {\n\t\tlet teardown: (() => void) | void = undefined\n\t\t// If the user wants to do something when the editor mounts, we make sure it doesn't effect the history.\n\t\t// todo: is this reeeeally what we want to do, or should we leave it up to the caller?\n\t\teditor.run(\n\t\t\t() => {\n\t\t\t\tteardown = onMount?.(editor)\n\t\t\t\teditor.emit('mount')\n\t\t\t},\n\t\t\t{ history: 'ignore' }\n\t\t)\n\t\twindow.tldrawReady = true\n\t\treturn teardown\n\t})\n\n\tReact.useLayoutEffect(() => {\n\t\tif (editor) return onMountEvent?.(editor)\n\t}, [editor, onMountEvent])\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { MigrationSequence, Store } from '@tldraw/store'\nimport { TLShape, TLStore, TLStoreSnapshot } from '@tldraw/tlschema'\nimport { Required, annotateError } from '@tldraw/utils'\nimport React, {\n\tReactNode,\n\tmemo,\n\tuseCallback,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\tuseSyncExternalStore,\n} from 'react'\n\nimport classNames from 'classnames'\nimport { version } from '../version'\nimport { OptionalErrorBoundary } from './components/ErrorBoundary'\nimport { DefaultErrorFallback } from './components/default-components/DefaultErrorFallback'\nimport { TLEditorSnapshot } from './config/TLEditorSnapshot'\nimport { TLStoreBaseOptions } from './config/createTLStore'\nimport { TLUser, createTLUser } from './config/createTLUser'\nimport { TLAnyBindingUtilConstructor } from './config/defaultBindings'\nimport { TLAnyShapeUtilConstructor } from './config/defaultShapes'\nimport { Editor } from './editor/Editor'\nimport { TLStateNodeConstructor } from './editor/tools/StateNode'\nimport { TLCameraOptions } from './editor/types/misc-types'\nimport { ContainerProvider, useContainer } from './hooks/useContainer'\nimport { useCursor } from './hooks/useCursor'\nimport { useDarkMode } from './hooks/useDarkMode'\nimport { EditorProvider, useEditor } from './hooks/useEditor'\nimport {\n\tEditorComponentsProvider,\n\tTLEditorComponents,\n\tuseEditorComponents,\n} from './hooks/useEditorComponents'\nimport { useEvent } from './hooks/useEvent'\nimport { useForceUpdate } from './hooks/useForceUpdate'\nimport { useShallowObjectIdentity } from './hooks/useIdentity'\nimport { useLocalStore } from './hooks/useLocalStore'\nimport { useRefState } from './hooks/useRefState'\nimport { useStateAttribute } from './hooks/useStateAttribute'\nimport { useZoomCss } from './hooks/useZoomCss'\nimport { LicenseProvider } from './license/LicenseProvider'\nimport { Watermark } from './license/Watermark'\nimport { TldrawOptions } from './options'\nimport { TLDeepLinkOptions } from './utils/deepLinks'\nimport { stopEventPropagation } from './utils/dom'\nimport { TLTextOptions } from './utils/richText'\nimport { TLStoreWithStatus } from './utils/sync/StoreWithStatus'\n\n/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components, when passing in a\n * `TLStore` directly. If you would like tldraw to create a store for you, use\n * {@link TldrawEditorWithoutStoreProps}.\n *\n * @public\n */\nexport interface TldrawEditorWithStoreProps {\n\t/**\n\t * The store to use in the editor.\n\t */\n\tstore: TLStore | TLStoreWithStatus\n}\n\n/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components, when not passing in a\n * `TLStore` directly. If you would like to pass in a store directly, use\n * {@link TldrawEditorWithStoreProps}.\n *\n * @public\n */\nexport interface TldrawEditorWithoutStoreProps extends TLStoreBaseOptions {\n\tstore?: undefined\n\n\t/**\n\t * Additional migrations to use in the store\n\t */\n\tmigrations?: readonly MigrationSequence[]\n\n\t/**\n\t * A starting snapshot of data to pre-populate the store. Do not supply both this and\n\t * `initialData`.\n\t */\n\tsnapshot?: TLEditorSnapshot | TLStoreSnapshot\n\n\t/**\n\t * If you would like to persist the store to the browser's local IndexedDB storage and sync it\n\t * across tabs, provide a key here. Each key represents a single tldraw document.\n\t */\n\tpersistenceKey?: string\n\n\tsessionId?: string\n}\n\n/** @public */\nexport type TldrawEditorStoreProps = TldrawEditorWithStoreProps | TldrawEditorWithoutStoreProps\n\n/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components.\n *\n * @public\n **/\nexport type TldrawEditorProps = TldrawEditorBaseProps & TldrawEditorStoreProps\n\n/**\n * Base props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components.\n *\n * @public\n */\nexport interface TldrawEditorBaseProps {\n\t/**\n\t * The component's children.\n\t */\n\tchildren?: ReactNode\n\n\t/**\n\t * An array of shape utils to use in the editor.\n\t */\n\tshapeUtils?: readonly TLAnyShapeUtilConstructor[]\n\n\t/**\n\t * An array of binding utils to use in the editor.\n\t */\n\tbindingUtils?: readonly TLAnyBindingUtilConstructor[]\n\n\t/**\n\t * An array of tools to add to the editor's state chart.\n\t */\n\ttools?: readonly TLStateNodeConstructor[]\n\n\t/**\n\t * Whether to automatically focus the editor when it mounts.\n\t */\n\tautoFocus?: boolean\n\n\t/**\n\t * Overrides for the editor's components, such as handles, collaborator cursors, etc.\n\t */\n\tcomponents?: TLEditorComponents\n\n\t/**\n\t * Called when the editor has mounted.\n\t */\n\tonMount?: TLOnMountHandler\n\n\t/**\n\t * The editor's initial state (usually the id of the first active tool).\n\t */\n\tinitialState?: string\n\n\t/**\n\t * A classname to pass to the editor's container.\n\t */\n\tclassName?: string\n\n\t/**\n\t * The user interacting with the editor.\n\t */\n\tuser?: TLUser\n\n\t/**\n\t * Whether to infer dark mode from the user's OS. Defaults to false.\n\t */\n\tinferDarkMode?: boolean\n\n\t/**\n\t * Camera options for the editor.\n\t */\n\tcameraOptions?: Partial<TLCameraOptions>\n\n\t/**\n\t * Text options for the editor.\n\t */\n\ttextOptions?: TLTextOptions\n\n\t/**\n\t * Options for the editor.\n\t */\n\toptions?: Partial<TldrawOptions>\n\n\t/**\n\t * The license key.\n\t */\n\tlicenseKey?: string\n\n\t/**\n\t * Options for syncing the editor's camera state with the URL.\n\t */\n\tdeepLinks?: true | TLDeepLinkOptions\n\n\t/**\n\t * Predicate for whether or not a shape should be hidden.\n\t *\n\t * @deprecated Use {@link TldrawEditorBaseProps#getShapeVisibility} instead.\n\t */\n\tisShapeHidden?(shape: TLShape, editor: Editor): boolean\n\n\t/**\n\t * Provides a way to hide shapes.\n\t *\n\t * Hidden shapes will not render in the editor, and they will not be eligible for hit test via\n\t * {@link Editor#getShapeAtPoint} and {@link Editor#getShapesAtPoint}. But otherwise they will\n\t * remain in the store and participate in all other operations.\n\t *\n\t * @example\n\t * ```ts\n\t * getShapeVisibility={(shape, editor) => shape.meta.hidden ? 'hidden' : 'inherit'}\n\t * ```\n\t *\n\t * - `'inherit' | undefined` - (default) The shape will be visible unless its parent is hidden.\n\t * - `'hidden'` - The shape will be hidden.\n\t * - `'visible'` - The shape will be visible.\n\t *\n\t * @param shape - The shape to check.\n\t * @param editor - The editor instance.\n\t */\n\tgetShapeVisibility?(\n\t\tshape: TLShape,\n\t\teditor: Editor\n\t): 'visible' | 'hidden' | 'inherit' | null | undefined\n\n\t/**\n\t * The URLs for the fonts to use in the editor.\n\t */\n\tassetUrls?: { fonts?: { [key: string]: string | undefined } }\n}\n\n/**\n * Called when the editor has mounted.\n * @example\n * ```ts\n * <Tldraw onMount={(editor) => editor.selectAll()} />\n * ```\n * @param editor - The editor instance.\n *\n * @public\n */\nexport type TLOnMountHandler = (editor: Editor) => (() => void | undefined) | undefined | void\n\ndeclare global {\n\tinterface Window {\n\t\ttldrawReady: boolean\n\t}\n}\n\nconst EMPTY_SHAPE_UTILS_ARRAY = [] as const\nconst EMPTY_BINDING_UTILS_ARRAY = [] as const\nconst EMPTY_TOOLS_ARRAY = [] as const\n/** @internal */\nexport const TL_CONTAINER_CLASS = 'tl-container'\n\n/** @public @react */\nexport const TldrawEditor = memo(function TldrawEditor({\n\tstore,\n\tcomponents,\n\tclassName,\n\tuser: _user,\n\toptions: _options,\n\t...rest\n}: TldrawEditorProps) {\n\tconst [container, setContainer] = useState<HTMLElement | null>(null)\n\tconst user = useMemo(() => _user ?? createTLUser(), [_user])\n\n\tconst ErrorFallback =\n\t\tcomponents?.ErrorFallback === undefined ? DefaultErrorFallback : components?.ErrorFallback\n\n\t// apply defaults. if you're using the bare @tldraw/editor package, we\n\t// default these to the \"tldraw zero\" configuration. We have different\n\t// defaults applied in tldraw.\n\tconst withDefaults = {\n\t\t...rest,\n\t\tshapeUtils: rest.shapeUtils ?? EMPTY_SHAPE_UTILS_ARRAY,\n\t\tbindingUtils: rest.bindingUtils ?? EMPTY_BINDING_UTILS_ARRAY,\n\t\ttools: rest.tools ?? EMPTY_TOOLS_ARRAY,\n\t\tcomponents,\n\t\toptions: useShallowObjectIdentity(_options),\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={setContainer}\n\t\t\tdata-tldraw={version}\n\t\t\tdraggable={false}\n\t\t\tclassName={classNames(`${TL_CONTAINER_CLASS} tl-theme__light`, className)}\n\t\t\tonPointerDown={stopEventPropagation}\n\t\t\ttabIndex={-1}\n\t\t\trole=\"application\"\n\t\t\taria-label={_options?.branding ?? 'tldraw'}\n\t\t>\n\t\t\t<OptionalErrorBoundary\n\t\t\t\tfallback={ErrorFallback}\n\t\t\t\tonError={(error) => annotateError(error, { tags: { origin: 'react.tldraw-before-app' } })}\n\t\t\t>\n\t\t\t\t{container && (\n\t\t\t\t\t<LicenseProvider licenseKey={rest.licenseKey}>\n\t\t\t\t\t\t<ContainerProvider container={container}>\n\t\t\t\t\t\t\t<EditorComponentsProvider overrides={components}>\n\t\t\t\t\t\t\t\t{store ? (\n\t\t\t\t\t\t\t\t\tstore instanceof Store ? (\n\t\t\t\t\t\t\t\t\t\t// Store is ready to go, whether externally synced or not\n\t\t\t\t\t\t\t\t\t\t<TldrawEditorWithReadyStore {...withDefaults} store={store} user={user} />\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t// Store is a synced store, so handle syncing stages internally\n\t\t\t\t\t\t\t\t\t\t<TldrawEditorWithLoadingStore {...withDefaults} store={store} user={user} />\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t// We have no store (it's undefined) so create one and possibly sync it\n\t\t\t\t\t\t\t\t\t<TldrawEditorWithOwnStore {...withDefaults} store={store} user={user} />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</EditorComponentsProvider>\n\t\t\t\t\t\t</ContainerProvider>\n\t\t\t\t\t</LicenseProvider>\n\t\t\t\t)}\n\t\t\t</OptionalErrorBoundary>\n\t\t</div>\n\t)\n})\n\nfunction TldrawEditorWithOwnStore(\n\tprops: Required<\n\t\tTldrawEditorProps & { store: undefined; user: TLUser },\n\t\t'shapeUtils' | 'bindingUtils' | 'tools'\n\t>\n) {\n\tconst {\n\t\tdefaultName,\n\t\tsnapshot,\n\t\tinitialData,\n\t\tshapeUtils,\n\t\tbindingUtils,\n\t\tpersistenceKey,\n\t\tsessionId,\n\t\tuser,\n\t\tassets,\n\t\tmigrations,\n\t} = props\n\n\tconst syncedStore = useLocalStore({\n\t\tshapeUtils,\n\t\tbindingUtils,\n\t\tinitialData,\n\t\tpersistenceKey,\n\t\tsessionId,\n\t\tdefaultName,\n\t\tsnapshot,\n\t\tassets,\n\t\tmigrations,\n\t})\n\n\treturn <TldrawEditorWithLoadingStore {...props} store={syncedStore} user={user} />\n}\n\nconst TldrawEditorWithLoadingStore = memo(function TldrawEditorBeforeLoading({\n\tstore,\n\tuser,\n\t...rest\n}: Required<\n\tTldrawEditorProps & { store: TLStoreWithStatus; user: TLUser },\n\t'shapeUtils' | 'bindingUtils' | 'tools'\n>) {\n\tconst container = useContainer()\n\n\tuseLayoutEffect(() => {\n\t\tif (user.userPreferences.get().colorScheme === 'dark') {\n\t\t\tcontainer.classList.remove('tl-theme__light')\n\t\t\tcontainer.classList.add('tl-theme__dark')\n\t\t}\n\t}, [container, user])\n\n\tconst { LoadingScreen } = useEditorComponents()\n\n\tswitch (store.status) {\n\t\tcase 'error': {\n\t\t\t// for error handling, we fall back to the default error boundary.\n\t\t\t// if users want to handle this error differently, they can render\n\t\t\t// their own error screen before the TldrawEditor component\n\t\t\tthrow store.error\n\t\t}\n\t\tcase 'loading': {\n\t\t\treturn LoadingScreen ? <LoadingScreen /> : null\n\t\t}\n\t\tcase 'not-synced': {\n\t\t\tbreak\n\t\t}\n\t\tcase 'synced-local': {\n\t\t\tbreak\n\t\t}\n\t\tcase 'synced-remote': {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn <TldrawEditorWithReadyStore {...rest} store={store.store} user={user} />\n})\n\nconst noAutoFocus = () => document.location.search.includes('tldraw_preserve_focus') // || !document.hasFocus() // breaks in nextjs\n\nfunction TldrawEditorWithReadyStore({\n\tonMount,\n\tchildren,\n\tstore,\n\ttools,\n\tshapeUtils,\n\tbindingUtils,\n\tuser,\n\tinitialState,\n\tautoFocus = true,\n\tinferDarkMode,\n\tcameraOptions,\n\ttextOptions,\n\toptions,\n\tlicenseKey,\n\tdeepLinks: _deepLinks,\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tisShapeHidden,\n\tgetShapeVisibility,\n\tassetUrls,\n}: Required<\n\tTldrawEditorProps & {\n\t\tstore: TLStore\n\t\tuser: TLUser\n\t},\n\t'shapeUtils' | 'bindingUtils' | 'tools'\n>) {\n\tconst { ErrorFallback } = useEditorComponents()\n\tconst container = useContainer()\n\n\tconst [editor, setEditor] = useRefState<Editor | null>(null)\n\n\tconst canvasRef = useRef<HTMLDivElement | null>(null)\n\n\tconst deepLinks = useShallowObjectIdentity(_deepLinks === true ? {} : _deepLinks)\n\n\t// props in this ref can be changed without causing the editor to be recreated.\n\tconst editorOptionsRef = useRef({\n\t\t// for these, it's because they're only used when the editor first mounts:\n\t\tautoFocus: autoFocus && !noAutoFocus(),\n\t\tinferDarkMode,\n\t\tinitialState,\n\n\t\t// for these, it's because we keep them up to date in a separate effect:\n\t\tcameraOptions,\n\t\tdeepLinks,\n\t})\n\n\tuseLayoutEffect(() => {\n\t\teditorOptionsRef.current = {\n\t\t\tautoFocus: autoFocus && !noAutoFocus(),\n\t\t\tinferDarkMode,\n\t\t\tinitialState,\n\t\t\tcameraOptions,\n\t\t\tdeepLinks,\n\t\t}\n\t}, [autoFocus, inferDarkMode, initialState, cameraOptions, deepLinks])\n\n\tuseLayoutEffect(\n\t\t() => {\n\t\t\tconst { autoFocus, inferDarkMode, initialState, cameraOptions, deepLinks } =\n\t\t\t\teditorOptionsRef.current\n\t\t\tconst editor = new Editor({\n\t\t\t\tstore,\n\t\t\t\tshapeUtils,\n\t\t\t\tbindingUtils,\n\t\t\t\ttools,\n\t\t\t\tgetContainer: () => container,\n\t\t\t\tuser,\n\t\t\t\tinitialState,\n\t\t\t\t// we should check for some kind of query parameter that turns off autofocus\n\t\t\t\tautoFocus,\n\t\t\t\tinferDarkMode,\n\t\t\t\tcameraOptions,\n\t\t\t\ttextOptions,\n\t\t\t\toptions,\n\t\t\t\tlicenseKey,\n\t\t\t\tisShapeHidden,\n\t\t\t\tgetShapeVisibility,\n\t\t\t\tfontAssetUrls: assetUrls?.fonts,\n\t\t\t})\n\n\t\t\teditor.updateViewportScreenBounds(canvasRef.current ?? container)\n\n\t\t\t// Use the ref here because we only want to do this once when the editor is created.\n\t\t\t// We don't want changes to the urlStateSync prop to trigger creating new editors.\n\t\t\tif (deepLinks) {\n\t\t\t\tif (!deepLinks?.getUrl) {\n\t\t\t\t\t// load the state from window.location\n\t\t\t\t\teditor.navigateToDeepLink(deepLinks)\n\t\t\t\t} else {\n\t\t\t\t\t// load the state from the provided URL\n\t\t\t\t\teditor.navigateToDeepLink({ ...deepLinks, url: deepLinks.getUrl(editor) })\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsetEditor(editor)\n\n\t\t\treturn () => {\n\t\t\t\teditor.dispose()\n\t\t\t}\n\t\t},\n\t\t// if any of these change, we need to recreate the editor.\n\t\t[\n\t\t\tbindingUtils,\n\t\t\tcontainer,\n\t\t\toptions,\n\t\t\tshapeUtils,\n\t\t\tstore,\n\t\t\ttools,\n\t\t\tuser,\n\t\t\tsetEditor,\n\t\t\tlicenseKey,\n\t\t\tisShapeHidden,\n\t\t\tgetShapeVisibility,\n\t\t\ttextOptions,\n\t\t\tassetUrls,\n\t\t]\n\t)\n\n\tuseLayoutEffect(() => {\n\t\tif (!editor) return\n\t\tif (deepLinks) {\n\t\t\treturn editor.registerDeepLinkListener(deepLinks)\n\t\t}\n\t}, [editor, deepLinks])\n\n\t// keep the editor up to date with the latest camera options\n\tuseLayoutEffect(() => {\n\t\tif (editor && cameraOptions) {\n\t\t\teditor.setCameraOptions(cameraOptions)\n\t\t}\n\t}, [editor, cameraOptions])\n\n\tconst crashingError = useSyncExternalStore(\n\t\tuseCallback(\n\t\t\t(onStoreChange) => {\n\t\t\t\tif (editor) {\n\t\t\t\t\teditor.on('crash', onStoreChange)\n\t\t\t\t\treturn () => editor.off('crash', onStoreChange)\n\t\t\t\t}\n\t\t\t\treturn () => {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t},\n\t\t\t[editor]\n\t\t),\n\t\t() => editor?.getCrashingError() ?? null\n\t)\n\n\t// For our examples site, we want autoFocus to be true on the examples site, but not\n\t// when embedded in our docs site. If present, the `tldraw_preserve_focus` search param\n\t// overrides the `autoFocus` prop and prevents the editor from focusing immediately,\n\t// however here we also add some logic to focus the editor when the user clicks\n\t// on it and unfocus it when the user clicks away from it.\n\tuseEffect(\n\t\tfunction handleFocusOnPointerDownForPreserveFocusMode() {\n\t\t\tif (!editor) return\n\n\t\t\tfunction handleFocusOnPointerDown() {\n\t\t\t\tif (!editor) return\n\t\t\t\teditor.focus()\n\t\t\t}\n\n\t\t\tfunction handleBlurOnPointerDown() {\n\t\t\t\tif (!editor) return\n\t\t\t\teditor.blur()\n\t\t\t}\n\n\t\t\tif (autoFocus && noAutoFocus()) {\n\t\t\t\teditor.getContainer().addEventListener('pointerdown', handleFocusOnPointerDown)\n\t\t\t\tdocument.body.addEventListener('pointerdown', handleBlurOnPointerDown)\n\n\t\t\t\treturn () => {\n\t\t\t\t\teditor.getContainer()?.removeEventListener('pointerdown', handleFocusOnPointerDown)\n\t\t\t\t\tdocument.body.removeEventListener('pointerdown', handleBlurOnPointerDown)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, autoFocus]\n\t)\n\n\tconst [_fontLoadingState, setFontLoadingState] = useState<{\n\t\teditor: Editor\n\t\tisLoaded: boolean\n\t} | null>(null)\n\tlet fontLoadingState = _fontLoadingState\n\tif (editor !== fontLoadingState?.editor) {\n\t\tfontLoadingState = null\n\t}\n\tuseEffect(() => {\n\t\tif (!editor) return\n\t\tlet isCancelled = false\n\n\t\tsetFontLoadingState({ editor, isLoaded: false })\n\n\t\teditor.fonts\n\t\t\t.loadRequiredFontsForCurrentPage(editor.options.maxFontsToLoadBeforeRender)\n\t\t\t.finally(() => {\n\t\t\t\tif (isCancelled) return\n\t\t\t\tsetFontLoadingState({ editor, isLoaded: true })\n\t\t\t})\n\n\t\treturn () => {\n\t\t\tisCancelled = true\n\t\t}\n\t}, [editor])\n\n\tconst { Canvas, LoadingScreen } = useEditorComponents()\n\n\tif (!editor || !fontLoadingState?.isLoaded) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{LoadingScreen && <LoadingScreen />}\n\t\t\t\t<div className=\"tl-canvas\" ref={canvasRef} />\n\t\t\t</>\n\t\t)\n\t}\n\n\treturn (\n\t\t// the top-level tldraw component also renders an error boundary almost\n\t\t// identical to this one. the reason we have two is because this one has\n\t\t// access to `App`, which means that here we can enrich errors with data\n\t\t// from app for reporting, and also still attempt to render the user's\n\t\t// document in the event of an error to reassure them that their work is\n\t\t// not lost.\n\t\t<OptionalErrorBoundary\n\t\t\tfallback={ErrorFallback as any}\n\t\t\tonError={(error) =>\n\t\t\t\teditor.annotateError(error, { origin: 'react.tldraw', willCrashApp: true })\n\t\t\t}\n\t\t>\n\t\t\t{crashingError ? (\n\t\t\t\t<Crash crashingError={crashingError} />\n\t\t\t) : (\n\t\t\t\t<EditorProvider editor={editor}>\n\t\t\t\t\t<Layout onMount={onMount}>\n\t\t\t\t\t\t{children ?? (Canvas ? <Canvas key={editor.contextId} /> : null)}\n\t\t\t\t\t\t<Watermark />\n\t\t\t\t\t</Layout>\n\t\t\t\t</EditorProvider>\n\t\t\t)}\n\t\t</OptionalErrorBoundary>\n\t)\n}\n\nfunction Layout({ children, onMount }: { children: ReactNode; onMount?: TLOnMountHandler }) {\n\tuseZoomCss()\n\tuseCursor()\n\tuseDarkMode()\n\tuseForceUpdate()\n\tuseStateAttribute()\n\tuseOnMount((editor) => {\n\t\tconst teardownStore = editor.store.props.onMount(editor)\n\t\tconst teardownCallback = onMount?.(editor)\n\n\t\treturn () => {\n\t\t\tteardownStore?.()\n\t\t\tteardownCallback?.()\n\t\t}\n\t})\n\n\treturn children\n}\n\nfunction Crash({ crashingError }: { crashingError: unknown }): null {\n\tthrow crashingError\n}\n\n/** @public */\nexport interface LoadingScreenProps {\n\tchildren: ReactNode\n}\n\n/** @public @react */\nexport function LoadingScreen({ children }: LoadingScreenProps) {\n\treturn (\n\t\t<div className=\"tl-loading\" aria-busy=\"true\" tabIndex={0}>\n\t\t\t{children}\n\t\t</div>\n\t)\n}\n\n/** @public @react */\nexport function ErrorScreen({ children }: LoadingScreenProps) {\n\treturn <div className=\"tl-loading\">{children}</div>\n}\n\n/** @internal */\nexport function useOnMount(onMount?: TLOnMountHandler) {\n\tconst editor = useEditor()\n\n\tconst onMountEvent = useEvent((editor: Editor) => {\n\t\tlet teardown: (() => void) | void = undefined\n\t\t// If the user wants to do something when the editor mounts, we make sure it doesn't effect the history.\n\t\t// todo: is this reeeeally what we want to do, or should we leave it up to the caller?\n\t\teditor.run(\n\t\t\t() => {\n\t\t\t\tteardown = onMount?.(editor)\n\t\t\t\teditor.emit('mount')\n\t\t\t},\n\t\t\t{ history: 'ignore' }\n\t\t)\n\t\twindow.tldrawReady = true\n\t\treturn teardown\n\t})\n\n\tReact.useLayoutEffect(() => {\n\t\tif (editor) return onMountEvent?.(editor)\n\t}, [editor, onMountEvent])\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["TldrawEditor", "LoadingScreen", "autoFocus", "inferDarkMode", "initialState", "cameraOptions", "deepLinks", "editor"]
|
|
7
7
|
}
|
|
@@ -16,7 +16,8 @@ const userTypeValidator = T.object({
|
|
|
16
16
|
isSnapMode: T.boolean.nullable().optional(),
|
|
17
17
|
isWrapMode: T.boolean.nullable().optional(),
|
|
18
18
|
isDynamicSizeMode: T.boolean.nullable().optional(),
|
|
19
|
-
isPasteAtCursorMode: T.boolean.nullable().optional()
|
|
19
|
+
isPasteAtCursorMode: T.boolean.nullable().optional(),
|
|
20
|
+
showUiLabels: T.boolean.nullable().optional()
|
|
20
21
|
});
|
|
21
22
|
const Versions = {
|
|
22
23
|
AddAnimationSpeed: 1,
|
|
@@ -27,7 +28,8 @@ const Versions = {
|
|
|
27
28
|
AddDynamicSizeMode: 6,
|
|
28
29
|
AllowSystemColorScheme: 7,
|
|
29
30
|
AddPasteAtCursor: 8,
|
|
30
|
-
AddKeyboardShortcuts: 9
|
|
31
|
+
AddKeyboardShortcuts: 9,
|
|
32
|
+
AddShowUiLabels: 10
|
|
31
33
|
};
|
|
32
34
|
const CURRENT_VERSION = Math.max(...Object.values(Versions));
|
|
33
35
|
function migrateSnapshot(data) {
|
|
@@ -62,6 +64,9 @@ function migrateSnapshot(data) {
|
|
|
62
64
|
if (data.version < Versions.AddKeyboardShortcuts) {
|
|
63
65
|
data.user.areKeyboardShortcutsEnabled = true;
|
|
64
66
|
}
|
|
67
|
+
if (data.version < Versions.AddShowUiLabels) {
|
|
68
|
+
data.user.showUiLabels = false;
|
|
69
|
+
}
|
|
65
70
|
data.version = CURRENT_VERSION;
|
|
66
71
|
}
|
|
67
72
|
const USER_COLORS = [
|
|
@@ -99,6 +104,7 @@ const defaultUserPreferences = Object.freeze({
|
|
|
99
104
|
isWrapMode: false,
|
|
100
105
|
isDynamicSizeMode: false,
|
|
101
106
|
isPasteAtCursorMode: false,
|
|
107
|
+
showUiLabels: false,
|
|
102
108
|
colorScheme: "light"
|
|
103
109
|
});
|
|
104
110
|
function getFreshUserPreferences() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/config/TLUserPreferences.ts"],
|
|
4
|
-
"sourcesContent": ["import { atom } from '@tldraw/state'\nimport { getDefaultTranslationLocale } from '@tldraw/tlschema'\nimport { getFromLocalStorage, setInLocalStorage, structuredClone, uniqueId } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\n\nconst USER_DATA_KEY = 'TLDRAW_USER_DATA_v3'\n\n/**\n * A user of tldraw\n *\n * @public\n */\nexport interface TLUserPreferences {\n\tid: string\n\tname?: string | null\n\tcolor?: string | null\n\t// N.B. These are duplicated in TLdrawAppUser.\n\tlocale?: string | null\n\tanimationSpeed?: number | null\n\tareKeyboardShortcutsEnabled?: boolean | null\n\tedgeScrollSpeed?: number | null\n\tcolorScheme?: 'light' | 'dark' | 'system'\n\tisSnapMode?: boolean | null\n\tisWrapMode?: boolean | null\n\tisDynamicSizeMode?: boolean | null\n\tisPasteAtCursorMode?: boolean | null\n}\n\ninterface UserDataSnapshot {\n\tversion: number\n\tuser: TLUserPreferences\n}\n\ninterface UserChangeBroadcastMessage {\n\ttype: typeof broadcastEventKey\n\torigin: string\n\tdata: UserDataSnapshot\n}\n\n/** @public */\nexport const userTypeValidator: T.Validator<TLUserPreferences> = T.object<TLUserPreferences>({\n\tid: T.string,\n\tname: T.string.nullable().optional(),\n\tcolor: T.string.nullable().optional(),\n\t// N.B. These are duplicated in TLdrawAppUser.\n\tlocale: T.string.nullable().optional(),\n\tanimationSpeed: T.number.nullable().optional(),\n\tareKeyboardShortcutsEnabled: T.boolean.nullable().optional(),\n\tedgeScrollSpeed: T.number.nullable().optional(),\n\tcolorScheme: T.literalEnum('light', 'dark', 'system').optional(),\n\tisSnapMode: T.boolean.nullable().optional(),\n\tisWrapMode: T.boolean.nullable().optional(),\n\tisDynamicSizeMode: T.boolean.nullable().optional(),\n\tisPasteAtCursorMode: T.boolean.nullable().optional(),\n})\n\nconst Versions = {\n\tAddAnimationSpeed: 1,\n\tAddIsSnapMode: 2,\n\tMakeFieldsNullable: 3,\n\tAddEdgeScrollSpeed: 4,\n\tAddExcalidrawSelectMode: 5,\n\tAddDynamicSizeMode: 6,\n\tAllowSystemColorScheme: 7,\n\tAddPasteAtCursor: 8,\n\tAddKeyboardShortcuts: 9,\n} as const\n\nconst CURRENT_VERSION = Math.max(...Object.values(Versions))\n\nfunction migrateSnapshot(data: { version: number; user: any }) {\n\tif (data.version < Versions.AddAnimationSpeed) {\n\t\tdata.user.animationSpeed = 1\n\t}\n\tif (data.version < Versions.AddIsSnapMode) {\n\t\tdata.user.isSnapMode = false\n\t}\n\tif (data.version < Versions.MakeFieldsNullable) {\n\t\t// noop\n\t}\n\tif (data.version < Versions.AddEdgeScrollSpeed) {\n\t\tdata.user.edgeScrollSpeed = 1\n\t}\n\tif (data.version < Versions.AddExcalidrawSelectMode) {\n\t\tdata.user.isWrapMode = false\n\t}\n\tif (data.version < Versions.AllowSystemColorScheme) {\n\t\tif (data.user.isDarkMode === true) {\n\t\t\tdata.user.colorScheme = 'dark'\n\t\t} else if (data.user.isDarkMode === false) {\n\t\t\tdata.user.colorScheme = 'light'\n\t\t}\n\t\tdelete data.user.isDarkMode\n\t}\n\n\tif (data.version < Versions.AddDynamicSizeMode) {\n\t\tdata.user.isDynamicSizeMode = false\n\t}\n\tif (data.version < Versions.AddPasteAtCursor) {\n\t\tdata.user.isPasteAtCursorMode = false\n\t}\n\tif (data.version < Versions.AddKeyboardShortcuts) {\n\t\tdata.user.areKeyboardShortcutsEnabled = true\n\t}\n\n\t// finally\n\tdata.version = CURRENT_VERSION\n}\n\n/** @internal */\nexport const USER_COLORS = [\n\t'#FF802B',\n\t'#EC5E41',\n\t'#F2555A',\n\t'#F04F88',\n\t'#E34BA9',\n\t'#BD54C6',\n\t'#9D5BD2',\n\t'#7B66DC',\n\t'#02B1CC',\n\t'#11B3A3',\n\t'#39B178',\n\t'#55B467',\n] as const\n\nfunction getRandomColor() {\n\treturn USER_COLORS[Math.floor(Math.random() * USER_COLORS.length)]\n}\n\n/** @internal */\nexport function userPrefersReducedMotion() {\n\tif (typeof window !== 'undefined' && 'matchMedia' in window) {\n\t\treturn window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ?? false\n\t}\n\n\treturn false\n}\n\n/** @public */\nexport const defaultUserPreferences = Object.freeze({\n\tname: '',\n\tlocale: getDefaultTranslationLocale(),\n\tcolor: getRandomColor(),\n\n\t// N.B. These are duplicated in TLdrawAppUser.\n\tedgeScrollSpeed: 1,\n\tanimationSpeed: userPrefersReducedMotion() ? 0 : 1,\n\tareKeyboardShortcutsEnabled: true,\n\tisSnapMode: false,\n\tisWrapMode: false,\n\tisDynamicSizeMode: false,\n\tisPasteAtCursorMode: false,\n\tcolorScheme: 'light',\n}) satisfies Readonly<Omit<TLUserPreferences, 'id'>>\n\n/** @public */\nexport function getFreshUserPreferences(): TLUserPreferences {\n\treturn {\n\t\tid: uniqueId(),\n\t\tcolor: getRandomColor(),\n\t}\n}\n\nfunction migrateUserPreferences(userData: unknown): TLUserPreferences {\n\tif (userData === null || typeof userData !== 'object') {\n\t\treturn getFreshUserPreferences()\n\t}\n\n\tif (!('version' in userData) || !('user' in userData) || typeof userData.version !== 'number') {\n\t\treturn getFreshUserPreferences()\n\t}\n\n\tconst snapshot = structuredClone(userData) as any\n\n\tmigrateSnapshot(snapshot)\n\n\ttry {\n\t\treturn userTypeValidator.validate(snapshot.user)\n\t} catch {\n\t\treturn getFreshUserPreferences()\n\t}\n}\n\nfunction loadUserPreferences(): TLUserPreferences {\n\tconst userData = (JSON.parse(getFromLocalStorage(USER_DATA_KEY) || 'null') ??\n\t\tnull) as null | UserDataSnapshot\n\n\treturn migrateUserPreferences(userData)\n}\n\nconst globalUserPreferences = atom<TLUserPreferences | null>('globalUserData', null)\n\nfunction storeUserPreferences() {\n\tsetInLocalStorage(\n\t\tUSER_DATA_KEY,\n\t\tJSON.stringify({\n\t\t\tversion: CURRENT_VERSION,\n\t\t\tuser: globalUserPreferences.get(),\n\t\t})\n\t)\n}\n\n/** @public */\nexport function setUserPreferences(user: TLUserPreferences) {\n\tuserTypeValidator.validate(user)\n\tglobalUserPreferences.set(user)\n\tstoreUserPreferences()\n\tbroadcastUserPreferencesChange()\n}\n\nconst isTest = typeof process !== 'undefined' && process.env.NODE_ENV === 'test'\n\nconst channel =\n\ttypeof BroadcastChannel !== 'undefined' && !isTest\n\t\t? new BroadcastChannel('tldraw-user-sync')\n\t\t: null\n\nchannel?.addEventListener('message', (e) => {\n\tconst data = e.data as undefined | UserChangeBroadcastMessage\n\tif (data?.type === broadcastEventKey && data?.origin !== getBroadcastOrigin()) {\n\t\tglobalUserPreferences.set(migrateUserPreferences(data.data))\n\t}\n})\n\nlet _broadcastOrigin = null as null | string\nfunction getBroadcastOrigin() {\n\tif (_broadcastOrigin === null) {\n\t\t_broadcastOrigin = uniqueId()\n\t}\n\treturn _broadcastOrigin\n}\nconst broadcastEventKey = 'tldraw-user-preferences-change' as const\n\nfunction broadcastUserPreferencesChange() {\n\tchannel?.postMessage({\n\t\ttype: broadcastEventKey,\n\t\torigin: getBroadcastOrigin(),\n\t\tdata: {\n\t\t\tuser: getUserPreferences(),\n\t\t\tversion: CURRENT_VERSION,\n\t\t},\n\t} satisfies UserChangeBroadcastMessage)\n}\n\n/** @public */\nexport function getUserPreferences(): TLUserPreferences {\n\tlet prefs = globalUserPreferences.get()\n\tif (!prefs) {\n\t\tprefs = loadUserPreferences()\n\t\tsetUserPreferences(prefs)\n\t}\n\treturn prefs\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY;AACrB,SAAS,mCAAmC;AAC5C,SAAS,qBAAqB,mBAAmB,iBAAiB,gBAAgB;AAClF,SAAS,SAAS;AAElB,MAAM,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import { atom } from '@tldraw/state'\nimport { getDefaultTranslationLocale } from '@tldraw/tlschema'\nimport { getFromLocalStorage, setInLocalStorage, structuredClone, uniqueId } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\n\nconst USER_DATA_KEY = 'TLDRAW_USER_DATA_v3'\n\n/**\n * A user of tldraw\n *\n * @public\n */\nexport interface TLUserPreferences {\n\tid: string\n\tname?: string | null\n\tcolor?: string | null\n\t// N.B. These are duplicated in TLdrawAppUser.\n\tlocale?: string | null\n\tanimationSpeed?: number | null\n\tareKeyboardShortcutsEnabled?: boolean | null\n\tedgeScrollSpeed?: number | null\n\tcolorScheme?: 'light' | 'dark' | 'system'\n\tisSnapMode?: boolean | null\n\tisWrapMode?: boolean | null\n\tisDynamicSizeMode?: boolean | null\n\tisPasteAtCursorMode?: boolean | null\n\tshowUiLabels?: boolean | null\n}\n\ninterface UserDataSnapshot {\n\tversion: number\n\tuser: TLUserPreferences\n}\n\ninterface UserChangeBroadcastMessage {\n\ttype: typeof broadcastEventKey\n\torigin: string\n\tdata: UserDataSnapshot\n}\n\n/** @public */\nexport const userTypeValidator: T.Validator<TLUserPreferences> = T.object<TLUserPreferences>({\n\tid: T.string,\n\tname: T.string.nullable().optional(),\n\tcolor: T.string.nullable().optional(),\n\t// N.B. These are duplicated in TLdrawAppUser.\n\tlocale: T.string.nullable().optional(),\n\tanimationSpeed: T.number.nullable().optional(),\n\tareKeyboardShortcutsEnabled: T.boolean.nullable().optional(),\n\tedgeScrollSpeed: T.number.nullable().optional(),\n\tcolorScheme: T.literalEnum('light', 'dark', 'system').optional(),\n\tisSnapMode: T.boolean.nullable().optional(),\n\tisWrapMode: T.boolean.nullable().optional(),\n\tisDynamicSizeMode: T.boolean.nullable().optional(),\n\tisPasteAtCursorMode: T.boolean.nullable().optional(),\n\tshowUiLabels: T.boolean.nullable().optional(),\n})\n\nconst Versions = {\n\tAddAnimationSpeed: 1,\n\tAddIsSnapMode: 2,\n\tMakeFieldsNullable: 3,\n\tAddEdgeScrollSpeed: 4,\n\tAddExcalidrawSelectMode: 5,\n\tAddDynamicSizeMode: 6,\n\tAllowSystemColorScheme: 7,\n\tAddPasteAtCursor: 8,\n\tAddKeyboardShortcuts: 9,\n\tAddShowUiLabels: 10,\n} as const\n\nconst CURRENT_VERSION = Math.max(...Object.values(Versions))\n\nfunction migrateSnapshot(data: { version: number; user: any }) {\n\tif (data.version < Versions.AddAnimationSpeed) {\n\t\tdata.user.animationSpeed = 1\n\t}\n\tif (data.version < Versions.AddIsSnapMode) {\n\t\tdata.user.isSnapMode = false\n\t}\n\tif (data.version < Versions.MakeFieldsNullable) {\n\t\t// noop\n\t}\n\tif (data.version < Versions.AddEdgeScrollSpeed) {\n\t\tdata.user.edgeScrollSpeed = 1\n\t}\n\tif (data.version < Versions.AddExcalidrawSelectMode) {\n\t\tdata.user.isWrapMode = false\n\t}\n\tif (data.version < Versions.AllowSystemColorScheme) {\n\t\tif (data.user.isDarkMode === true) {\n\t\t\tdata.user.colorScheme = 'dark'\n\t\t} else if (data.user.isDarkMode === false) {\n\t\t\tdata.user.colorScheme = 'light'\n\t\t}\n\t\tdelete data.user.isDarkMode\n\t}\n\n\tif (data.version < Versions.AddDynamicSizeMode) {\n\t\tdata.user.isDynamicSizeMode = false\n\t}\n\tif (data.version < Versions.AddPasteAtCursor) {\n\t\tdata.user.isPasteAtCursorMode = false\n\t}\n\tif (data.version < Versions.AddKeyboardShortcuts) {\n\t\tdata.user.areKeyboardShortcutsEnabled = true\n\t}\n\tif (data.version < Versions.AddShowUiLabels) {\n\t\tdata.user.showUiLabels = false\n\t}\n\n\t// finally\n\tdata.version = CURRENT_VERSION\n}\n\n/** @internal */\nexport const USER_COLORS = [\n\t'#FF802B',\n\t'#EC5E41',\n\t'#F2555A',\n\t'#F04F88',\n\t'#E34BA9',\n\t'#BD54C6',\n\t'#9D5BD2',\n\t'#7B66DC',\n\t'#02B1CC',\n\t'#11B3A3',\n\t'#39B178',\n\t'#55B467',\n] as const\n\nfunction getRandomColor() {\n\treturn USER_COLORS[Math.floor(Math.random() * USER_COLORS.length)]\n}\n\n/** @internal */\nexport function userPrefersReducedMotion() {\n\tif (typeof window !== 'undefined' && 'matchMedia' in window) {\n\t\treturn window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ?? false\n\t}\n\n\treturn false\n}\n\n/** @public */\nexport const defaultUserPreferences = Object.freeze({\n\tname: '',\n\tlocale: getDefaultTranslationLocale(),\n\tcolor: getRandomColor(),\n\n\t// N.B. These are duplicated in TLdrawAppUser.\n\tedgeScrollSpeed: 1,\n\tanimationSpeed: userPrefersReducedMotion() ? 0 : 1,\n\tareKeyboardShortcutsEnabled: true,\n\tisSnapMode: false,\n\tisWrapMode: false,\n\tisDynamicSizeMode: false,\n\tisPasteAtCursorMode: false,\n\tshowUiLabels: false,\n\tcolorScheme: 'light',\n}) satisfies Readonly<Omit<TLUserPreferences, 'id'>>\n\n/** @public */\nexport function getFreshUserPreferences(): TLUserPreferences {\n\treturn {\n\t\tid: uniqueId(),\n\t\tcolor: getRandomColor(),\n\t}\n}\n\nfunction migrateUserPreferences(userData: unknown): TLUserPreferences {\n\tif (userData === null || typeof userData !== 'object') {\n\t\treturn getFreshUserPreferences()\n\t}\n\n\tif (!('version' in userData) || !('user' in userData) || typeof userData.version !== 'number') {\n\t\treturn getFreshUserPreferences()\n\t}\n\n\tconst snapshot = structuredClone(userData) as any\n\n\tmigrateSnapshot(snapshot)\n\n\ttry {\n\t\treturn userTypeValidator.validate(snapshot.user)\n\t} catch {\n\t\treturn getFreshUserPreferences()\n\t}\n}\n\nfunction loadUserPreferences(): TLUserPreferences {\n\tconst userData = (JSON.parse(getFromLocalStorage(USER_DATA_KEY) || 'null') ??\n\t\tnull) as null | UserDataSnapshot\n\n\treturn migrateUserPreferences(userData)\n}\n\nconst globalUserPreferences = atom<TLUserPreferences | null>('globalUserData', null)\n\nfunction storeUserPreferences() {\n\tsetInLocalStorage(\n\t\tUSER_DATA_KEY,\n\t\tJSON.stringify({\n\t\t\tversion: CURRENT_VERSION,\n\t\t\tuser: globalUserPreferences.get(),\n\t\t})\n\t)\n}\n\n/** @public */\nexport function setUserPreferences(user: TLUserPreferences) {\n\tuserTypeValidator.validate(user)\n\tglobalUserPreferences.set(user)\n\tstoreUserPreferences()\n\tbroadcastUserPreferencesChange()\n}\n\nconst isTest = typeof process !== 'undefined' && process.env.NODE_ENV === 'test'\n\nconst channel =\n\ttypeof BroadcastChannel !== 'undefined' && !isTest\n\t\t? new BroadcastChannel('tldraw-user-sync')\n\t\t: null\n\nchannel?.addEventListener('message', (e) => {\n\tconst data = e.data as undefined | UserChangeBroadcastMessage\n\tif (data?.type === broadcastEventKey && data?.origin !== getBroadcastOrigin()) {\n\t\tglobalUserPreferences.set(migrateUserPreferences(data.data))\n\t}\n})\n\nlet _broadcastOrigin = null as null | string\nfunction getBroadcastOrigin() {\n\tif (_broadcastOrigin === null) {\n\t\t_broadcastOrigin = uniqueId()\n\t}\n\treturn _broadcastOrigin\n}\nconst broadcastEventKey = 'tldraw-user-preferences-change' as const\n\nfunction broadcastUserPreferencesChange() {\n\tchannel?.postMessage({\n\t\ttype: broadcastEventKey,\n\t\torigin: getBroadcastOrigin(),\n\t\tdata: {\n\t\t\tuser: getUserPreferences(),\n\t\t\tversion: CURRENT_VERSION,\n\t\t},\n\t} satisfies UserChangeBroadcastMessage)\n}\n\n/** @public */\nexport function getUserPreferences(): TLUserPreferences {\n\tlet prefs = globalUserPreferences.get()\n\tif (!prefs) {\n\t\tprefs = loadUserPreferences()\n\t\tsetUserPreferences(prefs)\n\t}\n\treturn prefs\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3944,6 +3944,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
|
|
|
3944
3944
|
hitInside = false,
|
|
3945
3945
|
hitFrameInside = false
|
|
3946
3946
|
} = opts;
|
|
3947
|
+
const [innerMargin, outerMargin] = Array.isArray(margin) ? margin : [margin, margin];
|
|
3947
3948
|
let inHollowSmallestArea = Infinity;
|
|
3948
3949
|
let inHollowSmallestAreaHit = null;
|
|
3949
3950
|
let inMarginClosestToEdgeDistance = Infinity;
|
|
@@ -3953,7 +3954,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
|
|
|
3953
3954
|
return false;
|
|
3954
3955
|
const pageMask = this.getShapeMask(shape);
|
|
3955
3956
|
if (pageMask && !pointInPolygon(point, pageMask)) return false;
|
|
3956
|
-
if (filter
|
|
3957
|
+
if (filter && !filter(shape)) return false;
|
|
3957
3958
|
return true;
|
|
3958
3959
|
});
|
|
3959
3960
|
for (let i = shapesToCheck.length - 1; i >= 0; i--) {
|
|
@@ -3969,8 +3970,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
|
|
|
3969
3970
|
}
|
|
3970
3971
|
}
|
|
3971
3972
|
if (this.isShapeOfType(shape, "frame")) {
|
|
3972
|
-
const distance2 = geometry.distanceToPoint(pointInShapeSpace,
|
|
3973
|
-
if (
|
|
3973
|
+
const distance2 = geometry.distanceToPoint(pointInShapeSpace, hitFrameInside);
|
|
3974
|
+
if (hitFrameInside ? distance2 > 0 && distance2 <= outerMargin || distance2 <= 0 && distance2 > -innerMargin : distance2 > 0 && distance2 <= outerMargin) {
|
|
3974
3975
|
return inMarginClosestToEdgeHit || shape;
|
|
3975
3976
|
}
|
|
3976
3977
|
if (geometry.hitTestPoint(pointInShapeSpace, 0, true)) {
|
|
@@ -3990,10 +3991,10 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
|
|
|
3990
3991
|
}
|
|
3991
3992
|
distance = minDistance;
|
|
3992
3993
|
} else {
|
|
3993
|
-
if (
|
|
3994
|
+
if (outerMargin === 0 && (geometry.bounds.w < 1 || geometry.bounds.h < 1)) {
|
|
3994
3995
|
distance = geometry.distanceToPoint(pointInShapeSpace, hitInside);
|
|
3995
3996
|
} else {
|
|
3996
|
-
if (geometry.bounds.containsPoint(pointInShapeSpace,
|
|
3997
|
+
if (geometry.bounds.containsPoint(pointInShapeSpace, outerMargin)) {
|
|
3997
3998
|
distance = geometry.distanceToPoint(pointInShapeSpace, hitInside);
|
|
3998
3999
|
} else {
|
|
3999
4000
|
distance = Infinity;
|
|
@@ -4001,12 +4002,22 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
|
|
|
4001
4002
|
}
|
|
4002
4003
|
}
|
|
4003
4004
|
if (geometry.isClosed) {
|
|
4004
|
-
if (distance <=
|
|
4005
|
+
if (distance <= outerMargin || hitInside && distance <= 0 && distance > -innerMargin) {
|
|
4005
4006
|
if (geometry.isFilled || isGroup && geometry.children[0].isFilled) {
|
|
4006
4007
|
return inMarginClosestToEdgeHit || shape;
|
|
4007
4008
|
} else {
|
|
4008
4009
|
if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
|
|
4009
|
-
if (
|
|
4010
|
+
if (hitInside ? (
|
|
4011
|
+
// On hitInside, the distance will be negative for hits inside
|
|
4012
|
+
// If the distance is positive, check against the outer margin
|
|
4013
|
+
(// If the distance is negative, check against the inner margin
|
|
4014
|
+
distance > 0 && distance <= outerMargin || distance <= 0 && distance > -innerMargin)
|
|
4015
|
+
) : (
|
|
4016
|
+
// If hitInside is false, then sadly _we do not know_ whether the
|
|
4017
|
+
// point is inside or outside of the shape, so we check against
|
|
4018
|
+
// the max of the two margins
|
|
4019
|
+
(Math.abs(distance) <= Math.max(innerMargin, outerMargin))
|
|
4020
|
+
)) {
|
|
4010
4021
|
if (Math.abs(distance) < inMarginClosestToEdgeDistance) {
|
|
4011
4022
|
inMarginClosestToEdgeDistance = Math.abs(distance);
|
|
4012
4023
|
inMarginClosestToEdgeHit = shape;
|
|
@@ -5525,8 +5536,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
|
|
|
5525
5536
|
const shapesMovingTogether = [shape];
|
|
5526
5537
|
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5527
5538
|
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5528
|
-
type: "stretch"
|
|
5529
|
-
shapes: shapesToStretchFirstPass
|
|
5539
|
+
type: "stretch"
|
|
5530
5540
|
})) {
|
|
5531
5541
|
continue;
|
|
5532
5542
|
}
|