tldraw 5.2.0-next.e2b8d10bf10e → 5.2.0
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/DOCS.md +20294 -0
- package/README.md +13 -1
- package/RELEASE_NOTES.md +2908 -0
- package/dist-cjs/index.d.ts +110 -23
- package/dist-cjs/index.js +3 -3
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawImage.js +0 -1
- package/dist-cjs/lib/TldrawImage.js.map +2 -2
- package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js +2 -1
- package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js +3 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
- package/dist-cjs/lib/defaultOverlayUtils.js +11 -11
- package/dist-cjs/lib/defaultOverlayUtils.js.map +2 -2
- package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js +76 -64
- package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js.map +2 -2
- package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js +1 -1
- package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js.map +2 -2
- package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js +107 -0
- package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +12 -3
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js +54 -6
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/getPath.js +1 -1
- package/dist-cjs/lib/shapes/draw/getPath.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +45 -47
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeTool.js +23 -18
- package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -1
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +11 -7
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -11
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +5 -1
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +31 -41
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/noteHelpers.js +1 -1
- package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +28 -6
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +3 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js +3 -3
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js +17 -3
- package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/core.js +424 -0
- package/dist-cjs/lib/shapes/shared/freehand/core.js.map +7 -0
- package/dist-cjs/lib/shapes/shared/freehand/fmt.js +106 -0
- package/dist-cjs/lib/shapes/shared/freehand/fmt.js.map +7 -0
- package/dist-cjs/lib/shapes/shared/freehand/getStroke.js +6 -6
- package/dist-cjs/lib/shapes/shared/freehand/getStroke.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js +320 -86
- package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js +20 -96
- package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/svg.js +55 -19
- package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/svgInk.js +189 -97
- package/dist-cjs/lib/shapes/shared/freehand/svgInk.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/types.js.map +1 -1
- package/dist-cjs/lib/shapes/shared/interpolate-props.js +6 -2
- package/dist-cjs/lib/shapes/shared/interpolate-props.js.map +2 -2
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/HandTool.js +16 -6
- package/dist-cjs/lib/tools/HandTool/HandTool.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js +10 -1
- package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +84 -0
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +7 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +12 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +4 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +107 -46
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +4 -3
- package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
- package/dist-cjs/lib/ui/components/A11y.js +2 -0
- package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +14 -1
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js +0 -6
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +2 -2
- package/dist-cjs/lib/ui/components/Dialogs.js +17 -37
- package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
- package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js +19 -4
- package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +12 -2
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +47 -70
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +25 -46
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js +1 -1
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +1 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js +7 -0
- package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js +2 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js +14 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +0 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js +1 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +70 -1
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/asset-urls.js +5 -8
- package/dist-cjs/lib/ui/context/asset-urls.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +13 -0
- package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
- package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +2 -0
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-cjs/lib/utils/embeds/embeds.js +4 -4
- package/dist-cjs/lib/utils/embeds/embeds.js.map +2 -2
- package/dist-cjs/lib/utils/test-helpers.js +2 -2
- package/dist-cjs/lib/utils/test-helpers.js.map +2 -2
- package/dist-cjs/lib/utils/text/richText.js +3 -1
- package/dist-cjs/lib/utils/text/richText.js.map +2 -2
- package/dist-esm/index.d.mts +110 -23
- package/dist-esm/index.mjs +5 -3
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawImage.mjs +0 -1
- package/dist-esm/lib/TldrawImage.mjs.map +2 -2
- package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs +2 -1
- package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs +3 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
- package/dist-esm/lib/defaultOverlayUtils.mjs +11 -11
- package/dist-esm/lib/defaultOverlayUtils.mjs.map +2 -2
- package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs +77 -65
- package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs.map +2 -2
- package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs +1 -1
- package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs.map +2 -2
- package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs +87 -0
- package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +9 -1
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +15 -3
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs +54 -6
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +3 -1
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/getPath.mjs +1 -1
- package/dist-esm/lib/shapes/draw/getPath.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +46 -47
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs +23 -18
- package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +4 -0
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +12 -7
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -11
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +6 -1
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +32 -42
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/noteHelpers.mjs +1 -1
- package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +29 -6
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +3 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +4 -3
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs +17 -3
- package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/core.mjs +404 -0
- package/dist-esm/lib/shapes/shared/freehand/core.mjs.map +7 -0
- package/dist-esm/lib/shapes/shared/freehand/fmt.mjs +86 -0
- package/dist-esm/lib/shapes/shared/freehand/fmt.mjs.map +7 -0
- package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs +7 -7
- package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs +332 -86
- package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs +31 -96
- package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs +55 -19
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs +214 -99
- package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/interpolate-props.mjs +6 -2
- package/dist-esm/lib/shapes/shared/interpolate-props.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +4 -0
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/HandTool.mjs +16 -6
- package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs +10 -1
- package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +64 -0
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +7 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +12 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +4 -0
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +108 -46
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +4 -3
- package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
- package/dist-esm/lib/ui/components/A11y.mjs +2 -0
- package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +21 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs +0 -6
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Dialogs.mjs +19 -39
- package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
- package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs +20 -5
- package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +12 -2
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +47 -70
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +25 -46
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs +1 -1
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +1 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs +7 -0
- package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs +14 -3
- package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +0 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs +1 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +71 -1
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/asset-urls.mjs +5 -8
- package/dist-esm/lib/ui/context/asset-urls.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs +13 -0
- package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +2 -0
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/dist-esm/lib/utils/embeds/embeds.mjs +4 -4
- package/dist-esm/lib/utils/embeds/embeds.mjs.map +2 -2
- package/dist-esm/lib/utils/test-helpers.mjs +2 -2
- package/dist-esm/lib/utils/test-helpers.mjs.map +2 -2
- package/dist-esm/lib/utils/text/richText.mjs +3 -1
- package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
- package/package.json +11 -6
- package/src/index.ts +6 -1
- package/src/lib/TldrawImage.tsx +2 -2
- package/src/lib/bindings/arrow/ArrowBindingUtil.ts +5 -1
- package/src/lib/defaultEmbedDefinitions.ts +28 -6
- package/src/lib/defaultOverlayUtils.ts +11 -11
- package/src/lib/overlays/SelectionForegroundOverlayUtil.ts +91 -72
- package/src/lib/overlays/ShapeHandleOverlayUtil.ts +3 -1
- package/src/lib/overlays/ShapeIndicatorOverlayUtil.ts +133 -0
- package/src/lib/shapes/arrow/toolStates/Pointing.tsx +11 -1
- package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +16 -3
- package/src/lib/shapes/bookmark/bookmarks.ts +105 -15
- package/src/lib/shapes/draw/DrawShapeUtil.tsx +7 -5
- package/src/lib/shapes/draw/getPath.ts +1 -1
- package/src/lib/shapes/draw/toolStates/Drawing.ts +55 -48
- package/src/lib/shapes/embed/EmbedShapeUtil.tsx +14 -4
- package/src/lib/shapes/frame/FrameShapeTool.ts +35 -24
- package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +46 -0
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +2 -1
- package/src/lib/shapes/geo/toolStates/Pointing.ts +5 -0
- package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +14 -11
- package/src/lib/shapes/image/ImageShapeUtil.tsx +7 -11
- package/src/lib/shapes/line/LineShapeTool.test.ts +41 -0
- package/src/lib/shapes/line/toolStates/Pointing.ts +12 -2
- package/src/lib/shapes/note/NoteShapeUtil.tsx +36 -51
- package/src/lib/shapes/note/noteCloning.test.ts +5 -5
- package/src/lib/shapes/note/noteHelpers.ts +1 -1
- package/src/lib/shapes/note/toolStates/Pointing.ts +40 -7
- package/src/lib/shapes/shared/PlainTextLabel.tsx +3 -3
- package/src/lib/shapes/shared/RichTextLabel.tsx +4 -3
- package/src/lib/shapes/shared/defaultStyleDefs.tsx +25 -3
- package/src/lib/shapes/shared/freehand/core.ts +547 -0
- package/src/lib/shapes/shared/freehand/fmt.ts +106 -0
- package/src/lib/shapes/shared/freehand/getStroke.ts +7 -7
- package/src/lib/shapes/shared/freehand/getStrokeOutlinePoints.ts +451 -139
- package/src/lib/shapes/shared/freehand/getStrokePoints.ts +33 -153
- package/src/lib/shapes/shared/freehand/svg.ts +72 -23
- package/src/lib/shapes/shared/freehand/svgInk.ts +281 -136
- package/src/lib/shapes/shared/freehand/types.ts +0 -1
- package/src/lib/shapes/shared/interpolate-props.ts +6 -2
- package/src/lib/shapes/text/toolStates/Pointing.ts +5 -0
- package/src/lib/tools/HandTool/HandTool.ts +19 -6
- package/src/lib/tools/HandTool/childStates/Dragging.ts +17 -1
- package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +79 -0
- package/src/lib/tools/SelectTool/childStates/Idle.ts +16 -2
- package/src/lib/tools/SelectTool/childStates/PointingShape.ts +8 -0
- package/src/lib/tools/SelectTool/childStates/Resizing.ts +137 -49
- package/src/lib/ui/TldrawUi.tsx +3 -3
- package/src/lib/ui/components/A11y.tsx +2 -0
- package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +32 -2
- package/src/lib/ui/components/ContextMenu/DefaultContextMenuContent.tsx +5 -6
- package/src/lib/ui/components/DefaultFollowingIndicator.tsx +2 -2
- package/src/lib/ui/components/Dialogs.tsx +20 -23
- package/src/lib/ui/components/HelperButtons/BackToContent.tsx +32 -4
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +10 -0
- package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +60 -74
- package/src/lib/ui/components/Minimap/MinimapManager.ts +35 -57
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.tsx +2 -2
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuContent.tsx +2 -1
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.tsx +2 -1
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuItem.tsx +3 -3
- package/src/lib/ui/components/StylePanel/StylePanelButtonPicker.tsx +5 -0
- package/src/lib/ui/components/menu-items.tsx +9 -0
- package/src/lib/ui/components/primitives/TldrawUiDropdownMenu.tsx +3 -1
- package/src/lib/ui/components/primitives/TldrawUiIcon.tsx +15 -3
- package/src/lib/ui/components/primitives/TldrawUiInput.tsx +4 -0
- package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +7 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +0 -2
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.tsx +0 -1
- package/src/lib/ui/context/actions.tsx +88 -1
- package/src/lib/ui/context/asset-urls.tsx +9 -8
- package/src/lib/ui/context/events.tsx +2 -0
- package/src/lib/ui/hooks/useKeyboardShortcuts.ts +45 -7
- package/src/lib/ui/hooks/useTools.tsx +7 -1
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +2 -0
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +20 -9
- package/src/lib/utils/embeds/embeds.test.ts +14 -12
- package/src/lib/utils/embeds/embeds.ts +10 -4
- package/src/lib/utils/test-helpers.ts +3 -3
- package/src/lib/utils/text/richText.test.ts +36 -0
- package/src/lib/utils/text/richText.ts +9 -1
- package/src/test/HandTool.test.ts +93 -0
- package/src/test/ImageShapeUtil.test.ts +88 -0
- package/src/test/SelectTool.test.ts +102 -1
- package/src/test/__snapshots__/drawing.test.ts.snap +2 -1
- package/src/test/attribution.test.ts +40 -29
- package/src/test/bookmark-shapes.test.ts +256 -28
- package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +2 -2
- package/src/test/commands/clipboardCallbacks.test.ts +3 -1
- package/src/test/commands/getSvgString.test.ts +30 -0
- package/src/test/commands/penmode.test.ts +97 -1
- package/src/test/commands/setCamera.test.ts +12 -0
- package/src/test/dragFromToolbar.test.ts +67 -0
- package/src/test/drawing.test.ts +48 -7
- package/src/test/frames.test.ts +72 -0
- package/src/test/freehand/corpus/presets.ts +71 -0
- package/src/test/freehand/corpus/real.ts +370 -0
- package/src/test/freehand/corpus/strokes.ts +50 -0
- package/src/test/freehand/svg.test.ts +20 -0
- package/src/test/freehand/wellformed.test.ts +30 -0
- package/src/test/long-press-create.test.ts +102 -0
- package/src/test/overlays/CollaboratorBrushOverlayUtil.test.ts +4 -4
- package/src/test/overlays/CollaboratorCursorOverlayUtil.test.ts +18 -18
- package/src/test/overlays/CollaboratorHintOverlayUtil.test.ts +7 -7
- package/src/test/overlays/CollaboratorScribbleOverlayUtil.test.ts +3 -3
- package/src/test/overlays/OverlayManager.test.ts +1 -1
- package/src/test/overlays/SelectionForegroundOverlayUtil.test.ts +58 -0
- package/src/test/overlays/ShapeHandleOverlayUtil.test.ts +2 -2
- package/src/test/overlays/ShapeIndicatorOverlayUtil.test.ts +36 -0
- package/src/test/resizing.test.ts +250 -0
- package/src/test/right-click-context-menu.test.ts +90 -0
- package/src/test/rightClickPanning.test.ts +11 -0
- package/src/test/selection-omnibus.test.ts +15 -2
- package/src/test/spatialIndex.test.ts +132 -0
- package/src/test/translating.test.ts +0 -6
- package/src/test/ui/ContextMenu.test.tsx +146 -3
- package/src/test/ui/Dialogs.test.tsx +256 -0
- package/src/test/ui/copyHoveredStyles.test.tsx +154 -0
- package/src/test/ui/keyboardShortcuts.test.tsx +266 -0
- package/tldraw.css +35 -12
- package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js +0 -100
- package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js.map +0 -7
- package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs +0 -80
- package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs.map +0 -7
- package/src/lib/shapes/shared/freehand/setStrokePointRadii.ts +0 -127
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { act } from '@testing-library/react'
|
|
2
|
+
import { createShapeId, Editor } from '@tldraw/editor'
|
|
3
|
+
import { useEffect } from 'react'
|
|
4
|
+
import { Tldraw } from '../../lib/Tldraw'
|
|
5
|
+
import { DefaultKeyboardShortcutsDialogContent } from '../../lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent'
|
|
6
|
+
import { TldrawUiMenuContextProvider } from '../../lib/ui/components/primitives/menus/TldrawUiMenuContext'
|
|
7
|
+
import { useActions } from '../../lib/ui/context/actions'
|
|
8
|
+
import {
|
|
9
|
+
getHotkeysStringFromKbd,
|
|
10
|
+
ParsedKbd,
|
|
11
|
+
parseKbd,
|
|
12
|
+
} from '../../lib/ui/hooks/useKeyboardShortcuts'
|
|
13
|
+
import { useTools } from '../../lib/ui/hooks/useTools'
|
|
14
|
+
import {
|
|
15
|
+
renderTldrawComponent,
|
|
16
|
+
renderTldrawComponentWithEditor,
|
|
17
|
+
} from '../testutils/renderTldrawComponent'
|
|
18
|
+
|
|
19
|
+
// These kbds are intentionally not registered in the shortcut registry, they're handled by
|
|
20
|
+
// useNativeClipboardEvents / the upload asset action instead. See SKIP_KBDS in useKeyboardShortcuts.
|
|
21
|
+
const SKIP_KBDS = ['copy', 'cut', 'paste', 'asset']
|
|
22
|
+
|
|
23
|
+
// Shortcuts that have a kbd but intentionally don't get their own row in the default keyboard
|
|
24
|
+
// shortcuts dialog. If you add a shortcut that should be visible to users, add it to
|
|
25
|
+
// DefaultKeyboardShortcutsDialogContent instead of this list.
|
|
26
|
+
const NOT_IN_SHORTCUTS_DIALOG = new Set([
|
|
27
|
+
// Opening the shortcuts dialog is covered by the a11y "Open keyboard shortcuts" row.
|
|
28
|
+
'open-kbd-shortcuts',
|
|
29
|
+
// Covered by the a11y "Open context menu" row.
|
|
30
|
+
'a11y-open-context-menu',
|
|
31
|
+
// Cursor-targeted variants of zoom in/out that share a label with the rows already shown.
|
|
32
|
+
'zoom-in-on-cursor',
|
|
33
|
+
'zoom-out-on-cursor',
|
|
34
|
+
// Rotation is covered by the a11y "Rotate shape" rows.
|
|
35
|
+
'rotate-cw',
|
|
36
|
+
'rotate-ccw',
|
|
37
|
+
// Cursor-targeted paste variants of the paste row already shown.
|
|
38
|
+
'paste-at-cursor',
|
|
39
|
+
'paste-plain-text-at-cursor',
|
|
40
|
+
// Style-picking shortcuts that aren't surfaced in the dialog.
|
|
41
|
+
'select-white-color',
|
|
42
|
+
'select-fill-fill',
|
|
43
|
+
'select-fill-lined-fill',
|
|
44
|
+
// Re-selects the last geo tool; covered by the rectangle/ellipse tool rows.
|
|
45
|
+
'select-geo-tool',
|
|
46
|
+
// Page navigation shortcuts without dialog labels.
|
|
47
|
+
'change-page-prev',
|
|
48
|
+
'change-page-next',
|
|
49
|
+
// Only rendered when collaboration UI is enabled, which is off in this test.
|
|
50
|
+
'open-cursor-chat',
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
interface ShortcutEntry {
|
|
54
|
+
id: string
|
|
55
|
+
kbd: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function serializeParsedKbd(parsed: ParsedKbd): string {
|
|
59
|
+
const modifiers: string[] = []
|
|
60
|
+
if (parsed.meta) modifiers.push('meta')
|
|
61
|
+
if (parsed.ctrl) modifiers.push('ctrl')
|
|
62
|
+
if (parsed.alt) modifiers.push('alt')
|
|
63
|
+
if (parsed.shift) modifiers.push('shift')
|
|
64
|
+
return [...modifiers, parsed.key].join('+')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getKbdKeyCombos(kbd: string): string[] {
|
|
68
|
+
return parseKbd(getHotkeysStringFromKbd(kbd)).map(serializeParsedKbd)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function ShortcutCapturer({ onCapture }: { onCapture(entries: ShortcutEntry[]): void }) {
|
|
72
|
+
const actions = useActions()
|
|
73
|
+
const tools = useTools()
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
const entries: ShortcutEntry[] = []
|
|
77
|
+
for (const action of Object.values(actions)) {
|
|
78
|
+
if (!action.kbd || SKIP_KBDS.includes(action.id)) continue
|
|
79
|
+
entries.push({ id: `action.${action.id}`, kbd: action.kbd })
|
|
80
|
+
}
|
|
81
|
+
for (const tool of Object.values(tools)) {
|
|
82
|
+
if (!tool.kbd || SKIP_KBDS.includes(tool.id)) continue
|
|
83
|
+
entries.push({ id: `tool.${tool.id}`, kbd: tool.kbd })
|
|
84
|
+
}
|
|
85
|
+
onCapture(entries)
|
|
86
|
+
}, [actions, tools, onCapture])
|
|
87
|
+
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function getDefaultShortcutEntries() {
|
|
92
|
+
let captured: ShortcutEntry[] = []
|
|
93
|
+
await renderTldrawComponent(
|
|
94
|
+
<Tldraw>
|
|
95
|
+
<ShortcutCapturer onCapture={(entries) => (captured = entries)} />
|
|
96
|
+
</Tldraw>,
|
|
97
|
+
{ waitForPatterns: false }
|
|
98
|
+
)
|
|
99
|
+
return captured
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
describe('default keyboard shortcuts', () => {
|
|
103
|
+
it('does not bind the same key combo to more than one action or tool', async () => {
|
|
104
|
+
const entries = await getDefaultShortcutEntries()
|
|
105
|
+
|
|
106
|
+
// Sanity check: we actually captured the default actions/tools.
|
|
107
|
+
expect(entries.length).toBeGreaterThan(0)
|
|
108
|
+
|
|
109
|
+
const comboToIds = new Map<string, string[]>()
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
for (const combo of getKbdKeyCombos(entry.kbd)) {
|
|
112
|
+
const ids = comboToIds.get(combo) ?? []
|
|
113
|
+
ids.push(entry.id)
|
|
114
|
+
comboToIds.set(combo, ids)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const collisions = [...comboToIds.entries()]
|
|
119
|
+
.filter(([, ids]) => ids.length > 1)
|
|
120
|
+
.map(([combo, ids]) => `${combo} -> ${ids.join(', ')}`)
|
|
121
|
+
|
|
122
|
+
expect(collisions).toEqual([])
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('lists every shortcut in the keyboard shortcuts dialog (or marks it as intentionally omitted)', async () => {
|
|
126
|
+
let entries: ShortcutEntry[] = []
|
|
127
|
+
const rendered = await renderTldrawComponent(
|
|
128
|
+
<Tldraw>
|
|
129
|
+
<ShortcutCapturer onCapture={(captured) => (entries = captured)} />
|
|
130
|
+
<TldrawUiMenuContextProvider type="keyboard-shortcuts" sourceId="kbd">
|
|
131
|
+
<DefaultKeyboardShortcutsDialogContent />
|
|
132
|
+
</TldrawUiMenuContextProvider>
|
|
133
|
+
</Tldraw>,
|
|
134
|
+
{ waitForPatterns: false }
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
// The raw ids (without the `action.`/`tool.` prefix) rendered as rows in the dialog.
|
|
138
|
+
const idsInDialog = new Set(
|
|
139
|
+
[...rendered.container.querySelectorAll('[data-testid^="kbd."]')].map((el) =>
|
|
140
|
+
el.getAttribute('data-testid')!.slice('kbd.'.length)
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
expect(idsInDialog.size).toBeGreaterThan(0)
|
|
144
|
+
|
|
145
|
+
const missing = entries
|
|
146
|
+
.map((entry) => entry.id.replace(/^(action|tool)\./, ''))
|
|
147
|
+
.filter((id) => !idsInDialog.has(id) && !NOT_IN_SHORTCUTS_DIALOG.has(id))
|
|
148
|
+
|
|
149
|
+
expect(missing).toEqual([])
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
async function setupFocusedEditor() {
|
|
154
|
+
const { editor } = await renderTldrawComponentWithEditor(
|
|
155
|
+
(onMount) => <Tldraw onMount={onMount} />,
|
|
156
|
+
{ waitForPatterns: false }
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
// Shortcuts only register while the editor is focused.
|
|
160
|
+
act(() => {
|
|
161
|
+
editor.updateInstanceState({ isFocused: true })
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return { editor }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function keydown(editor: Editor, init: KeyboardEventInit) {
|
|
168
|
+
act(() => {
|
|
169
|
+
editor
|
|
170
|
+
.getContainerDocument()
|
|
171
|
+
.body.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, ...init }))
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function keyup(editor: Editor, init: KeyboardEventInit) {
|
|
176
|
+
act(() => {
|
|
177
|
+
editor
|
|
178
|
+
.getContainerDocument()
|
|
179
|
+
.body.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, ...init }))
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
describe('keyboard shortcuts with a held key', () => {
|
|
184
|
+
it('fires the plain shortcut on a fresh key press', async () => {
|
|
185
|
+
const { editor } = await setupFocusedEditor()
|
|
186
|
+
expect(editor.getInstanceState().isToolLocked).toBe(false)
|
|
187
|
+
|
|
188
|
+
// Plain `q` toggles tool lock.
|
|
189
|
+
keydown(editor, { key: 'q', code: 'KeyQ' })
|
|
190
|
+
expect(editor.getInstanceState().isToolLocked).toBe(true)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('does not fall back to the plain shortcut when a modifier is released mid-hold', async () => {
|
|
194
|
+
const { editor } = await setupFocusedEditor()
|
|
195
|
+
expect(editor.getInstanceState().isToolLocked).toBe(false)
|
|
196
|
+
|
|
197
|
+
// Press shift+q (copy-hovered-styles), which does not toggle tool lock.
|
|
198
|
+
keydown(editor, { key: 'q', code: 'KeyQ', shiftKey: true })
|
|
199
|
+
expect(editor.getInstanceState().isToolLocked).toBe(false)
|
|
200
|
+
|
|
201
|
+
// Release shift but keep holding q. The auto-repeat keydown events should not start
|
|
202
|
+
// firing the adjacent plain `q` shortcut (toggle tool lock).
|
|
203
|
+
keydown(editor, { key: 'q', code: 'KeyQ', shiftKey: false, repeat: true })
|
|
204
|
+
keydown(editor, { key: 'q', code: 'KeyQ', shiftKey: false, repeat: true })
|
|
205
|
+
expect(editor.getInstanceState().isToolLocked).toBe(false)
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('fires the plain shortcut again after the held key is released and pressed fresh', async () => {
|
|
209
|
+
const { editor } = await setupFocusedEditor()
|
|
210
|
+
|
|
211
|
+
keydown(editor, { key: 'q', code: 'KeyQ', shiftKey: true })
|
|
212
|
+
keydown(editor, { key: 'q', code: 'KeyQ', shiftKey: false, repeat: true })
|
|
213
|
+
expect(editor.getInstanceState().isToolLocked).toBe(false)
|
|
214
|
+
|
|
215
|
+
// Releasing the physical key clears the held-key tracking, so a fresh press works again.
|
|
216
|
+
keyup(editor, { key: 'q', code: 'KeyQ' })
|
|
217
|
+
keydown(editor, { key: 'q', code: 'KeyQ' })
|
|
218
|
+
expect(editor.getInstanceState().isToolLocked).toBe(true)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('releases the held key even when the keyup lands on a text input', async () => {
|
|
222
|
+
const { editor } = await setupFocusedEditor()
|
|
223
|
+
|
|
224
|
+
keydown(editor, { key: 'q', code: 'KeyQ', shiftKey: true })
|
|
225
|
+
expect(editor.getInstanceState().isToolLocked).toBe(false)
|
|
226
|
+
|
|
227
|
+
// The key is released while focus is inside a text input, so the keyup is otherwise
|
|
228
|
+
// skipped. It must still clear the held-key tracking.
|
|
229
|
+
const body = editor.getContainerDocument().body
|
|
230
|
+
const input = editor.getContainerDocument().createElement('input')
|
|
231
|
+
body.appendChild(input)
|
|
232
|
+
act(() => {
|
|
233
|
+
input.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, key: 'q', code: 'KeyQ' }))
|
|
234
|
+
})
|
|
235
|
+
body.removeChild(input)
|
|
236
|
+
|
|
237
|
+
// A fresh plain `q` press now works rather than being blocked by a stale entry.
|
|
238
|
+
keydown(editor, { key: 'q', code: 'KeyQ' })
|
|
239
|
+
expect(editor.getInstanceState().isToolLocked).toBe(true)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
// Regression test for #9099: redo (cmd+shift+z) stopped firing after an undo (cmd+z) on
|
|
243
|
+
// macOS, where the browser swallows the `z` keyup while cmd stays held. The held-key
|
|
244
|
+
// tracking from #9099 never got cleared, so the stale undo registration blocked the redo
|
|
245
|
+
// on the same physical `KeyZ`. A fresh keypress must always be free to trigger its match.
|
|
246
|
+
it('fires redo after undo on the same physical key when the keyup is swallowed (cmd held)', async () => {
|
|
247
|
+
const { editor } = await setupFocusedEditor()
|
|
248
|
+
|
|
249
|
+
const id = createShapeId()
|
|
250
|
+
act(() => {
|
|
251
|
+
editor.markHistoryStoppingPoint()
|
|
252
|
+
editor.createShape({ id, type: 'geo', x: 0, y: 0 })
|
|
253
|
+
})
|
|
254
|
+
expect(editor.getCurrentPageShapeIds().has(id)).toBe(true)
|
|
255
|
+
|
|
256
|
+
// cmd+z undoes the shape creation. On macOS the `z` keyup is never delivered while cmd
|
|
257
|
+
// stays held, so we deliberately don't dispatch it.
|
|
258
|
+
keydown(editor, { key: 'z', code: 'KeyZ', metaKey: true })
|
|
259
|
+
expect(editor.getCurrentPageShapeIds().has(id)).toBe(false)
|
|
260
|
+
|
|
261
|
+
// Adding shift and pressing z again is a fresh keypress (not an auto-repeat), so it must
|
|
262
|
+
// trigger redo rather than being blocked by the stale undo registration on `KeyZ`.
|
|
263
|
+
keydown(editor, { key: 'z', code: 'KeyZ', metaKey: true, shiftKey: true })
|
|
264
|
+
expect(editor.getCurrentPageShapeIds().has(id)).toBe(true)
|
|
265
|
+
})
|
|
266
|
+
})
|
package/tldraw.css
CHANGED
|
@@ -186,6 +186,7 @@
|
|
|
186
186
|
--tl-color-text-0: hsl(0, 0%, 11%);
|
|
187
187
|
--tl-color-text-1: hsl(0, 0%, 18%);
|
|
188
188
|
--tl-color-text-3: hsl(204, 4%, 45%);
|
|
189
|
+
--tl-color-text-disabled: hsl(204, 4%, 55%);
|
|
189
190
|
--tl-color-text-shadow: hsl(0, 0%, 100%);
|
|
190
191
|
--tl-color-text-highlight: hsl(52, 100%, 50%);
|
|
191
192
|
--tl-color-text-highlight-p3: color(display-p3 0.972 0.8205 0.05);
|
|
@@ -240,6 +241,7 @@
|
|
|
240
241
|
--tl-color-text-0: hsl(0, 9%, 94%);
|
|
241
242
|
--tl-color-text-1: hsl(0, 0%, 85%);
|
|
242
243
|
--tl-color-text-3: hsl(204, 4%, 75%);
|
|
244
|
+
--tl-color-text-disabled: hsl(204, 4%, 50%);
|
|
243
245
|
--tl-color-text-shadow: hsl(210, 13%, 18%);
|
|
244
246
|
--tl-color-text-highlight: hsl(52, 100%, 41%);
|
|
245
247
|
--tl-color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
|
|
@@ -766,17 +768,17 @@ input,
|
|
|
766
768
|
.tl-rich-text ol {
|
|
767
769
|
text-align: left;
|
|
768
770
|
margin: 0;
|
|
769
|
-
padding-left:
|
|
771
|
+
padding-left: 1.625ch;
|
|
770
772
|
/* Some resets, like Tailwind, nix the list styling. */
|
|
771
773
|
list-style: revert;
|
|
772
774
|
}
|
|
773
775
|
|
|
774
776
|
.tl-rich-text ol:has(> li:nth-child(10)) {
|
|
775
|
-
padding-left:
|
|
777
|
+
padding-left: 2.625ch;
|
|
776
778
|
}
|
|
777
779
|
|
|
778
780
|
.tl-rich-text ol:has(> li:nth-child(100)) {
|
|
779
|
-
padding-left:
|
|
781
|
+
padding-left: 3.625ch;
|
|
780
782
|
}
|
|
781
783
|
|
|
782
784
|
.tl-rich-text h1,
|
|
@@ -815,6 +817,7 @@ input,
|
|
|
815
817
|
.tl-theme__dark .tl-rich-text mark {
|
|
816
818
|
background-color: var(--tl-color-text-highlight);
|
|
817
819
|
color: currentColor;
|
|
820
|
+
text-shadow: none;
|
|
818
821
|
}
|
|
819
822
|
|
|
820
823
|
@supports (color: color(display-p3 1 1 1)) {
|
|
@@ -987,6 +990,15 @@ input,
|
|
|
987
990
|
color: var(--tl-color-text-1);
|
|
988
991
|
}
|
|
989
992
|
|
|
993
|
+
.tl-content-slot {
|
|
994
|
+
position: absolute;
|
|
995
|
+
inset: 0px;
|
|
996
|
+
height: 100%;
|
|
997
|
+
width: 100%;
|
|
998
|
+
pointer-events: none;
|
|
999
|
+
transform-origin: top left;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
990
1002
|
/* -------------------- Group shape ------------------ */
|
|
991
1003
|
|
|
992
1004
|
.tl-group {
|
|
@@ -1573,9 +1585,8 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1573
1585
|
* (which creates its own stacking context at z-index 300), so their
|
|
1574
1586
|
* z-indices are relative to the layout, not the container.
|
|
1575
1587
|
*
|
|
1576
|
-
* cursor
|
|
1577
|
-
*
|
|
1578
|
-
* to that context.
|
|
1588
|
+
* cursor is rendered inside canvas-in-front (stacking context at
|
|
1589
|
+
* z-index 250), so their z-indices are relative to that context.
|
|
1579
1590
|
*/
|
|
1580
1591
|
--tl-layer-above: 1;
|
|
1581
1592
|
--tl-layer-focused-input: 10;
|
|
@@ -1585,7 +1596,6 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1585
1596
|
--tl-layer-toasts: 650;
|
|
1586
1597
|
--tl-layer-cursor: 700;
|
|
1587
1598
|
--tl-layer-header-footer: 999;
|
|
1588
|
-
--tl-layer-following-indicator: 1000;
|
|
1589
1599
|
}
|
|
1590
1600
|
|
|
1591
1601
|
/* Button */
|
|
@@ -1615,14 +1625,14 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1615
1625
|
|
|
1616
1626
|
.tlui-button:disabled,
|
|
1617
1627
|
.tlui-button[data-disabled] {
|
|
1618
|
-
color: var(--tl-color-text-
|
|
1628
|
+
color: var(--tl-color-text-disabled);
|
|
1619
1629
|
text-shadow: none;
|
|
1620
1630
|
cursor: default;
|
|
1621
1631
|
}
|
|
1622
1632
|
|
|
1623
1633
|
.tlui-button:disabled .tlui-kbd,
|
|
1624
1634
|
.tlui-button[data-disabled] .tlui-kbd {
|
|
1625
|
-
color: var(--tl-color-text-
|
|
1635
|
+
color: var(--tl-color-text-disabled);
|
|
1626
1636
|
}
|
|
1627
1637
|
|
|
1628
1638
|
.tlui-button > * {
|
|
@@ -1991,6 +2001,11 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1991
2001
|
height: 15px;
|
|
1992
2002
|
}
|
|
1993
2003
|
|
|
2004
|
+
.tlui-icon__tiny {
|
|
2005
|
+
width: 12px;
|
|
2006
|
+
height: 12px;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
1994
2009
|
/* --------------------- Slider --------------------- */
|
|
1995
2010
|
|
|
1996
2011
|
.tlui-slider__container {
|
|
@@ -2604,7 +2619,7 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2604
2619
|
left: 8px;
|
|
2605
2620
|
}
|
|
2606
2621
|
|
|
2607
|
-
/*
|
|
2622
|
+
/*
|
|
2608
2623
|
* focusing skip-to-main-content hide top ui buttons to make sure we avoid
|
|
2609
2624
|
* z-index clashes on hover (see issue #8328)
|
|
2610
2625
|
*/
|
|
@@ -3251,8 +3266,17 @@ tldraw? probably.
|
|
|
3251
3266
|
height: 100%;
|
|
3252
3267
|
z-index: var(--tl-layer-canvas-overlays);
|
|
3253
3268
|
background-color: var(--tl-color-overlay);
|
|
3254
|
-
pointer-events: all;
|
|
3255
3269
|
animation: tl-fade-in 0.12s ease-out;
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
.tlui-dialog__positioner {
|
|
3273
|
+
position: absolute;
|
|
3274
|
+
top: 0px;
|
|
3275
|
+
left: 0px;
|
|
3276
|
+
width: 100%;
|
|
3277
|
+
height: 100%;
|
|
3278
|
+
z-index: var(--tl-layer-canvas-overlays);
|
|
3279
|
+
pointer-events: all;
|
|
3256
3280
|
display: grid;
|
|
3257
3281
|
place-items: center;
|
|
3258
3282
|
overflow-y: auto;
|
|
@@ -3742,7 +3766,6 @@ tldraw? probably.
|
|
|
3742
3766
|
inset: 0px;
|
|
3743
3767
|
border-width: 2px;
|
|
3744
3768
|
border-style: solid;
|
|
3745
|
-
z-index: var(--tl-layer-following-indicator);
|
|
3746
3769
|
pointer-events: none;
|
|
3747
3770
|
}
|
|
3748
3771
|
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var setStrokePointRadii_exports = {};
|
|
20
|
-
__export(setStrokePointRadii_exports, {
|
|
21
|
-
setStrokePointRadii: () => setStrokePointRadii
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(setStrokePointRadii_exports);
|
|
24
|
-
var import_editor = require("@tldraw/editor");
|
|
25
|
-
const { min } = Math;
|
|
26
|
-
const RATE_OF_PRESSURE_CHANGE = 0.275;
|
|
27
|
-
function setStrokePointRadii(strokePoints, options) {
|
|
28
|
-
const {
|
|
29
|
-
size = 16,
|
|
30
|
-
thinning = 0.5,
|
|
31
|
-
simulatePressure = true,
|
|
32
|
-
easing = (t) => t,
|
|
33
|
-
start = {},
|
|
34
|
-
end = {}
|
|
35
|
-
} = options;
|
|
36
|
-
const { easing: taperStartEase = import_editor.EASINGS.easeOutQuad } = start;
|
|
37
|
-
const { easing: taperEndEase = import_editor.EASINGS.easeOutCubic } = end;
|
|
38
|
-
const totalLength = strokePoints[strokePoints.length - 1].runningLength;
|
|
39
|
-
let firstRadius;
|
|
40
|
-
let prevPressure = strokePoints[0].pressure;
|
|
41
|
-
let strokePoint;
|
|
42
|
-
if (!simulatePressure && totalLength < size) {
|
|
43
|
-
const max = strokePoints.reduce((max2, curr) => Math.max(max2, curr.pressure), 0.5);
|
|
44
|
-
strokePoints.forEach((sp) => {
|
|
45
|
-
sp.pressure = max;
|
|
46
|
-
sp.radius = size * easing(0.5 - thinning * (0.5 - sp.pressure));
|
|
47
|
-
});
|
|
48
|
-
return strokePoints;
|
|
49
|
-
} else {
|
|
50
|
-
let p;
|
|
51
|
-
for (let i = 0, n = strokePoints.length; i < n; i++) {
|
|
52
|
-
strokePoint = strokePoints[i];
|
|
53
|
-
if (strokePoint.runningLength > size * 5) break;
|
|
54
|
-
const sp = min(1, strokePoint.distance / size);
|
|
55
|
-
if (simulatePressure) {
|
|
56
|
-
const rp = min(1, 1 - sp);
|
|
57
|
-
p = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE));
|
|
58
|
-
} else {
|
|
59
|
-
p = min(1, prevPressure + (strokePoint.pressure - prevPressure) * 0.5);
|
|
60
|
-
}
|
|
61
|
-
prevPressure = prevPressure + (p - prevPressure) * 0.5;
|
|
62
|
-
}
|
|
63
|
-
for (let i = 0; i < strokePoints.length; i++) {
|
|
64
|
-
strokePoint = strokePoints[i];
|
|
65
|
-
if (thinning) {
|
|
66
|
-
let { pressure } = strokePoint;
|
|
67
|
-
const sp = min(1, strokePoint.distance / size);
|
|
68
|
-
if (simulatePressure) {
|
|
69
|
-
const rp = min(1, 1 - sp);
|
|
70
|
-
pressure = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE));
|
|
71
|
-
} else {
|
|
72
|
-
pressure = min(
|
|
73
|
-
1,
|
|
74
|
-
prevPressure + (pressure - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE)
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
strokePoint.radius = size * easing(0.5 - thinning * (0.5 - pressure));
|
|
78
|
-
prevPressure = pressure;
|
|
79
|
-
} else {
|
|
80
|
-
strokePoint.radius = size / 2;
|
|
81
|
-
}
|
|
82
|
-
if (firstRadius === void 0) {
|
|
83
|
-
firstRadius = strokePoint.radius;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const taperStart = start.taper === false ? 0 : start.taper === true ? Math.max(size, totalLength) : start.taper;
|
|
88
|
-
const taperEnd = end.taper === false ? 0 : end.taper === true ? Math.max(size, totalLength) : end.taper;
|
|
89
|
-
if (taperStart || taperEnd) {
|
|
90
|
-
for (let i = 0; i < strokePoints.length; i++) {
|
|
91
|
-
strokePoint = strokePoints[i];
|
|
92
|
-
const { runningLength } = strokePoint;
|
|
93
|
-
const ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1;
|
|
94
|
-
const te = totalLength - runningLength < taperEnd ? taperEndEase((totalLength - runningLength) / taperEnd) : 1;
|
|
95
|
-
strokePoint.radius = Math.max(0.01, strokePoint.radius * Math.min(ts, te));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return strokePoints;
|
|
99
|
-
}
|
|
100
|
-
//# sourceMappingURL=setStrokePointRadii.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/lib/shapes/shared/freehand/setStrokePointRadii.ts"],
|
|
4
|
-
"sourcesContent": ["import { EASINGS } from '@tldraw/editor'\nimport { StrokeOptions, StrokePoint } from './types'\n\nconst { min } = Math\n\n// This is the rate of change for simulated pressure. It could be an option.\nconst RATE_OF_PRESSURE_CHANGE = 0.275\n\n/** @public */\nexport function setStrokePointRadii(strokePoints: StrokePoint[], options: StrokeOptions) {\n\tconst {\n\t\tsize = 16,\n\t\tthinning = 0.5,\n\t\tsimulatePressure = true,\n\t\teasing = (t) => t,\n\t\tstart = {},\n\t\tend = {},\n\t} = options\n\n\tconst { easing: taperStartEase = EASINGS.easeOutQuad } = start\n\tconst { easing: taperEndEase = EASINGS.easeOutCubic } = end\n\n\tconst totalLength = strokePoints[strokePoints.length - 1].runningLength\n\n\tlet firstRadius: number | undefined\n\tlet prevPressure = strokePoints[0].pressure\n\tlet strokePoint: StrokePoint\n\n\tif (!simulatePressure && totalLength < size) {\n\t\tconst max = strokePoints.reduce((max, curr) => Math.max(max, curr.pressure), 0.5)\n\t\tstrokePoints.forEach((sp) => {\n\t\t\tsp.pressure = max\n\t\t\tsp.radius = size * easing(0.5 - thinning * (0.5 - sp.pressure))\n\t\t})\n\t\treturn strokePoints\n\t} else {\n\t\t// Calculate initial pressure based on the average of the first\n\t\t// n number of points. This prevents \"dots\" at the start of the\n\t\t// line. Drawn lines almost always start slow!\n\t\tlet p: number\n\t\tfor (let i = 0, n = strokePoints.length; i < n; i++) {\n\t\t\tstrokePoint = strokePoints[i]\n\t\t\tif (strokePoint.runningLength > size * 5) break\n\t\t\tconst sp = min(1, strokePoint.distance / size)\n\t\t\tif (simulatePressure) {\n\t\t\t\tconst rp = min(1, 1 - sp)\n\t\t\t\tp = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE))\n\t\t\t} else {\n\t\t\t\tp = min(1, prevPressure + (strokePoint.pressure - prevPressure) * 0.5)\n\t\t\t}\n\t\t\tprevPressure = prevPressure + (p - prevPressure) * 0.5\n\t\t}\n\n\t\t// Now calculate pressure and radius for each point\n\t\tfor (let i = 0; i < strokePoints.length; i++) {\n\t\t\tstrokePoint = strokePoints[i]\n\t\t\tif (thinning) {\n\t\t\t\tlet { pressure } = strokePoint\n\t\t\t\tconst sp = min(1, strokePoint.distance / size)\n\t\t\t\tif (simulatePressure) {\n\t\t\t\t\t// If we're simulating pressure, then do so based on the distance\n\t\t\t\t\t// between the current point and the previous point, and the size\n\t\t\t\t\t// of the stroke.\n\t\t\t\t\tconst rp = min(1, 1 - sp)\n\t\t\t\t\tpressure = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE))\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, use the input pressure slightly smoothed based on the\n\t\t\t\t\t// distance between the current point and the previous point.\n\t\t\t\t\tpressure = min(\n\t\t\t\t\t\t1,\n\t\t\t\t\t\tprevPressure + (pressure - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE)\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tstrokePoint.radius = size * easing(0.5 - thinning * (0.5 - pressure))\n\n\t\t\t\tprevPressure = pressure\n\t\t\t} else {\n\t\t\t\tstrokePoint.radius = size / 2\n\t\t\t}\n\n\t\t\tif (firstRadius === undefined) {\n\t\t\t\tfirstRadius = strokePoint.radius\n\t\t\t}\n\t\t}\n\t}\n\n\tconst taperStart =\n\t\tstart.taper === false\n\t\t\t? 0\n\t\t\t: start.taper === true\n\t\t\t\t? Math.max(size, totalLength)\n\t\t\t\t: (start.taper as number)\n\n\tconst taperEnd =\n\t\tend.taper === false\n\t\t\t? 0\n\t\t\t: end.taper === true\n\t\t\t\t? Math.max(size, totalLength)\n\t\t\t\t: (end.taper as number)\n\n\tif (taperStart || taperEnd) {\n\t\tfor (let i = 0; i < strokePoints.length; i++) {\n\t\t\tstrokePoint = strokePoints[i]\n\t\t\t/*\n\t\t\t\tApply tapering\n\n\t\t\t\tIf the current length is within the taper distance at either the\n\t\t\t\tstart or the end, calculate the taper strengths. Apply the smaller \n\t\t\t\tof the two taper strengths to the radius.\n\t\t\t*/\n\n\t\t\tconst { runningLength } = strokePoint\n\n\t\t\tconst ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1\n\n\t\t\tconst te =\n\t\t\t\ttotalLength - runningLength < taperEnd\n\t\t\t\t\t? taperEndEase((totalLength - runningLength) / taperEnd)\n\t\t\t\t\t: 1\n\n\t\t\tstrokePoint.radius = Math.max(0.01, strokePoint.radius * Math.min(ts, te))\n\t\t}\n\t}\n\n\treturn strokePoints\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["max"]
|
|
7
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { EASINGS } from "@tldraw/editor";
|
|
2
|
-
const { min } = Math;
|
|
3
|
-
const RATE_OF_PRESSURE_CHANGE = 0.275;
|
|
4
|
-
function setStrokePointRadii(strokePoints, options) {
|
|
5
|
-
const {
|
|
6
|
-
size = 16,
|
|
7
|
-
thinning = 0.5,
|
|
8
|
-
simulatePressure = true,
|
|
9
|
-
easing = (t) => t,
|
|
10
|
-
start = {},
|
|
11
|
-
end = {}
|
|
12
|
-
} = options;
|
|
13
|
-
const { easing: taperStartEase = EASINGS.easeOutQuad } = start;
|
|
14
|
-
const { easing: taperEndEase = EASINGS.easeOutCubic } = end;
|
|
15
|
-
const totalLength = strokePoints[strokePoints.length - 1].runningLength;
|
|
16
|
-
let firstRadius;
|
|
17
|
-
let prevPressure = strokePoints[0].pressure;
|
|
18
|
-
let strokePoint;
|
|
19
|
-
if (!simulatePressure && totalLength < size) {
|
|
20
|
-
const max = strokePoints.reduce((max2, curr) => Math.max(max2, curr.pressure), 0.5);
|
|
21
|
-
strokePoints.forEach((sp) => {
|
|
22
|
-
sp.pressure = max;
|
|
23
|
-
sp.radius = size * easing(0.5 - thinning * (0.5 - sp.pressure));
|
|
24
|
-
});
|
|
25
|
-
return strokePoints;
|
|
26
|
-
} else {
|
|
27
|
-
let p;
|
|
28
|
-
for (let i = 0, n = strokePoints.length; i < n; i++) {
|
|
29
|
-
strokePoint = strokePoints[i];
|
|
30
|
-
if (strokePoint.runningLength > size * 5) break;
|
|
31
|
-
const sp = min(1, strokePoint.distance / size);
|
|
32
|
-
if (simulatePressure) {
|
|
33
|
-
const rp = min(1, 1 - sp);
|
|
34
|
-
p = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE));
|
|
35
|
-
} else {
|
|
36
|
-
p = min(1, prevPressure + (strokePoint.pressure - prevPressure) * 0.5);
|
|
37
|
-
}
|
|
38
|
-
prevPressure = prevPressure + (p - prevPressure) * 0.5;
|
|
39
|
-
}
|
|
40
|
-
for (let i = 0; i < strokePoints.length; i++) {
|
|
41
|
-
strokePoint = strokePoints[i];
|
|
42
|
-
if (thinning) {
|
|
43
|
-
let { pressure } = strokePoint;
|
|
44
|
-
const sp = min(1, strokePoint.distance / size);
|
|
45
|
-
if (simulatePressure) {
|
|
46
|
-
const rp = min(1, 1 - sp);
|
|
47
|
-
pressure = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE));
|
|
48
|
-
} else {
|
|
49
|
-
pressure = min(
|
|
50
|
-
1,
|
|
51
|
-
prevPressure + (pressure - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE)
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
strokePoint.radius = size * easing(0.5 - thinning * (0.5 - pressure));
|
|
55
|
-
prevPressure = pressure;
|
|
56
|
-
} else {
|
|
57
|
-
strokePoint.radius = size / 2;
|
|
58
|
-
}
|
|
59
|
-
if (firstRadius === void 0) {
|
|
60
|
-
firstRadius = strokePoint.radius;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const taperStart = start.taper === false ? 0 : start.taper === true ? Math.max(size, totalLength) : start.taper;
|
|
65
|
-
const taperEnd = end.taper === false ? 0 : end.taper === true ? Math.max(size, totalLength) : end.taper;
|
|
66
|
-
if (taperStart || taperEnd) {
|
|
67
|
-
for (let i = 0; i < strokePoints.length; i++) {
|
|
68
|
-
strokePoint = strokePoints[i];
|
|
69
|
-
const { runningLength } = strokePoint;
|
|
70
|
-
const ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1;
|
|
71
|
-
const te = totalLength - runningLength < taperEnd ? taperEndEase((totalLength - runningLength) / taperEnd) : 1;
|
|
72
|
-
strokePoint.radius = Math.max(0.01, strokePoint.radius * Math.min(ts, te));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return strokePoints;
|
|
76
|
-
}
|
|
77
|
-
export {
|
|
78
|
-
setStrokePointRadii
|
|
79
|
-
};
|
|
80
|
-
//# sourceMappingURL=setStrokePointRadii.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/lib/shapes/shared/freehand/setStrokePointRadii.ts"],
|
|
4
|
-
"sourcesContent": ["import { EASINGS } from '@tldraw/editor'\nimport { StrokeOptions, StrokePoint } from './types'\n\nconst { min } = Math\n\n// This is the rate of change for simulated pressure. It could be an option.\nconst RATE_OF_PRESSURE_CHANGE = 0.275\n\n/** @public */\nexport function setStrokePointRadii(strokePoints: StrokePoint[], options: StrokeOptions) {\n\tconst {\n\t\tsize = 16,\n\t\tthinning = 0.5,\n\t\tsimulatePressure = true,\n\t\teasing = (t) => t,\n\t\tstart = {},\n\t\tend = {},\n\t} = options\n\n\tconst { easing: taperStartEase = EASINGS.easeOutQuad } = start\n\tconst { easing: taperEndEase = EASINGS.easeOutCubic } = end\n\n\tconst totalLength = strokePoints[strokePoints.length - 1].runningLength\n\n\tlet firstRadius: number | undefined\n\tlet prevPressure = strokePoints[0].pressure\n\tlet strokePoint: StrokePoint\n\n\tif (!simulatePressure && totalLength < size) {\n\t\tconst max = strokePoints.reduce((max, curr) => Math.max(max, curr.pressure), 0.5)\n\t\tstrokePoints.forEach((sp) => {\n\t\t\tsp.pressure = max\n\t\t\tsp.radius = size * easing(0.5 - thinning * (0.5 - sp.pressure))\n\t\t})\n\t\treturn strokePoints\n\t} else {\n\t\t// Calculate initial pressure based on the average of the first\n\t\t// n number of points. This prevents \"dots\" at the start of the\n\t\t// line. Drawn lines almost always start slow!\n\t\tlet p: number\n\t\tfor (let i = 0, n = strokePoints.length; i < n; i++) {\n\t\t\tstrokePoint = strokePoints[i]\n\t\t\tif (strokePoint.runningLength > size * 5) break\n\t\t\tconst sp = min(1, strokePoint.distance / size)\n\t\t\tif (simulatePressure) {\n\t\t\t\tconst rp = min(1, 1 - sp)\n\t\t\t\tp = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE))\n\t\t\t} else {\n\t\t\t\tp = min(1, prevPressure + (strokePoint.pressure - prevPressure) * 0.5)\n\t\t\t}\n\t\t\tprevPressure = prevPressure + (p - prevPressure) * 0.5\n\t\t}\n\n\t\t// Now calculate pressure and radius for each point\n\t\tfor (let i = 0; i < strokePoints.length; i++) {\n\t\t\tstrokePoint = strokePoints[i]\n\t\t\tif (thinning) {\n\t\t\t\tlet { pressure } = strokePoint\n\t\t\t\tconst sp = min(1, strokePoint.distance / size)\n\t\t\t\tif (simulatePressure) {\n\t\t\t\t\t// If we're simulating pressure, then do so based on the distance\n\t\t\t\t\t// between the current point and the previous point, and the size\n\t\t\t\t\t// of the stroke.\n\t\t\t\t\tconst rp = min(1, 1 - sp)\n\t\t\t\t\tpressure = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE))\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, use the input pressure slightly smoothed based on the\n\t\t\t\t\t// distance between the current point and the previous point.\n\t\t\t\t\tpressure = min(\n\t\t\t\t\t\t1,\n\t\t\t\t\t\tprevPressure + (pressure - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE)\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tstrokePoint.radius = size * easing(0.5 - thinning * (0.5 - pressure))\n\n\t\t\t\tprevPressure = pressure\n\t\t\t} else {\n\t\t\t\tstrokePoint.radius = size / 2\n\t\t\t}\n\n\t\t\tif (firstRadius === undefined) {\n\t\t\t\tfirstRadius = strokePoint.radius\n\t\t\t}\n\t\t}\n\t}\n\n\tconst taperStart =\n\t\tstart.taper === false\n\t\t\t? 0\n\t\t\t: start.taper === true\n\t\t\t\t? Math.max(size, totalLength)\n\t\t\t\t: (start.taper as number)\n\n\tconst taperEnd =\n\t\tend.taper === false\n\t\t\t? 0\n\t\t\t: end.taper === true\n\t\t\t\t? Math.max(size, totalLength)\n\t\t\t\t: (end.taper as number)\n\n\tif (taperStart || taperEnd) {\n\t\tfor (let i = 0; i < strokePoints.length; i++) {\n\t\t\tstrokePoint = strokePoints[i]\n\t\t\t/*\n\t\t\t\tApply tapering\n\n\t\t\t\tIf the current length is within the taper distance at either the\n\t\t\t\tstart or the end, calculate the taper strengths. Apply the smaller \n\t\t\t\tof the two taper strengths to the radius.\n\t\t\t*/\n\n\t\t\tconst { runningLength } = strokePoint\n\n\t\t\tconst ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1\n\n\t\t\tconst te =\n\t\t\t\ttotalLength - runningLength < taperEnd\n\t\t\t\t\t? taperEndEase((totalLength - runningLength) / taperEnd)\n\t\t\t\t\t: 1\n\n\t\t\tstrokePoint.radius = Math.max(0.01, strokePoint.radius * Math.min(ts, te))\n\t\t}\n\t}\n\n\treturn strokePoints\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["max"]
|
|
7
|
-
}
|