feat(core): add raster layer type

This commit is contained in:
syntaxbullet
2026-07-03 17:34:02 +02:00
parent c946fb4c93
commit 665f4a5340
10 changed files with 66 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ import {
documentAddAssetCommand, documentAddAssetCommand,
documentAddGroupLayerCommand, documentAddGroupLayerCommand,
documentAddImageLayerCommand, documentAddImageLayerCommand,
documentAddRasterLayerCommand,
documentGroupLayersCommand, documentGroupLayersCommand,
documentMoveLayerCommand, documentMoveLayerCommand,
documentRemoveArtboardCommand, documentRemoveArtboardCommand,
@@ -77,6 +78,32 @@ describe("document commands", () => {
expect(next.document.artboards[0]?.layers.map((layer) => layer.id)).toEqual(["l1"]); expect(next.document.artboards[0]?.layers.map((layer) => layer.id)).toEqual(["l1"]);
}); });
test("adds raster layers to artboards", () => {
const state = documentAddArtboardCommand.execute(
{ state: createInitialAppState("Test") },
{ id: "a1", name: "Artboard 1", bounds: { x: 0, y: 0, w: 320, h: 240 } },
);
const next = documentAddRasterLayerCommand.execute(
{ state },
{
artboardId: "a1",
layer: {
id: "r1",
type: "raster",
name: "Raster",
visible: true,
locked: false,
opacity: 1,
assetId: "asset-1",
transform: { position: { x: 10, y: 20 }, scale: { x: 1, y: 1 }, rotation: 0 },
},
},
);
expect(next.document.artboards[0]?.layers.map((layer) => layer.id)).toEqual(["r1"]);
});
test("adds group layers", () => { test("adds group layers", () => {
const state = documentAddArtboardCommand.execute( const state = documentAddArtboardCommand.execute(
{ state: createInitialAppState("Test") }, { state: createInitialAppState("Test") },

View File

@@ -4,6 +4,7 @@ import type { Rect } from "@core/geometry";
import type { ArtboardId, LayerId } from "@core/id"; import type { ArtboardId, LayerId } from "@core/id";
import type { ImageLayer } from "@core/image-layer"; import type { ImageLayer } from "@core/image-layer";
import type { Layer } from "@core/layer"; import type { Layer } from "@core/layer";
import type { RasterLayer } from "@core/raster-layer";
import type { LayerGroup } from "@core/layer-group"; import type { LayerGroup } from "@core/layer-group";
import type { Command } from "./command"; import type { Command } from "./command";
import { commandIds } from "./ids"; import { commandIds } from "./ids";
@@ -48,6 +49,12 @@ export type DocumentAddImageLayerPayload = {
layer: ImageLayer; layer: ImageLayer;
}; };
export type DocumentAddRasterLayerPayload = {
artboardId: ArtboardId;
parentGroupId?: LayerId;
layer: RasterLayer;
};
export type DocumentAddGroupLayerPayload = { export type DocumentAddGroupLayerPayload = {
artboardId: ArtboardId; artboardId: ArtboardId;
parentGroupId?: LayerId; parentGroupId?: LayerId;
@@ -223,6 +230,17 @@ export const documentAddImageLayerCommand: Command<DocumentAddImageLayerPayload>
}, },
}; };
export const documentAddRasterLayerCommand: Command<DocumentAddRasterLayerPayload> = {
id: commandIds.documentAddRasterLayer,
name: "Add raster layer",
execute({ state }, payload) {
return {
...state,
document: insertLayer(state.document, payload.artboardId, payload.parentGroupId, payload.layer),
};
},
};
export const documentAddGroupLayerCommand: Command<DocumentAddGroupLayerPayload> = { export const documentAddGroupLayerCommand: Command<DocumentAddGroupLayerPayload> = {
id: commandIds.documentAddGroupLayer, id: commandIds.documentAddGroupLayer,
name: "Add group layer", name: "Add group layer",
@@ -389,6 +407,7 @@ export const documentCommands = [
documentRenameArtboardCommand, documentRenameArtboardCommand,
documentAddAssetCommand, documentAddAssetCommand,
documentAddImageLayerCommand, documentAddImageLayerCommand,
documentAddRasterLayerCommand,
documentAddGroupLayerCommand, documentAddGroupLayerCommand,
documentMoveLayerCommand, documentMoveLayerCommand,
documentGroupLayersCommand, documentGroupLayersCommand,

View File

@@ -7,6 +7,7 @@ export const commandIds = {
documentRenameArtboard: "document.renameArtboard", documentRenameArtboard: "document.renameArtboard",
documentAddAsset: "document.addAsset", documentAddAsset: "document.addAsset",
documentAddImageLayer: "document.addImageLayer", documentAddImageLayer: "document.addImageLayer",
documentAddRasterLayer: "document.addRasterLayer",
documentAddGroupLayer: "document.addGroupLayer", documentAddGroupLayer: "document.addGroupLayer",
documentMoveLayer: "document.moveLayer", documentMoveLayer: "document.moveLayer",
documentGroupLayers: "document.groupLayers", documentGroupLayers: "document.groupLayers",

View File

@@ -4,6 +4,7 @@ export {
documentAddAssetCommand, documentAddAssetCommand,
documentAddGroupLayerCommand, documentAddGroupLayerCommand,
documentAddImageLayerCommand, documentAddImageLayerCommand,
documentAddRasterLayerCommand,
documentCommands, documentCommands,
documentGroupLayersCommand, documentGroupLayersCommand,
documentMoveLayerCommand, documentMoveLayerCommand,
@@ -24,6 +25,7 @@ export type {
DocumentAddAssetPayload, DocumentAddAssetPayload,
DocumentAddGroupLayerPayload, DocumentAddGroupLayerPayload,
DocumentAddImageLayerPayload, DocumentAddImageLayerPayload,
DocumentAddRasterLayerPayload,
DocumentGroupLayersPayload, DocumentGroupLayersPayload,
DocumentMoveLayerPayload, DocumentMoveLayerPayload,
DocumentRemoveArtboardPayload, DocumentRemoveArtboardPayload,

View File

@@ -4,6 +4,7 @@ import type {
DocumentAddAssetPayload, DocumentAddAssetPayload,
DocumentAddGroupLayerPayload, DocumentAddGroupLayerPayload,
DocumentAddImageLayerPayload, DocumentAddImageLayerPayload,
DocumentAddRasterLayerPayload,
DocumentGroupLayersPayload, DocumentGroupLayersPayload,
DocumentMoveLayerPayload, DocumentMoveLayerPayload,
DocumentRemoveArtboardPayload, DocumentRemoveArtboardPayload,
@@ -38,6 +39,7 @@ export type CommandPayloads = {
[commandIds.documentRenameArtboard]: DocumentRenameArtboardPayload; [commandIds.documentRenameArtboard]: DocumentRenameArtboardPayload;
[commandIds.documentAddAsset]: DocumentAddAssetPayload; [commandIds.documentAddAsset]: DocumentAddAssetPayload;
[commandIds.documentAddImageLayer]: DocumentAddImageLayerPayload; [commandIds.documentAddImageLayer]: DocumentAddImageLayerPayload;
[commandIds.documentAddRasterLayer]: DocumentAddRasterLayerPayload;
[commandIds.documentAddGroupLayer]: DocumentAddGroupLayerPayload; [commandIds.documentAddGroupLayer]: DocumentAddGroupLayerPayload;
[commandIds.documentMoveLayer]: DocumentMoveLayerPayload; [commandIds.documentMoveLayer]: DocumentMoveLayerPayload;
[commandIds.documentGroupLayers]: DocumentGroupLayersPayload; [commandIds.documentGroupLayers]: DocumentGroupLayersPayload;

View File

@@ -16,3 +16,4 @@ export type { ArtboardId, AssetId, DocumentId, LayerId } from "./id";
export type { ImageLayer } from "./image-layer"; export type { ImageLayer } from "./image-layer";
export type { Layer } from "./layer"; export type { Layer } from "./layer";
export type { LayerGroup } from "./layer-group"; export type { LayerGroup } from "./layer-group";
export type { RasterLayer } from "./raster-layer";

View File

@@ -1,4 +1,5 @@
import type { ImageLayer } from "./image-layer"; import type { ImageLayer } from "./image-layer";
import type { LayerGroup } from "./layer-group"; import type { LayerGroup } from "./layer-group";
import type { RasterLayer } from "./raster-layer";
export type Layer = ImageLayer | LayerGroup; export type Layer = ImageLayer | RasterLayer | LayerGroup;

7
core/raster-layer.ts Normal file
View File

@@ -0,0 +1,7 @@
import type { BaseLayer } from "./base-layer";
import type { AssetId } from "./id";
export type RasterLayer = BaseLayer & {
type: "raster";
assetId: AssetId;
};

View File

@@ -45,7 +45,7 @@ function applyLayerBounds(document: ImageDocument, layerId: LayerId, bounds: Rec
function applyLayerBoundsInTree(document: ImageDocument, layers: Layer[], layerId: LayerId, bounds: Rect): Layer[] { function applyLayerBoundsInTree(document: ImageDocument, layers: Layer[], layerId: LayerId, bounds: Rect): Layer[] {
return layers.map((layer) => { return layers.map((layer) => {
if (layer.id === layerId && layer.type === "image") { if (layer.id === layerId && (layer.type === "image" || layer.type === "raster")) {
const asset = document.assets.find((candidate) => candidate.id === layer.assetId); const asset = document.assets.find((candidate) => candidate.id === layer.assetId);
if (!asset) return layer; if (!asset) return layer;
@@ -95,7 +95,8 @@ function resolveLayerBounds(document: ImageDocument, layer: Layer): Rect | undef
const bounds = resolveLayerBounds(document, child); const bounds = resolveLayerBounds(document, child);
return bounds ? [bounds] : []; return bounds ? [bounds] : [];
})); }));
case "image": { case "image":
case "raster": {
const asset = document.assets.find((candidate) => candidate.id === layer.assetId); const asset = document.assets.find((candidate) => candidate.id === layer.assetId);
if (!asset) return undefined; if (!asset) return undefined;

View File

@@ -344,12 +344,12 @@ function addLayer(document: ImageDocument, artboardId: ArtboardId, selectedLayer
intrinsicSize: { w: width, h: height }, intrinsicSize: { w: width, h: height },
}, },
}); });
dispatch(commandIds.documentAddImageLayer, { dispatch(commandIds.documentAddRasterLayer, {
artboardId, artboardId,
parentGroupId: selectedLayer?.layer.type === "group" ? selectedLayer.layer.id : undefined, parentGroupId: selectedLayer?.layer.type === "group" ? selectedLayer.layer.id : undefined,
layer: { layer: {
id: layerId, id: layerId,
type: "image", type: "raster",
name: "Layer", name: "Layer",
visible: true, visible: true,
locked: false, locked: false,