feat(masks): add mask editing mode
This commit is contained in:
@@ -77,7 +77,14 @@ export function App({ app }: AppProps) {
|
||||
dispatch={app.store.dispatch}
|
||||
/>
|
||||
</div>
|
||||
<LayersSheet document={state.document} selection={state.editor.selection} open={layersOpen} dispatch={app.store.dispatch} onClose={() => setLayersOpen(false)} />
|
||||
<LayersSheet
|
||||
document={state.document}
|
||||
selection={state.editor.selection}
|
||||
maskEditLayerId={state.editor.maskEditLayerId}
|
||||
open={layersOpen}
|
||||
dispatch={app.store.dispatch}
|
||||
onClose={() => setLayersOpen(false)}
|
||||
/>
|
||||
<div className="absolute inset-x-0 bottom-4 z-10 flex justify-center">
|
||||
<BottomControlsIsland
|
||||
viewport={state.editor.viewport}
|
||||
|
||||
@@ -12,12 +12,13 @@ import { downloadArtboardPng } from "./exportArtboardPng";
|
||||
export type LayersSheetProps = {
|
||||
document: ImageDocument;
|
||||
selection: SelectionState;
|
||||
maskEditLayerId?: string;
|
||||
open: boolean;
|
||||
dispatch: AppStore["dispatch"];
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export function LayersSheet({ document, selection, open, dispatch, onClose }: LayersSheetProps) {
|
||||
export function LayersSheet({ document, selection, maskEditLayerId, open, dispatch, onClose }: LayersSheetProps) {
|
||||
const selectedArtboardId = selection.artboardId ?? document.artboards[0]?.id;
|
||||
const selectedLayer = findLayerInfoInDocument(document, selection.layerIds[0]);
|
||||
const canGroup = Boolean(selection.artboardId && selection.layerIds.length > 0);
|
||||
@@ -137,6 +138,7 @@ export function LayersSheet({ document, selection, open, dispatch, onClose }: La
|
||||
editingTitle={editingTitle}
|
||||
setEditingTitle={setEditingTitle}
|
||||
selectedMaskLayer={selectedLayer}
|
||||
maskEditLayerId={maskEditLayerId}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
))
|
||||
@@ -159,6 +161,7 @@ function LayerRow({
|
||||
editingTitle,
|
||||
setEditingTitle,
|
||||
selectedMaskLayer,
|
||||
maskEditLayerId,
|
||||
dispatch,
|
||||
}: {
|
||||
document: ImageDocument;
|
||||
@@ -170,6 +173,7 @@ function LayerRow({
|
||||
editingTitle: EditingTitle | undefined;
|
||||
setEditingTitle: (editingTitle: EditingTitle | undefined) => void;
|
||||
selectedMaskLayer?: LayerInfo;
|
||||
maskEditLayerId?: string;
|
||||
dispatch: AppStore["dispatch"];
|
||||
}) {
|
||||
const selected = selectedLayerIds.includes(layer.id);
|
||||
@@ -178,6 +182,7 @@ function LayerRow({
|
||||
const maskIndent = maskLayer ? 24 : 0;
|
||||
const canSetMask =
|
||||
Boolean(selectedMaskLayer && layerInfo && selectedMaskLayer.layer.id !== layer.id && selectedMaskLayer.artboardId === layerInfo.artboardId && selectedMaskLayer.parentGroupId === layerInfo.parentGroupId);
|
||||
const editingMask = maskEditLayerId === layer.clippingMask?.maskLayerId;
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
@@ -244,6 +249,13 @@ function LayerRow({
|
||||
<div className="mt-1 flex items-center gap-2 text-xs text-sky-100/60" style={{ paddingLeft: 52 + depth * 16 + maskIndent }}>
|
||||
<span className="h-px w-5 bg-sky-200/25" />
|
||||
<span>masked by {maskLayer.name}</span>
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded-full px-2 py-0.5 transition ${editingMask ? "bg-sky-300 text-black" : "bg-sky-400/10 text-sky-100/75 hover:bg-sky-400/20 hover:text-sky-50"}`}
|
||||
onClick={() => dispatch(commandIds.toolSetMaskEditLayer, { layerId: editingMask ? undefined : layer.clippingMask?.maskLayerId })}
|
||||
>
|
||||
{editingMask ? "Editing mask" : "Edit mask"}
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
{layer.type === "group"
|
||||
@@ -259,6 +271,7 @@ function LayerRow({
|
||||
editingTitle={editingTitle}
|
||||
setEditingTitle={setEditingTitle}
|
||||
selectedMaskLayer={selectedMaskLayer}
|
||||
maskEditLayerId={maskEditLayerId}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
))
|
||||
|
||||
@@ -15,7 +15,7 @@ export type BrushSession = {
|
||||
|
||||
export function beginBrushSession(document: ImageDocument, editor: EditorState, point: Vec2D): BrushSession | undefined {
|
||||
if (isPanInteractionMode(editor.tools.interactionMode) || (editor.tools.activeTool !== "brush" && editor.tools.activeTool !== "eraser")) return undefined;
|
||||
const layerId = editor.selection.layerIds[0];
|
||||
const layerId = editor.maskEditLayerId ?? editor.selection.layerIds[0];
|
||||
if (!layerId) return undefined;
|
||||
const layer = findRasterLayer(document.artboards.flatMap((artboard) => artboard.layers), layerId);
|
||||
if (!layer || layer.locked || !layer.visible) return undefined;
|
||||
@@ -43,7 +43,7 @@ export async function updateBrushSession(options: {
|
||||
height: asset.intrinsicSize.h,
|
||||
from: documentPointToAssetPoint(options.session.previousPoint, layer, asset.intrinsicSize.w, asset.intrinsicSize.h),
|
||||
to: documentPointToAssetPoint(options.point, layer, asset.intrinsicSize.w, asset.intrinsicSize.h),
|
||||
color: options.color,
|
||||
color: state.editor.maskEditLayerId ? "#ffffff" : options.color,
|
||||
size: options.size,
|
||||
hardness: options.hardness,
|
||||
mode: options.session.mode,
|
||||
|
||||
Reference in New Issue
Block a user