Tldraw/packages/tldraw/src/lib/shapes/text/TextShapeUtil.tsx

370 wiersze
8.6 KiB
TypeScript
Czysty Zwykły widok Historia

2023-04-25 11:01:25 +00:00
/* eslint-disable react-hooks/rules-of-hooks */
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
import {
React-powered SVG exports (#3117) ## Migration path 1. If any of your shapes implement `toSvg` for exports, you'll need to replace your implementation with a new version that returns JSX (it's a react component) instead of manually constructing SVG DOM nodes 2. `editor.getSvg` is deprecated. It still works, but will be going away in a future release. If you still need SVGs as DOM elements rather than strings, use `new DOMParser().parseFromString(svgString, 'image/svg+xml').firstElementChild` ## The change in detail At the moment, our SVG exports very carefully try to recreate the visuals of our shapes by manually constructing SVG DOM nodes. On its own this is really painful, but it also results in a lot of duplicated logic between the `component` and `getSvg` methods of shape utils. In #3020, we looked at using string concatenation & DOMParser to make this a bit less painful. This works, but requires specifying namespaces everywhere, is still pretty painful (no syntax highlighting or formatting), and still results in all that duplicated logic. I briefly experimented with creating my own version of the javascript language that let you embed XML like syntax directly. I was going to call it EXTREME JAVASCRIPT or XJS for short, but then I noticed that we already wrote the whole of tldraw in this thing called react and a (imo much worse named) version of the javascript xml thing already existed. Given the entire library already depends on react, what would it look like if we just used react directly for these exports? Turns out things get a lot simpler! Take a look at lmk what you think This diff was intended as a proof of concept, but is actually pretty close to being landable. The main thing is that here, I've deliberately leant into this being a big breaking change to see just how much code we could delete (turns out: lots). We could if we wanted to make this without making it a breaking change at all, but it would add back a lot of complexity on our side and run a fair bit slower --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-03-25 14:16:55 +00:00
Box,
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
Editor,
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
Rectangle2d,
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
ShapeUtil,
SvgExportContext,
TLOnEditEndHandler,
TLOnResizeHandler,
TLShapeId,
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
TLShapeUtilFlag,
TLTextShape,
Vec,
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
WeakMapCache,
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
getDefaultColorTheme,
preventDefault,
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
textShapeMigrations,
textShapeProps,
toDomPrecision,
useEditor,
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
} from '@tldraw/editor'
import { useCallback } from 'react'
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
import { useDefaultColorTheme } from '../shared/ShapeFill'
React-powered SVG exports (#3117) ## Migration path 1. If any of your shapes implement `toSvg` for exports, you'll need to replace your implementation with a new version that returns JSX (it's a react component) instead of manually constructing SVG DOM nodes 2. `editor.getSvg` is deprecated. It still works, but will be going away in a future release. If you still need SVGs as DOM elements rather than strings, use `new DOMParser().parseFromString(svgString, 'image/svg+xml').firstElementChild` ## The change in detail At the moment, our SVG exports very carefully try to recreate the visuals of our shapes by manually constructing SVG DOM nodes. On its own this is really painful, but it also results in a lot of duplicated logic between the `component` and `getSvg` methods of shape utils. In #3020, we looked at using string concatenation & DOMParser to make this a bit less painful. This works, but requires specifying namespaces everywhere, is still pretty painful (no syntax highlighting or formatting), and still results in all that duplicated logic. I briefly experimented with creating my own version of the javascript language that let you embed XML like syntax directly. I was going to call it EXTREME JAVASCRIPT or XJS for short, but then I noticed that we already wrote the whole of tldraw in this thing called react and a (imo much worse named) version of the javascript xml thing already existed. Given the entire library already depends on react, what would it look like if we just used react directly for these exports? Turns out things get a lot simpler! Take a look at lmk what you think This diff was intended as a proof of concept, but is actually pretty close to being landable. The main thing is that here, I've deliberately leant into this being a big breaking change to see just how much code we could delete (turns out: lots). We could if we wanted to make this without making it a breaking change at all, but it would add back a lot of complexity on our side and run a fair bit slower --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-03-25 14:16:55 +00:00
import { SvgTextLabel } from '../shared/SvgTextLabel'
import { TextHelpers } from '../shared/TextHelpers'
import { TextLabel } from '../shared/TextLabel'
import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from '../shared/default-shape-constants'
import { getFontDefForExport } from '../shared/defaultStyleDefs'
2023-04-25 11:01:25 +00:00
import { resizeScaled } from '../shared/resizeScaled'
const sizeCache = new WeakMapCache<TLTextShape['props'], { height: number; width: number }>()
/** @public */
export class TextShapeUtil extends ShapeUtil<TLTextShape> {
static override type = 'text' as const
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
static override props = textShapeProps
static override migrations = textShapeMigrations
2023-04-25 11:01:25 +00:00
`ShapeUtil` refactor, `Editor` cleanup (#1611) This PR improves the ergonomics of `ShapeUtil` classes. ### Cached methods First, I've remove the cached methods (such as `bounds`) from the `ShapeUtil` class and lifted this to the `Editor` class. Previously, calling `ShapeUtil.getBounds` would return the un-cached bounds of a shape, while calling `ShapeUtil.bounds` would return the cached bounds of a shape. We also had `Editor.getBounds`, which would call `ShapeUtil.bounds`. It was confusing. The cached methods like `outline` were also marked with "please don't override", which suggested the architecture was just wrong. The only weirdness from this is that utils sometimes reach out to the editor for cached versions of data rather than calling their own cached methods. It's still an easier story to tell than what we had before. ### More defaults We now have three and only three `abstract` methods for a `ShapeUtil`: - `getDefaultProps` (renamed from `defaultProps`) - `getBounds`, - `component` - `indicator` Previously, we also had `getCenter` as an abstract method, though this was usually just the middle of the bounds anyway. ### Editing bounds This PR removes the concept of editingBounds. The viewport will no longer animate to editing shapes. ### Active area manager This PR also removes the active area manager, which was not being used in the way we expected it to be. ### Dpr manager This PR removes the dpr manager and uses a hook instead to update it from React. This is one less runtime browser dependency in the app, one less thing to document. ### Moving things around This PR also continues to try to organize related methods and properties in the editor. ### Change Type - [x] `major` — Breaking change ### Release Notes - [editor] renames `defaultProps` to `getDefaultProps` - [editor] removes `outline`, `outlineSegments`, `handles`, `bounds` - [editor] renames `renderBackground` to `backgroundComponent`
2023-06-19 14:01:18 +00:00
getDefaultProps(): TLTextShape['props'] {
2023-04-25 11:01:25 +00:00
return {
color: 'black',
size: 'm',
w: 8,
text: '',
font: 'draw',
align: 'middle',
autoSize: true,
scale: 1,
}
}
getMinDimensions(shape: TLTextShape) {
return sizeCache.get(shape.props, (props) => getTextSize(this.editor, props))
2023-04-25 11:01:25 +00:00
}
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
getGeometry(shape: TLTextShape) {
2023-04-25 11:01:25 +00:00
const { scale } = shape.props
const { width, height } = this.getMinDimensions(shape)!
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
return new Rectangle2d({
width: width * scale,
height: height * scale,
isFilled: true,
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
isLabel: true,
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
})
2023-04-25 11:01:25 +00:00
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override canEdit = () => true
override isAspectRatioLocked: TLShapeUtilFlag<TLTextShape> = () => true
component(shape: TLTextShape) {
2023-04-25 11:01:25 +00:00
const {
id,
props: { font, size, text, color, scale, align },
2023-04-25 11:01:25 +00:00
} = shape
const { width, height } = this.getMinDimensions(shape)
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
const isSelected = shape.id === this.editor.getOnlySelectedShapeId()
const theme = useDefaultColorTheme()
const handleKeyDown = useTextShapeKeydownHandler(id)
2023-04-25 11:01:25 +00:00
return (
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
<TextLabel
id={id}
classNamePrefix="tl-text-shape"
type="text"
font={font}
fontSize={FONT_SIZES[size]}
lineHeight={TEXT_PROPS.lineHeight}
align={align}
verticalAlign="middle"
text={text}
labelColor={theme[color].solid}
isSelected={isSelected}
textWidth={width}
textHeight={height}
style={{
transform: `scale(${scale})`,
transformOrigin: 'top left',
}}
wrap
onKeyDown={handleKeyDown}
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
/>
2023-04-25 11:01:25 +00:00
)
}
indicator(shape: TLTextShape) {
const bounds = this.editor.getShapeGeometry(shape).bounds
const editor = useEditor()
if (shape.props.autoSize && editor.getEditingShapeId() === shape.id) return null
2023-04-25 11:01:25 +00:00
return <rect width={toDomPrecision(bounds.width)} height={toDomPrecision(bounds.height)} />
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override toSvg(shape: TLTextShape, ctx: SvgExportContext) {
ctx.addExportDef(getFontDefForExport(shape.props.font))
React-powered SVG exports (#3117) ## Migration path 1. If any of your shapes implement `toSvg` for exports, you'll need to replace your implementation with a new version that returns JSX (it's a react component) instead of manually constructing SVG DOM nodes 2. `editor.getSvg` is deprecated. It still works, but will be going away in a future release. If you still need SVGs as DOM elements rather than strings, use `new DOMParser().parseFromString(svgString, 'image/svg+xml').firstElementChild` ## The change in detail At the moment, our SVG exports very carefully try to recreate the visuals of our shapes by manually constructing SVG DOM nodes. On its own this is really painful, but it also results in a lot of duplicated logic between the `component` and `getSvg` methods of shape utils. In #3020, we looked at using string concatenation & DOMParser to make this a bit less painful. This works, but requires specifying namespaces everywhere, is still pretty painful (no syntax highlighting or formatting), and still results in all that duplicated logic. I briefly experimented with creating my own version of the javascript language that let you embed XML like syntax directly. I was going to call it EXTREME JAVASCRIPT or XJS for short, but then I noticed that we already wrote the whole of tldraw in this thing called react and a (imo much worse named) version of the javascript xml thing already existed. Given the entire library already depends on react, what would it look like if we just used react directly for these exports? Turns out things get a lot simpler! Take a look at lmk what you think This diff was intended as a proof of concept, but is actually pretty close to being landable. The main thing is that here, I've deliberately leant into this being a big breaking change to see just how much code we could delete (turns out: lots). We could if we wanted to make this without making it a breaking change at all, but it would add back a lot of complexity on our side and run a fair bit slower --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-03-25 14:16:55 +00:00
if (shape.props.text) ctx.addExportDef(getFontDefForExport(shape.props.font))
const bounds = this.editor.getShapeGeometry(shape).bounds
2023-04-25 11:01:25 +00:00
const width = bounds.width / (shape.props.scale ?? 1)
const height = bounds.height / (shape.props.scale ?? 1)
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
const theme = getDefaultColorTheme(ctx)
React-powered SVG exports (#3117) ## Migration path 1. If any of your shapes implement `toSvg` for exports, you'll need to replace your implementation with a new version that returns JSX (it's a react component) instead of manually constructing SVG DOM nodes 2. `editor.getSvg` is deprecated. It still works, but will be going away in a future release. If you still need SVGs as DOM elements rather than strings, use `new DOMParser().parseFromString(svgString, 'image/svg+xml').firstElementChild` ## The change in detail At the moment, our SVG exports very carefully try to recreate the visuals of our shapes by manually constructing SVG DOM nodes. On its own this is really painful, but it also results in a lot of duplicated logic between the `component` and `getSvg` methods of shape utils. In #3020, we looked at using string concatenation & DOMParser to make this a bit less painful. This works, but requires specifying namespaces everywhere, is still pretty painful (no syntax highlighting or formatting), and still results in all that duplicated logic. I briefly experimented with creating my own version of the javascript language that let you embed XML like syntax directly. I was going to call it EXTREME JAVASCRIPT or XJS for short, but then I noticed that we already wrote the whole of tldraw in this thing called react and a (imo much worse named) version of the javascript xml thing already existed. Given the entire library already depends on react, what would it look like if we just used react directly for these exports? Turns out things get a lot simpler! Take a look at lmk what you think This diff was intended as a proof of concept, but is actually pretty close to being landable. The main thing is that here, I've deliberately leant into this being a big breaking change to see just how much code we could delete (turns out: lots). We could if we wanted to make this without making it a breaking change at all, but it would add back a lot of complexity on our side and run a fair bit slower --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-03-25 14:16:55 +00:00
return (
<SvgTextLabel
fontSize={FONT_SIZES[shape.props.size]}
font={shape.props.font}
align={shape.props.align}
verticalAlign="middle"
text={shape.props.text}
Stickies: release candidate (#3249) This PR is the target for the stickies PRs that are moving forward. It should collect changes. - [x] New icon - [x] Improved shadows - [x] Shadow LOD - [x] New colors / theme options - [x] Shrink text size to avoid word breaks on the x axis - [x] Hide indicator whilst typing (reverted) - [x] Adjacent note positions - [x] buttons / clone handles - [x] position helpers for creating / translating (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [x] multiple shape translating - [x] Text editing - [x] Edit on type (feature flagged) - [x] click goes in correct place - [x] Notes as parents (reverted) - [x] Update colors - [x] Update SVG appearance ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Test Plan Todo: fold in test plans for child PRs ### Unit tests: - [ ] Shrink text size to avoid word breaks on the x axis - [x] Adjacent notes - [x] buttons (clone handles) - [x] position helpers (pits) - [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter, Shift+Cmd+enter) - [ ] Text editing - [ ] Edit on type - [ ] click goes in correct place ### Release Notes - Improves sticky notes (see list) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
labelColor={theme[shape.props.color].solid}
React-powered SVG exports (#3117) ## Migration path 1. If any of your shapes implement `toSvg` for exports, you'll need to replace your implementation with a new version that returns JSX (it's a react component) instead of manually constructing SVG DOM nodes 2. `editor.getSvg` is deprecated. It still works, but will be going away in a future release. If you still need SVGs as DOM elements rather than strings, use `new DOMParser().parseFromString(svgString, 'image/svg+xml').firstElementChild` ## The change in detail At the moment, our SVG exports very carefully try to recreate the visuals of our shapes by manually constructing SVG DOM nodes. On its own this is really painful, but it also results in a lot of duplicated logic between the `component` and `getSvg` methods of shape utils. In #3020, we looked at using string concatenation & DOMParser to make this a bit less painful. This works, but requires specifying namespaces everywhere, is still pretty painful (no syntax highlighting or formatting), and still results in all that duplicated logic. I briefly experimented with creating my own version of the javascript language that let you embed XML like syntax directly. I was going to call it EXTREME JAVASCRIPT or XJS for short, but then I noticed that we already wrote the whole of tldraw in this thing called react and a (imo much worse named) version of the javascript xml thing already existed. Given the entire library already depends on react, what would it look like if we just used react directly for these exports? Turns out things get a lot simpler! Take a look at lmk what you think This diff was intended as a proof of concept, but is actually pretty close to being landable. The main thing is that here, I've deliberately leant into this being a big breaking change to see just how much code we could delete (turns out: lots). We could if we wanted to make this without making it a breaking change at all, but it would add back a lot of complexity on our side and run a fair bit slower --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-03-25 14:16:55 +00:00
bounds={new Box(0, 0, width, height)}
padding={0}
/>
Measure individual words instead of just line breaks for text exports (#1397) This diff fixes a number of issues with text export by completely overhauling how we approach laying out text in exports. Currently, we try to carefully replicate in-browser behaviour around line breaks and whitespace collapsing. We do this using an iterative algorithm that forces the browser to perform a layout for each word, and attempting to re-implement how the browser does things like whitespace collapsing & finding line break opportunities. Lots of export issues come from the fact that this is almost impossible to do well (short of sending a complete text layout algorithm & full unicode lookup tables). Luckily, the browser already has a complete text layout algorithm and full unicode lookup tables! In the new approach, we ask the browser to lay the text out once. Then, we use the [`Range`](https://developer.mozilla.org/en-US/docs/Web/API/Range) API to loop over every character in the rendered text and measure its position. These character positions are then grouped into "spans". A span is a contiguous range of either whitespace or non-whitespace characters, uninterrupted by any browser-inserting line breaks. When we come to render the SVG, each span gets its own `<tspan>` element, absolutely positioned according to where it ended up in the user's browser. This fixes a bunch of issues: **Misaligned text due to whitespace collapsing at line breaks** ![Kapture 2023-05-17 at 12 07 30](https://github.com/tldraw/tldraw/assets/1489520/5ab66fe0-6ceb-45bb-8787-90ccb124664a) **Hyphenated text (or text with non-trivial/whitespace-based breaking rules like Thai) not splitting correctly** ![Kapture 2023-05-17 at 12 21 40](https://github.com/tldraw/tldraw/assets/1489520/d2d5fd13-3e79-48c4-8e76-ae2c70a6471e) **Weird alignment issues in note shapes** ![Kapture 2023-05-17 at 12 24 59](https://github.com/tldraw/tldraw/assets/1489520/a0e51d57-7c1c-490e-9952-b92417ffdf9e) **Frame labels not respecting multiple spaces & not truncating correctly** ![Kapture 2023-05-17 at 12 27 27](https://github.com/tldraw/tldraw/assets/1489520/39b2f53c-0180-460e-b10a-9fd955a6fa78) #### Quick note on browser compatibility This approach works well across all browsers, but in some cases actually _increases_ x-browser variance. Consider these screenshots of the same element (original above, export below): ![image](https://github.com/tldraw/tldraw/assets/1489520/5633b041-8cb3-4c92-bef6-4f3c202305de) Notice how on chrome, the whitespace at the end of each line of right-aligned text is preserved. On safari, it's collapsed. The safari option looks better - so our manual line-breaking/white-space-collapsing algorithm preferred safari's approach. That meant that in-app, this shape looks very slightly different from browser to browser. But out of the app, the exports would have been the same (although also note that hyphenation is broken). Now, because these shapes look different across browsers, the exports now look different across browsers too. We're relying on the host-browsers text layout algorithm, which means we'll faithfully reproduce any quirks/inconsistencies of that algorithm. I think this is an acceptable tradeoff. ### Change Type - [x] `patch` — Bug Fix ### Test Plan * Comprehensive testing of text in exports, paying close attention to details around white-space, line-breaking and alignment * Consider setting `tldrawDebugSvg = true` * Check text shapes, geo shapes with labels, arrow shapes with labels, note shapes, frame labels * Check different alignments and fonts (including vertical alignment) ### Release Notes - Add a brief release note for your PR here.
2023-05-22 15:10:03 +00:00
)
2023-04-25 11:01:25 +00:00
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override onResize: TLOnResizeHandler<TLTextShape> = (shape, info) => {
2023-04-25 11:01:25 +00:00
const { initialBounds, initialShape, scaleX, handle } = info
if (info.mode === 'scale_shape' || (handle !== 'right' && handle !== 'left')) {
`ShapeUtil` refactor, `Editor` cleanup (#1611) This PR improves the ergonomics of `ShapeUtil` classes. ### Cached methods First, I've remove the cached methods (such as `bounds`) from the `ShapeUtil` class and lifted this to the `Editor` class. Previously, calling `ShapeUtil.getBounds` would return the un-cached bounds of a shape, while calling `ShapeUtil.bounds` would return the cached bounds of a shape. We also had `Editor.getBounds`, which would call `ShapeUtil.bounds`. It was confusing. The cached methods like `outline` were also marked with "please don't override", which suggested the architecture was just wrong. The only weirdness from this is that utils sometimes reach out to the editor for cached versions of data rather than calling their own cached methods. It's still an easier story to tell than what we had before. ### More defaults We now have three and only three `abstract` methods for a `ShapeUtil`: - `getDefaultProps` (renamed from `defaultProps`) - `getBounds`, - `component` - `indicator` Previously, we also had `getCenter` as an abstract method, though this was usually just the middle of the bounds anyway. ### Editing bounds This PR removes the concept of editingBounds. The viewport will no longer animate to editing shapes. ### Active area manager This PR also removes the active area manager, which was not being used in the way we expected it to be. ### Dpr manager This PR removes the dpr manager and uses a hook instead to update it from React. This is one less runtime browser dependency in the app, one less thing to document. ### Moving things around This PR also continues to try to organize related methods and properties in the editor. ### Change Type - [x] `major` — Breaking change ### Release Notes - [editor] renames `defaultProps` to `getDefaultProps` - [editor] removes `outline`, `outlineSegments`, `handles`, `bounds` - [editor] renames `renderBackground` to `backgroundComponent`
2023-06-19 14:01:18 +00:00
return {
id: shape.id,
type: shape.type,
...resizeScaled(shape, info),
}
2023-04-25 11:01:25 +00:00
} else {
const prevWidth = initialBounds.width
let nextWidth = prevWidth * scaleX
const offset = new Vec(0, 0)
2023-04-25 11:01:25 +00:00
nextWidth = Math.max(1, Math.abs(nextWidth))
if (handle === 'left') {
offset.x = prevWidth - nextWidth
if (scaleX < 0) {
offset.x += nextWidth
}
} else {
if (scaleX < 0) {
offset.x -= nextWidth
}
}
const { x, y } = offset.rot(shape.rotation).add(initialShape)
return {
`ShapeUtil` refactor, `Editor` cleanup (#1611) This PR improves the ergonomics of `ShapeUtil` classes. ### Cached methods First, I've remove the cached methods (such as `bounds`) from the `ShapeUtil` class and lifted this to the `Editor` class. Previously, calling `ShapeUtil.getBounds` would return the un-cached bounds of a shape, while calling `ShapeUtil.bounds` would return the cached bounds of a shape. We also had `Editor.getBounds`, which would call `ShapeUtil.bounds`. It was confusing. The cached methods like `outline` were also marked with "please don't override", which suggested the architecture was just wrong. The only weirdness from this is that utils sometimes reach out to the editor for cached versions of data rather than calling their own cached methods. It's still an easier story to tell than what we had before. ### More defaults We now have three and only three `abstract` methods for a `ShapeUtil`: - `getDefaultProps` (renamed from `defaultProps`) - `getBounds`, - `component` - `indicator` Previously, we also had `getCenter` as an abstract method, though this was usually just the middle of the bounds anyway. ### Editing bounds This PR removes the concept of editingBounds. The viewport will no longer animate to editing shapes. ### Active area manager This PR also removes the active area manager, which was not being used in the way we expected it to be. ### Dpr manager This PR removes the dpr manager and uses a hook instead to update it from React. This is one less runtime browser dependency in the app, one less thing to document. ### Moving things around This PR also continues to try to organize related methods and properties in the editor. ### Change Type - [x] `major` — Breaking change ### Release Notes - [editor] renames `defaultProps` to `getDefaultProps` - [editor] removes `outline`, `outlineSegments`, `handles`, `bounds` - [editor] renames `renderBackground` to `backgroundComponent`
2023-06-19 14:01:18 +00:00
id: shape.id,
type: shape.type,
2023-04-25 11:01:25 +00:00
x,
y,
props: {
w: nextWidth / initialShape.props.scale,
autoSize: false,
},
}
}
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override onBeforeCreate = (shape: TLTextShape) => {
2023-04-25 11:01:25 +00:00
// When a shape is created, center the text at the created point.
// Only center if the shape is set to autosize.
if (!shape.props.autoSize) return
// Only center if the shape is empty when created.
if (shape.props.text.trim()) return
const bounds = this.getMinDimensions(shape)
return {
...shape,
x: shape.x - bounds.width / 2,
y: shape.y - bounds.height / 2,
}
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override onEditEnd: TLOnEditEndHandler<TLTextShape> = (shape) => {
2023-04-25 11:01:25 +00:00
const {
id,
type,
props: { text },
} = shape
const trimmedText = shape.props.text.trimEnd()
2023-04-25 11:01:25 +00:00
if (trimmedText.length === 0) {
this.editor.deleteShapes([shape.id])
2023-04-25 11:01:25 +00:00
} else {
if (trimmedText !== shape.props.text) {
this.editor.updateShapes([
2023-04-25 11:01:25 +00:00
{
id,
type,
props: {
text: text.trimEnd(),
2023-04-25 11:01:25 +00:00
},
},
])
}
}
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override onBeforeUpdate = (prev: TLTextShape, next: TLTextShape) => {
2023-04-25 11:01:25 +00:00
if (!next.props.autoSize) return
const styleDidChange =
prev.props.size !== next.props.size ||
prev.props.align !== next.props.align ||
prev.props.font !== next.props.font ||
(prev.props.scale !== 1 && next.props.scale === 1)
const textDidChange = prev.props.text !== next.props.text
// Only update position if either changed
if (!styleDidChange && !textDidChange) return
// Might return a cached value for the bounds
const boundsA = this.getMinDimensions(prev)
// Will always be a fresh call to getTextSize
const boundsB = getTextSize(this.editor, next.props)
2023-04-25 11:01:25 +00:00
const wA = boundsA.width * prev.props.scale
const hA = boundsA.height * prev.props.scale
const wB = boundsB.width * next.props.scale
const hB = boundsB.height * next.props.scale
let delta: Vec | undefined
2023-04-25 11:01:25 +00:00
switch (next.props.align) {
case 'middle': {
delta = new Vec((wB - wA) / 2, textDidChange ? 0 : (hB - hA) / 2)
2023-04-25 11:01:25 +00:00
break
}
case 'end': {
delta = new Vec(wB - wA, textDidChange ? 0 : (hB - hA) / 2)
2023-04-25 11:01:25 +00:00
break
}
default: {
if (textDidChange) break
delta = new Vec(0, (hB - hA) / 2)
2023-04-25 11:01:25 +00:00
break
}
}
if (delta) {
// account for shape rotation when writing text:
delta.rot(next.rotation)
const { x, y } = next
return {
...next,
x: x - delta.x,
y: y - delta.y,
props: { ...next.props, w: wB },
}
} else {
return {
...next,
props: { ...next.props, w: wB },
}
}
}
tldraw zero - package shuffle (#1710) This PR moves code between our packages so that: - @tldraw/editor is a “core” library with the engine and canvas but no shapes, tools, or other things - @tldraw/tldraw contains everything particular to the experience we’ve built for tldraw At first look, this might seem like a step away from customization and configuration, however I believe it greatly increases the configuration potential of the @tldraw/editor while also providing a more accurate reflection of what configuration options actually exist for @tldraw/tldraw. ## Library changes @tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports @tldraw/editor. - users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always only import things from @tldraw/editor. - users of @tldraw/tldraw should almost always only import things from @tldraw/tldraw. - @tldraw/polyfills is merged into @tldraw/editor - @tldraw/indices is merged into @tldraw/editor - @tldraw/primitives is merged mostly into @tldraw/editor, partially into @tldraw/tldraw - @tldraw/file-format is merged into @tldraw/tldraw - @tldraw/ui is merged into @tldraw/tldraw Many (many) utils and other code is moved from the editor to tldraw. For example, embeds now are entirely an feature of @tldraw/tldraw. The only big chunk of code left in core is related to arrow handling. ## API Changes The editor can now be used without tldraw's assets. We load them in @tldraw/tldraw instead, so feel free to use whatever fonts or images or whatever that you like with the editor. All tools and shapes (except for the `Group` shape) are moved to @tldraw/tldraw. This includes the `select` tool. You should use the editor with at least one tool, however, so you now also need to send in an `initialState` prop to the Editor / <TldrawEditor> component indicating which state the editor should begin in. The `components` prop now also accepts `SelectionForeground`. The complex selection component that we use for tldraw is moved to @tldraw/tldraw. The default component is quite basic but can easily be replaced via the `components` prop. We pass down our tldraw-flavored SelectionFg via `components`. Likewise with the `Scribble` component: the `DefaultScribble` no longer uses our freehand tech and is a simple path instead. We pass down the tldraw-flavored scribble via `components`. The `ExternalContentManager` (`Editor.externalContentManager`) is removed and replaced with a mapping of types to handlers. - Register new content handlers with `Editor.registerExternalContentHandler`. - Register new asset creation handlers (for files and URLs) with `Editor.registerExternalAssetHandler` ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [@tldraw/editor] lots, wip - [@tldraw/ui] gone, merged to tldraw/tldraw - [@tldraw/polyfills] gone, merged to tldraw/editor - [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw - [@tldraw/indices] gone, merged to tldraw/editor - [@tldraw/file-format] gone, merged to tldraw/tldraw --------- Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
override onDoubleClickEdge = (shape: TLTextShape) => {
2023-04-25 11:01:25 +00:00
// If the shape has a fixed width, set it to autoSize.
if (!shape.props.autoSize) {
return {
id: shape.id,
type: shape.type,
props: {
autoSize: true,
},
}
}
// If the shape is scaled, reset the scale to 1.
if (shape.props.scale !== 1) {
return {
id: shape.id,
type: shape.type,
props: {
scale: 1,
},
}
}
}
}
function getTextSize(editor: Editor, props: TLTextShape['props']) {
2023-04-25 11:01:25 +00:00
const { font, text, autoSize, size, w } = props
const minWidth = autoSize ? 16 : Math.max(16, w)
2023-04-25 11:01:25 +00:00
const fontSize = FONT_SIZES[size]
const cw = autoSize
Fix text-wrapping on Safari (#1980) Co-authored-by: Alex Alex@dytry.ch closes [#1978](https://github.com/tldraw/tldraw/issues/1978) Text was wrapping on Safari because the measure text div was rendered differently on different browsers. Interestingly, when forcing the text-measure div to be visible and on-screen in Chrome, the same text-wrapping behaviour was apparent. By setting white-space to 'pre' when width hasn't been set by the user, we can ensure that only line breaks the user has inputted are rendered by default on all browsers. ### Change Type - [x] `patch` — Bug fix - [ ] `minor` — New feature - [ ] `major` — Breaking change - [ ] `dependencies` — Changes to package dependencies[^1] - [ ] `documentation` — Changes to the documentation only[^2] - [ ] `tests` — Changes to any test code only[^2] - [ ] `internal` — Any other changes that don't affect the published package[^2] - [ ] I don't know [^1]: publishes a `patch` release, for devDependencies use `internal` [^2]: will not publish a new version ### Test Plan 1. On Safari 2. Make a new text shape and start typing 3. At a certain point the text starts to wrap without the width having been set ### Release Notes - Fix text wrapping differently on Safari and Chrome/Firefox Before/After <image width="350" src="https://github.com/tldraw/tldraw/assets/98838967/320171b4-61e0-4a41-b8d3-830bd90bea65"> <image width="350" src="https://github.com/tldraw/tldraw/assets/98838967/b42d7156-0ce9-4894-9692-9338dc931b79">
2023-10-02 11:30:53 +00:00
? null
2023-04-25 11:01:25 +00:00
: // `measureText` floors the number so we need to do the same here to avoid issues.
Math.floor(Math.max(minWidth, w))
2023-04-25 11:01:25 +00:00
const result = editor.textMeasure.measureText(text, {
2023-04-25 11:01:25 +00:00
...TEXT_PROPS,
fontFamily: FONT_FAMILIES[font],
fontSize: fontSize,
maxWidth: cw,
2023-04-25 11:01:25 +00:00
})
// // If we're autosizing the measureText will essentially `Math.floor`
// // the numbers so `19` rather than `19.3`, this means we must +1 to
// // whatever we get to avoid wrapping.
if (autoSize) {
result.w += 1
}
return {
width: Math.max(minWidth, result.w),
height: Math.max(fontSize, result.h),
}
}
function useTextShapeKeydownHandler(id: TLShapeId) {
const editor = useEditor()
return useCallback(
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (editor.getEditingShapeId() !== id) return
switch (e.key) {
case 'Enter': {
if (e.ctrlKey || e.metaKey) {
editor.complete()
}
break
}
case 'Tab': {
preventDefault(e)
if (e.shiftKey) {
TextHelpers.unindent(e.currentTarget)
} else {
TextHelpers.indent(e.currentTarget)
}
break
}
}
},
[editor, id]
)
}