diff --git a/src/definitions/editor.ts b/src/definitions/editor.ts index 70c4362..6f41afe 100644 --- a/src/definitions/editor.ts +++ b/src/definitions/editor.ts @@ -142,4 +142,7 @@ export type WandToolOptions = { sampleMerged: boolean; }; -export type CopiedSelection = SizedImage & { type: LayerTypes }; \ No newline at end of file +export type CopiedSelection = { + bitmap: HTMLCanvasElement; + type: LayerTypes; +}; diff --git a/src/factories/history-state-factory.ts b/src/factories/history-state-factory.ts index d04aec9..21d61d2 100644 --- a/src/factories/history-state-factory.ts +++ b/src/factories/history-state-factory.ts @@ -20,8 +20,8 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { Store } from "vuex"; -import type { BitMapperyState } from "@/store"; +import { type Store } from "vuex"; +import { type BitMapperyState } from "@/store"; /** * a history state should provide undo and redo functions and an optional @@ -38,7 +38,7 @@ const stateQueue = new Map(); const ENQUEUE_TIMEOUT = 1000; let timeout = 0; -let store: Store; +let store: Store | undefined; export const initHistory = ( storeReference: Store ): void => { store = storeReference; @@ -87,6 +87,6 @@ export const enqueueState = ( key: string, undoRedoState: UndoRedoState ): void function processQueue(): void { window.clearTimeout( timeout ); - stateQueue.forEach( undoRedoState => store.commit( "saveState", undoRedoState )); + stateQueue.forEach( undoRedoState => store?.commit( "saveState", undoRedoState )); stateQueue.clear(); } diff --git a/src/store/index.ts b/src/store/index.ts index 8b5945c..912ad9c 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -39,7 +39,7 @@ import history, { HistoryState } from "./modules/history-module"; import image, { ImageState } from "./modules/image-module"; import preferences, { PreferencesState } from "./modules/preferences-module"; import tool, { ToolState } from "./modules/tool-module"; -import { cloneCanvas, imageToCanvas } from "@/utils/canvas-util"; +import { cloneCanvas } from "@/utils/canvas-util"; import { copySelection, deleteSelectionContent } from "@/utils/document-util"; import { saveBlobAsFile, selectFile } from "@/utils/file-util"; import { replaceLayerSource } from "@/utils/layer-util"; @@ -281,13 +281,14 @@ export default { }, pasteSelection({ commit, getters, dispatch, state }: ActionContext ): void { const selection = state.selectionContent; - const { image, size, type } = selection; + const { bitmap, type } = selection; const layer = LayerFactory.create({ type: ( !type || type === LayerTypes.LAYER_TEXT ) ? LayerTypes.LAYER_GRAPHIC : type, - source: imageToCanvas( image, size.width, size.height ), - ...size, - left: getters.activeDocument.width / 2 - size.width / 2, - top : getters.activeDocument.height / 2 - size.height / 2, + source: cloneCanvas( bitmap ), + width: bitmap.width, + height: bitmap.height, + left: getters.activeDocument.width / 2 - bitmap.width / 2, + top : getters.activeDocument.height / 2 - bitmap.height / 2, }); const index = getters.activeDocument.layers.length; const paste = () => { @@ -295,7 +296,7 @@ export default { dispatch( "clearSelection" ); }; paste(); - enqueueState( `paste_${selection.size.width}_${selection.size.height}`, { + enqueueState( `paste_${type}_${bitmap.width}_${bitmap.height}`, { undo() { commit( "setSelectionContent", selection ); commit( "removeLayer", index ); diff --git a/src/utils/document-util.ts b/src/utils/document-util.ts index cc10cb3..7b3e126 100644 --- a/src/utils/document-util.ts +++ b/src/utils/document-util.ts @@ -20,9 +20,7 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { canvas, loader } from "zcanvas"; -import type { Rectangle } from "zcanvas"; -import { PNG } from "@/definitions/image-types"; +import { canvas, type Rectangle } from "zcanvas"; import type { Document, Shape, Layer } from "@/definitions/document"; import type { CopiedSelection } from "@/definitions/editor"; import { renderEffectsForLayer } from "@/services/render-service"; @@ -202,10 +200,8 @@ export const copySelection = async ( activeDocument: Document, activeLayer: Laye ); zcvs.dispose(); - const output = await loader.loadImage( selectionCanvas.cvs.toDataURL( PNG.mime )); - return { - ...output, + bitmap: selectionCanvas.cvs, type: activeLayer.type, }; }; diff --git a/tests/unit/store/store.spec.ts b/tests/unit/store/store.spec.ts index 2f55f26..db1c436 100644 --- a/tests/unit/store/store.spec.ts +++ b/tests/unit/store/store.spec.ts @@ -1,5 +1,5 @@ import { it, beforeEach, describe, expect, afterAll, vi } from "vitest"; -import { mockZCanvas } from "../mocks"; +import { createMockCanvasElement, createState, mockZCanvas } from "../mocks"; import { type Layer } from "@/definitions/document"; import { type Dialog } from "@/definitions/editor"; import { SAVE_DOCUMENT } from "@/definitions/modal-windows"; @@ -10,7 +10,6 @@ import DocumentFactory from "@/factories/document-factory"; import LayerFactory from "@/factories/layer-factory"; import KeyboardService from "@/services/keyboard-service"; import store, { type BitMapperyState } from "@/store"; -import { createState, createMockImageElement } from "../mocks"; const { getters, mutations, actions } = store; @@ -28,6 +27,7 @@ vi.mock( "@/utils/file-util", () => ({ })); vi.mock("@/utils/canvas-util", () => ({ createCanvas: vi.fn(() => ({ cvs: {}, ctx: {} })), + cloneCanvas: vi.fn( cvs => cvs ), imageToBase64: vi.fn(), imageToCanvas: vi.fn(), base64ToLayerImage: vi.fn() @@ -83,7 +83,7 @@ describe( "Vuex store", () => { it( "should be able to set the current selection content", () => { const state = createState({ selectionContent: null }); - const selection = { image: createMockImageElement(), size: { width: 100, height: 50 }, type: LayerTypes.LAYER_GRAPHIC }; + const selection = { bitmap: createMockCanvasElement(), type: LayerTypes.LAYER_GRAPHIC }; mutations.setSelectionContent( state, selection ); expect( state.selectionContent ).toEqual( selection ); }); @@ -392,11 +392,7 @@ describe( "Vuex store", () => { beforeEach(() => { state = createState({ selectionContent: { - image: createMockImageElement(), - size: { - width: 40, - height: 30 - }, + bitmap: createMockCanvasElement(), type: LayerTypes.LAYER_GRAPHIC, }, });