feat(draw): lock shape
This commit is contained in:
@@ -22,3 +22,4 @@ export * from './translate-shapes';
|
|||||||
export * from './ungroup-shapes';
|
export * from './ungroup-shapes';
|
||||||
export * from './update-shapes';
|
export * from './update-shapes';
|
||||||
export * from './set-shapes-props';
|
export * from './set-shapes-props';
|
||||||
|
export * from './set-shapes-lock-status';
|
||||||
|
|||||||
59
libs/components/board-commands/src/set-shapes-lock-status.ts
Normal file
59
libs/components/board-commands/src/set-shapes-lock-status.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import type {
|
||||||
|
TDShape,
|
||||||
|
TldrawCommand,
|
||||||
|
} from '@toeverything/components/board-types';
|
||||||
|
import type { TldrawApp } from '@toeverything/components/board-state';
|
||||||
|
|
||||||
|
export function setShapesLockStatus<T extends TDShape>(
|
||||||
|
app: TldrawApp,
|
||||||
|
ids: string[],
|
||||||
|
isLocked: boolean
|
||||||
|
): TldrawCommand {
|
||||||
|
const { currentPageId, selectedIds } = app;
|
||||||
|
|
||||||
|
const initialShapes = ids.map(id => app.getShape<T>(id));
|
||||||
|
|
||||||
|
const before: Record<string, Partial<TDShape>> = {};
|
||||||
|
const after: Record<string, Partial<TDShape>> = {};
|
||||||
|
|
||||||
|
initialShapes.forEach(shape => {
|
||||||
|
before[shape.id] = {
|
||||||
|
isLocked: shape.isLocked,
|
||||||
|
};
|
||||||
|
after[shape.id] = {
|
||||||
|
isLocked,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: 'set_shapes_lock_status',
|
||||||
|
before: {
|
||||||
|
document: {
|
||||||
|
pages: {
|
||||||
|
[currentPageId]: {
|
||||||
|
shapes: before,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pageStates: {
|
||||||
|
[currentPageId]: {
|
||||||
|
selectedIds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
after: {
|
||||||
|
document: {
|
||||||
|
pages: {
|
||||||
|
[currentPageId]: {
|
||||||
|
shapes: after,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pageStates: {
|
||||||
|
[currentPageId]: {
|
||||||
|
selectedIds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import { FontSizeConfig } from './FontSizeConfig';
|
|||||||
import { StrokeLineStyleConfig } from './stroke-line-style-config';
|
import { StrokeLineStyleConfig } from './stroke-line-style-config';
|
||||||
import { Group, UnGroup } from './GroupOperation';
|
import { Group, UnGroup } from './GroupOperation';
|
||||||
import { DeleteShapes } from './DeleteOperation';
|
import { DeleteShapes } from './DeleteOperation';
|
||||||
|
import { Lock, Unlock } from './LockOperation';
|
||||||
|
|
||||||
export const CommandPanel: FC<{ app: TldrawApp }> = ({ app }) => {
|
export const CommandPanel: FC<{ app: TldrawApp }> = ({ app }) => {
|
||||||
const state = app.useStore();
|
const state = app.useStore();
|
||||||
@@ -63,6 +64,16 @@ export const CommandPanel: FC<{ app: TldrawApp }> = ({ app }) => {
|
|||||||
shapes={config.ungroup.selectedShapes}
|
shapes={config.ungroup.selectedShapes}
|
||||||
/>
|
/>
|
||||||
) : null,
|
) : null,
|
||||||
|
lock: config.lock.selectedShapes.length ? (
|
||||||
|
<Lock key="lock" app={app} shapes={config.lock.selectedShapes} />
|
||||||
|
) : null,
|
||||||
|
unlock: config.unlock.selectedShapes.length ? (
|
||||||
|
<Unlock
|
||||||
|
key="unlock"
|
||||||
|
app={app}
|
||||||
|
shapes={config.unlock.selectedShapes}
|
||||||
|
/>
|
||||||
|
) : null,
|
||||||
delete: (
|
delete: (
|
||||||
<DeleteShapes
|
<DeleteShapes
|
||||||
key="deleteShapes"
|
key="deleteShapes"
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import type { FC } from 'react';
|
||||||
|
import type { TldrawApp } from '@toeverything/components/board-state';
|
||||||
|
import type { TDShape } from '@toeverything/components/board-types';
|
||||||
|
import { IconButton, Tooltip } from '@toeverything/components/ui';
|
||||||
|
import { LockIcon, UnlockIcon } from '@toeverything/components/icons';
|
||||||
|
import { getShapeIds } from './utils';
|
||||||
|
|
||||||
|
interface GroupAndUnGroupProps {
|
||||||
|
app: TldrawApp;
|
||||||
|
shapes: TDShape[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Lock: FC<GroupAndUnGroupProps> = ({ app, shapes }) => {
|
||||||
|
const lock = () => {
|
||||||
|
app.lock(getShapeIds(shapes));
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Tooltip content="Lock">
|
||||||
|
<IconButton onClick={lock}>
|
||||||
|
<UnlockIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Unlock: FC<GroupAndUnGroupProps> = ({ app, shapes }) => {
|
||||||
|
const unlock = () => {
|
||||||
|
app.unlock(getShapeIds(shapes));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip content="Unlock">
|
||||||
|
<IconButton onClick={unlock}>
|
||||||
|
<LockIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -4,7 +4,15 @@ import { TDShapeType } from '@toeverything/components/board-types';
|
|||||||
import { TLDR } from '@toeverything/components/board-state';
|
import { TLDR } from '@toeverything/components/board-state';
|
||||||
|
|
||||||
interface Config {
|
interface Config {
|
||||||
type: 'stroke' | 'fill' | 'font' | 'group' | 'ungroup' | 'deleteShapes';
|
type:
|
||||||
|
| 'stroke'
|
||||||
|
| 'fill'
|
||||||
|
| 'font'
|
||||||
|
| 'group'
|
||||||
|
| 'ungroup'
|
||||||
|
| 'deleteShapes'
|
||||||
|
| 'lock'
|
||||||
|
| 'unlock';
|
||||||
selectedShapes: TDShape[];
|
selectedShapes: TDShape[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +42,14 @@ const _createInitConfig = (): Record<Config['type'], Config> => {
|
|||||||
type: 'deleteShapes',
|
type: 'deleteShapes',
|
||||||
selectedShapes: [],
|
selectedShapes: [],
|
||||||
},
|
},
|
||||||
|
lock: {
|
||||||
|
type: 'lock',
|
||||||
|
selectedShapes: [],
|
||||||
|
},
|
||||||
|
unlock: {
|
||||||
|
type: 'unlock',
|
||||||
|
selectedShapes: [],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,6 +80,17 @@ const _isSupportFill = (shape: TDShape): boolean => {
|
|||||||
].some(type => type === shape.type);
|
].some(type => type === shape.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _isSupportFont = (shape: TDShape): boolean => {
|
||||||
|
return [
|
||||||
|
TDShapeType.Rectangle,
|
||||||
|
TDShapeType.Ellipse,
|
||||||
|
TDShapeType.Hexagon,
|
||||||
|
TDShapeType.Triangle,
|
||||||
|
TDShapeType.WhiteArrow,
|
||||||
|
TDShapeType.Pentagram,
|
||||||
|
].some(type => type === shape.type);
|
||||||
|
};
|
||||||
|
|
||||||
export const useConfig = (app: TldrawApp): Record<Config['type'], Config> => {
|
export const useConfig = (app: TldrawApp): Record<Config['type'], Config> => {
|
||||||
const state = app.useStore();
|
const state = app.useStore();
|
||||||
const selectedShapes = TLDR.get_selected_shapes(state, app.currentPageId);
|
const selectedShapes = TLDR.get_selected_shapes(state, app.currentPageId);
|
||||||
@@ -74,6 +101,8 @@ export const useConfig = (app: TldrawApp): Record<Config['type'], Config> => {
|
|||||||
}
|
}
|
||||||
if (_isSupportFill(cur)) {
|
if (_isSupportFill(cur)) {
|
||||||
acc.fill.selectedShapes.push(cur);
|
acc.fill.selectedShapes.push(cur);
|
||||||
|
}
|
||||||
|
if (_isSupportFont(cur)) {
|
||||||
acc.font.selectedShapes.push(cur);
|
acc.font.selectedShapes.push(cur);
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
@@ -81,6 +110,7 @@ export const useConfig = (app: TldrawApp): Record<Config['type'], Config> => {
|
|||||||
_createInitConfig()
|
_createInitConfig()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// group
|
||||||
if (
|
if (
|
||||||
selectedShapes.length === 1 &&
|
selectedShapes.length === 1 &&
|
||||||
selectedShapes[0].type === TDShapeType.Group
|
selectedShapes[0].type === TDShapeType.Group
|
||||||
@@ -91,6 +121,13 @@ export const useConfig = (app: TldrawApp): Record<Config['type'], Config> => {
|
|||||||
config.group.selectedShapes = selectedShapes;
|
config.group.selectedShapes = selectedShapes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lock
|
||||||
|
if (selectedShapes.length === 1 && selectedShapes[0].isLocked) {
|
||||||
|
config.unlock.selectedShapes = selectedShapes;
|
||||||
|
} else {
|
||||||
|
config.lock.selectedShapes = selectedShapes;
|
||||||
|
}
|
||||||
|
|
||||||
config.deleteShapes.selectedShapes = selectedShapes;
|
config.deleteShapes.selectedShapes = selectedShapes;
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|||||||
@@ -3577,6 +3577,24 @@ export class TldrawApp extends StateManager<TDSnapshot> {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lock = (ids = this.selectedIds): this => {
|
||||||
|
if (ids.length === 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return this.set_state(
|
||||||
|
this.commands.setShapesLockStatus(this, ids, true)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
unlock = (ids = this.selectedIds): this => {
|
||||||
|
if (ids.length === 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return this.set_state(
|
||||||
|
this.commands.setShapesLockStatus(this, ids, false)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle the fixed-aspect-ratio property of one or more shapes.
|
* Toggle the fixed-aspect-ratio property of one or more shapes.
|
||||||
* @param ids The ids to change (defaults to selection).
|
* @param ids The ids to change (defaults to selection).
|
||||||
|
|||||||
@@ -102,4 +102,9 @@ export interface Commands {
|
|||||||
updates: ({ id: string } & Partial<TDShape>)[],
|
updates: ({ id: string } & Partial<TDShape>)[],
|
||||||
pageId: string
|
pageId: string
|
||||||
): TldrawCommand;
|
): TldrawCommand;
|
||||||
|
setShapesLockStatus(
|
||||||
|
app: TldrawApp,
|
||||||
|
ids: string[],
|
||||||
|
isLocked: boolean
|
||||||
|
): TldrawCommand;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user