Fix ActionButton bug
This commit is contained in:
parent
e2369003c6
commit
72b6fafcc1
2 changed files with 171 additions and 24 deletions
147
packages/tldraw/README.md
Normal file
147
packages/tldraw/README.md
Normal file
|
@ -0,0 +1,147 @@
|
|||
# @tldraw/tldraw
|
||||
|
||||
> `This library is not yet released and these docs are partially out of date!`
|
||||
|
||||
This package contains the [tldraw](https://tldraw.com) editor as a standalone React component.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm i @tldraw/tldraw
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
yarn add @tldraw/tldraw
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Import the `TLDraw` React component and use it in your app.
|
||||
|
||||
```tsx
|
||||
import { TLDraw } from '@tldraw/tldraw'
|
||||
|
||||
function App() {
|
||||
return <TLDraw />
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### `TLDraw`
|
||||
|
||||
The `TLDraw` React component is the [tldraw](https://tldraw.com) editor exported as a standalone component. You can control the editor through props, or through the `TLDrawState`'s imperative API.
|
||||
|
||||
| Prop | Type | Description |
|
||||
| --------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | `string` | (optional) An id under which to persist the component's state. |
|
||||
| `document` | `TLDrawDocument` | (optional) An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||
| `currentPageId` | `string` | (optional) A current page id, referencing the `TLDrawDocument` object provided via the `document` prop. |
|
||||
| `onMount` | `(TLDrawState) => void` | (optional) A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
||||
| `onChange` | `(TLDrawState, string) => void` | (optional) A callback function that will be called whenever the `TLDrawState` updates. The update will include the current `TLDrawState` and the reason for the change. |
|
||||
|
||||
### `TLDrawDocument`
|
||||
|
||||
A `TLDrawDocument` is an object with three properties:
|
||||
|
||||
- `id` - A unique ID for this document
|
||||
- `pages` - A table of `TLPage` objects
|
||||
- `pageStates` - A table of `TLPageState` objects
|
||||
|
||||
```ts
|
||||
const tldocument: TLDrawDocument = {
|
||||
id: 'doc',
|
||||
pages: {
|
||||
page1: {
|
||||
id: 'page1',
|
||||
shapes: {},
|
||||
bindings: {},
|
||||
},
|
||||
},
|
||||
pageStates: {
|
||||
page1: {
|
||||
id: 'page1',
|
||||
selectedIds: [],
|
||||
currentParentId: 'page1',
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Important:** In the `pages` object, each `TLPage` object must be keyed under its `id` property. Likewise, each `TLPageState` object must be keyed under its `id`. In addition, each `TLPageState` object must have an `id` that matches its corresponding page.
|
||||
|
||||
In the example above, the page above with the id `page1`is at `tldocument.pages["page1"]`. Its corresponding page state has the same id (`page1`) and is at `tldocument.pageStates["page1"]`.
|
||||
|
||||
### Shapes
|
||||
|
||||
Your `TLPage` objects may include shapes: objects that fit one of the `TLDrawShape` interfaces listed below. All `TLDrawShapes` extends a common interface:
|
||||
|
||||
| Property | Type | Description |
|
||||
| --------------------- | ------------ | --------------------------------------------------------------- |
|
||||
| `id` | `string` | A unique ID for the shape. |
|
||||
| `name` | `string` | The shape's name. |
|
||||
| `type` | `string` | The shape's type. |
|
||||
| `parentId` | `string` | The ID of the shape's parent (a shape or its page). |
|
||||
| `childIndex` | `number` | The shape's order within its parent's children, indexed from 1. |
|
||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||
| `handles` | `TLHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||
| `isLocked` | `boolean` | True if the shape is locked. |
|
||||
| `isHidden` | `boolean` | True if the shape is hidden. |
|
||||
| `isEditing` | `boolean` | True if the shape is currently editing. |
|
||||
| `isGenerated` | `boolean` | True if the shape is generated. |
|
||||
| `isAspectRatioLocked` | `boolean` | True if the shape's aspect ratio is locked. |
|
||||
|
||||
> **Important:** In order for re-ordering to work correctly, a shape's `childIndex` values _must_ start from 1, not 0. The page or parent shape's "bottom-most" child should have a `childIndex` of 1.
|
||||
|
||||
The `ShapeStyle` object is a common style API for all shapes.
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------- | ------------ | --------------------------------------- |
|
||||
| `size` | `SizeStyle` | The size of the shape's stroke. |
|
||||
| `dash` | `DashStyle` | The style of the shape's stroke. |
|
||||
| `color` | `ColorStyle` | The shape's color. |
|
||||
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
||||
|
||||
#### Draw
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ------------ | ----------------------------------------- |
|
||||
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
||||
|
||||
##### Rectangle
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ---------- | --------------------------------------- |
|
||||
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
||||
|
||||
#### Ellipse
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ---------- | ----------------------------------- |
|
||||
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
||||
|
||||
#### Arrow
|
||||
|
||||
| Property | Type | Description |
|
||||
| --------- | -------- | ----------------------------------------------------------------------- |
|
||||
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
||||
|
||||
#### Text
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | -------- | ------------------------- |
|
||||
| `text` | `string` | The shape's text content. |
|
||||
|
||||
## Development
|
||||
|
||||
### Running unit tests
|
||||
|
||||
Run `nx test tldraw` to execute the unit tests via [Jest](https://jestjs.io).
|
|
@ -62,12 +62,12 @@ const isAllGroupedSelector = (s: Data) => {
|
|||
)
|
||||
}
|
||||
|
||||
const hasSelectionSelector = (s: Data) => {
|
||||
const hasSelectionClickor = (s: Data) => {
|
||||
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
|
||||
return selectedIds.length > 0
|
||||
}
|
||||
|
||||
const hasMultipleSelectionSelector = (s: Data) => {
|
||||
const hasMultipleSelectionClickor = (s: Data) => {
|
||||
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
|
||||
return selectedIds.length > 1
|
||||
}
|
||||
|
@ -81,9 +81,9 @@ export function ActionButton(): JSX.Element {
|
|||
|
||||
const isAllGrouped = useSelector(isAllGroupedSelector)
|
||||
|
||||
const hasSelection = useSelector(hasSelectionSelector)
|
||||
const hasSelection = useSelector(hasSelectionClickor)
|
||||
|
||||
const hasMultipleSelection = useSelector(hasMultipleSelectionSelector)
|
||||
const hasMultipleSelection = useSelector(hasMultipleSelectionClickor)
|
||||
|
||||
const handleRotate = React.useCallback(() => {
|
||||
tlstate.rotate()
|
||||
|
@ -180,55 +180,55 @@ export function ActionButton(): JSX.Element {
|
|||
<DMContent>
|
||||
<>
|
||||
<ButtonsRow>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleDuplicate}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleDuplicate}>
|
||||
<Tooltip label="Duplicate" kbd={`#D`}>
|
||||
<CopyIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleRotate}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleRotate}>
|
||||
<Tooltip label="Rotate">
|
||||
<RotateCounterClockwiseIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleToggleLocked}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleToggleLocked}>
|
||||
<Tooltip label="Toogle Locked" kbd={`#L`}>
|
||||
{isAllLocked ? <LockClosedIcon /> : <LockOpen1Icon opacity={0.4} />}
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleToggleAspectRatio}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleToggleAspectRatio}>
|
||||
<Tooltip label="Toogle Aspect Ratio Lock">
|
||||
<AspectRatioIcon opacity={isAllAspectLocked ? 1 : 0.4} />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!isAllGrouped && !hasMultipleSelection} onSelect={handleGroup}>
|
||||
<IconButton disabled={!isAllGrouped && !hasMultipleSelection} onClick={handleGroup}>
|
||||
<Tooltip label="Group" kbd={`#G`}>
|
||||
<GroupIcon opacity={isAllGrouped ? 1 : 0.4} />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</ButtonsRow>
|
||||
<ButtonsRow>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleMoveToBack}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleMoveToBack}>
|
||||
<Tooltip label="Move to Back" kbd={`#⇧[`}>
|
||||
<PinBottomIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
|
||||
<IconButton disabled={!hasSelection} onSelect={handleMoveBackward}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleMoveBackward}>
|
||||
<Tooltip label="Move Backward" kbd={`#[`}>
|
||||
<ArrowDownIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleMoveForward}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleMoveForward}>
|
||||
<Tooltip label="Move Forward" kbd={`#]`}>
|
||||
<ArrowUpIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleMoveToFront}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleMoveToFront}>
|
||||
<Tooltip label="More to Front" kbd={`#⇧]`}>
|
||||
<PinTopIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasSelection} onSelect={handleDelete}>
|
||||
<IconButton disabled={!hasSelection} onClick={handleDelete}>
|
||||
<Tooltip label="Delete" kbd="⌫">
|
||||
<TrashIcon />
|
||||
</Tooltip>
|
||||
|
@ -236,36 +236,36 @@ export function ActionButton(): JSX.Element {
|
|||
</ButtonsRow>
|
||||
<Divider />
|
||||
<ButtonsRow>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={alignLeft}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={alignLeft}>
|
||||
<AlignLeftIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={alignCenterHorizontal}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={alignCenterHorizontal}>
|
||||
<AlignCenterHorizontallyIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={alignRight}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={alignRight}>
|
||||
<AlignRightIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={stretchHorizontally}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={stretchHorizontally}>
|
||||
<StretchHorizontallyIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasThreeOrMore} onSelect={distributeHorizontally}>
|
||||
<IconButton disabled={!hasThreeOrMore} onClick={distributeHorizontally}>
|
||||
<SpaceEvenlyHorizontallyIcon />
|
||||
</IconButton>
|
||||
</ButtonsRow>
|
||||
<ButtonsRow>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={alignTop}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={alignTop}>
|
||||
<AlignTopIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={alignCenterVertical}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={alignCenterVertical}>
|
||||
<AlignCenterVerticallyIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={alignBottom}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={alignBottom}>
|
||||
<AlignBottomIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasTwoOrMore} onSelect={stretchVertically}>
|
||||
<IconButton disabled={!hasTwoOrMore} onClick={stretchVertically}>
|
||||
<StretchVerticallyIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={!hasThreeOrMore} onSelect={distributeVertically}>
|
||||
<IconButton disabled={!hasThreeOrMore} onClick={distributeVertically}>
|
||||
<SpaceEvenlyVerticallyIcon />
|
||||
</IconButton>
|
||||
</ButtonsRow>
|
||||
|
|
Loading…
Reference in a new issue