@nextcloud/image-editor 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +156 -0
- package/dist/assets/index.css +509 -0
- package/dist/index.cjs +4690 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +233 -0
- package/dist/index.mjs +4683 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +105 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../lib/composables/useHistory.ts","../lib/utils/id.ts","../lib/editor/state.ts","../lib/components/base/GlassSurface.vue","../node_modules/vue-material-design-icons/ContrastCircle.vue","../node_modules/vue-material-design-icons/InvertColors.vue","../node_modules/vue-material-design-icons/WhiteBalanceSunny.vue","../lib/components/base/EditorSlider.vue","../lib/components/base/IconTab.vue","../lib/utils/l10n.ts","../lib/editor/view.ts","../lib/editor/context.ts","../lib/components/panels/AdjustPanel.vue","../node_modules/vue-material-design-icons/ArrowTopRight.vue","../node_modules/vue-material-design-icons/EllipseOutline.vue","../node_modules/vue-material-design-icons/FormatText.vue","../node_modules/vue-material-design-icons/Pencil.vue","../node_modules/vue-material-design-icons/RectangleOutline.vue","../lib/composables/useAnnotationColor.ts","../lib/components/panels/AnnotatePanel.vue","../node_modules/vue-material-design-icons/FlipHorizontal.vue","../node_modules/vue-material-design-icons/FlipVertical.vue","../node_modules/vue-material-design-icons/RotateLeft.vue","../node_modules/vue-material-design-icons/RotateRight.vue","../lib/editor/commands.ts","../lib/components/panels/CropPanel.vue","../lib/components/base/PresetChip.vue","../lib/editor/filters.ts","../lib/editor/render.ts","../lib/components/panels/FilterStrip.vue","../lib/components/panels/RedactPanel.vue","../lib/components/panels/SelectPanel.vue","../lib/components/panels/StickerPanel.vue","../lib/components/EditorPanel.vue","../node_modules/vue-material-design-icons/Blur.vue","../node_modules/vue-material-design-icons/Crop.vue","../node_modules/vue-material-design-icons/CursorDefaultOutline.vue","../node_modules/vue-material-design-icons/PaletteOutline.vue","../node_modules/vue-material-design-icons/StickerEmoji.vue","../node_modules/vue-material-design-icons/Tune.vue","../lib/components/EditorSidebar.vue","../node_modules/vue-material-design-icons/Check.vue","../node_modules/vue-material-design-icons/Close.vue","../node_modules/vue-material-design-icons/History.vue","../node_modules/vue-material-design-icons/MagnifyMinusOutline.vue","../node_modules/vue-material-design-icons/MagnifyPlusOutline.vue","../node_modules/vue-material-design-icons/Redo.vue","../node_modules/vue-material-design-icons/Restore.vue","../node_modules/vue-material-design-icons/Undo.vue","../lib/components/EditorTopBar.vue","../node_modules/vue-material-design-icons/ContentCopy.vue","../node_modules/vue-material-design-icons/Delete.vue","../lib/components/SelectionToolbar.vue","../lib/components/TextOverlay.vue","../lib/utils/theme.ts","../lib/composables/useAmbient.ts","../lib/composables/useAnnouncements.ts","../lib/utils/dom.ts","../lib/composables/useEditorShortcuts.ts","../lib/utils/image.ts","../lib/composables/useExportImage.ts","../lib/composables/useTextEditing.ts","../lib/composables/useWheelControls.ts","../lib/editor/animate.ts","../lib/editor/cropOverlay.ts","../lib/utils/geometry.ts","../lib/editor/orient.ts","../lib/editor/selection.ts","../lib/editor/tools.ts","../lib/components/ImageEditor.vue"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { ComputedRef } from 'vue'\n\nimport { computed, shallowRef } from 'vue'\n\nexport interface HistoryEntry<T> {\n\t/** The recorded state */\n\tsnapshot: T\n\t/**\n\t * What the user did to get here, already translated. Undefined for\n\t * a step whose call site did not name it.\n\t */\n\tlabel?: string\n}\n\nexport interface UseHistory<T> {\n\t/** Whether an older snapshot is available */\n\tcanUndo: ComputedRef<boolean>\n\t/** Whether a newer snapshot is available */\n\tcanRedo: ComputedRef<boolean>\n\t/** The active snapshot, undefined while the history is empty */\n\tcurrent: ComputedRef<T | undefined>\n\t/** Every recorded step, oldest first */\n\tentries: ComputedRef<readonly HistoryEntry<T>[]>\n\t/** Position of the active step in entries, -1 while empty */\n\tindex: ComputedRef<number>\n\t/**\n\t * Append a snapshot after the active one, discarding any redoable\n\t * entries.\n\t *\n\t * @param snapshot the state to record\n\t * @param label what the user did, for a history list\n\t */\n\tpush(snapshot: T, label?: string): void\n\t/** Move back one snapshot and return it, or undefined at the oldest entry */\n\tundo(): T | undefined\n\t/** Move forward one snapshot and return it, or undefined at the newest entry */\n\tredo(): T | undefined\n\t/**\n\t * Move to an arbitrary step and return its snapshot, or undefined\n\t * where there is no such step or it is the active one already.\n\t *\n\t * @param target position in entries\n\t */\n\tjumpTo(target: number): T | undefined\n\t/** Drop all snapshots */\n\tclear(): void\n}\n\n/**\n * Linear undo/redo history of immutable state snapshots.\n *\n * Snapshots are treated as opaque immutable values. Whatever is pushed\n * must not be mutated afterwards, or the history it sits in changes\n * under the caller; pushing a reference to a value the caller keeps\n * building new versions of is fine, and cheaper than copying.\n *\n * @param capacity maximum number of snapshots kept, oldest dropped first\n */\nexport function useHistory<T>(capacity = 100): UseHistory<T> {\n\tif (!Number.isInteger(capacity) || capacity < 1) {\n\t\tthrow new RangeError('History capacity must be a positive integer')\n\t}\n\n\tconst entries = shallowRef<HistoryEntry<T>[]>([])\n\tconst index = shallowRef(-1)\n\n\tconst canUndo = computed(() => index.value > 0)\n\tconst canRedo = computed(() => index.value < entries.value.length - 1)\n\tconst current = computed<T | undefined>(() => entries.value[index.value]?.snapshot)\n\n\t/**\n\t * Append a snapshot after the active one, discarding any redoable entries.\n\t *\n\t * @param snapshot the state to record\n\t * @param label what the user did, for a history list\n\t */\n\tfunction push(snapshot: T, label?: string): void {\n\t\tconst kept = [...entries.value.slice(0, index.value + 1), { snapshot, label }]\n\t\tentries.value = kept.slice(Math.max(0, kept.length - capacity))\n\t\tindex.value = entries.value.length - 1\n\t}\n\n\t/**\n\t * Move to an arbitrary step and return its snapshot.\n\t *\n\t * @param target position in entries\n\t */\n\tfunction jumpTo(target: number): T | undefined {\n\t\tif (target === index.value || target < 0 || target >= entries.value.length) {\n\t\t\treturn undefined\n\t\t}\n\t\tindex.value = target\n\t\treturn current.value\n\t}\n\n\t/**\n\t * Move back one snapshot and return it, or undefined at the oldest entry.\n\t */\n\tfunction undo(): T | undefined {\n\t\treturn canUndo.value ? jumpTo(index.value - 1) : undefined\n\t}\n\n\t/**\n\t * Move forward one snapshot and return it, or undefined at the newest entry.\n\t */\n\tfunction redo(): T | undefined {\n\t\treturn canRedo.value ? jumpTo(index.value + 1) : undefined\n\t}\n\n\t/**\n\t * Drop all snapshots.\n\t */\n\tfunction clear(): void {\n\t\tentries.value = []\n\t\tindex.value = -1\n\t}\n\n\treturn {\n\t\tcanUndo,\n\t\tcanRedo,\n\t\tcurrent,\n\t\tentries: computed(() => entries.value),\n\t\tindex: computed(() => index.value),\n\t\tpush,\n\t\tundo,\n\t\tredo,\n\t\tjumpTo,\n\t\tclear,\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/**\n * A unique id for an annotation.\n *\n * crypto.randomUUID is only exposed in a secure context, and a\n * Nextcloud instance served over plain HTTP on a local network is not\n * one. There it is undefined, and calling it threw on every annotation\n * the user tried to create. crypto.getRandomValues has no such\n * restriction, so it carries the fallback.\n */\nexport function newId(): string {\n\tif (typeof crypto.randomUUID === 'function') {\n\t\treturn crypto.randomUUID()\n\t}\n\treturn [...crypto.getRandomValues(new Uint8Array(16))]\n\t\t.map((byte) => byte.toString(16).padStart(2, '0'))\n\t\t.join('')\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { newId } from '../utils/id.ts'\n\nexport type Rotation = 0 | 90 | 180 | 270\n\nexport interface Size {\n\twidth: number\n\theight: number\n}\n\nexport interface Rect {\n\tx: number\n\ty: number\n\twidth: number\n\theight: number\n}\n\n/** All values range from -100 to 100, 0 meaning unchanged */\nexport interface Adjustments {\n\tbrightness: number\n\tcontrast: number\n\tsaturation: number\n}\n\nexport type FilterPreset\n\t= | 'none'\n\t\t| 'grayscale'\n\t\t| 'noir'\n\t\t| 'luna'\n\t\t| 'sepia'\n\t\t| 'fade'\n\t\t| 'warm'\n\t\t| 'cool'\n\t\t| 'golden'\n\t\t| 'coast'\n\t\t| 'mist'\n\t\t| 'berry'\n\t\t| 'cinema'\n\t\t| 'invert'\n\t\t| 'solarize'\n\t\t| 'posterize'\n\t\t| 'pop'\n\nexport interface DrawAnnotation {\n\tid: string\n\ttype: 'draw'\n\t/** Flat [x1, y1, x2, y2, …] polyline in oriented image coordinates */\n\tpoints: number[]\n\tcolor: string\n\tstrokeWidth: number\n}\n\nexport interface ArrowAnnotation {\n\tid: string\n\ttype: 'arrow'\n\t/** [fromX, fromY, toX, toY] in oriented image coordinates */\n\tpoints: [number, number, number, number]\n\tcolor: string\n\tstrokeWidth: number\n}\n\nexport interface BoxAnnotation {\n\tid: string\n\ttype: 'rectangle' | 'ellipse'\n\t/** The shape's local frame: rotation pivots on the rect's top-left */\n\trect: Rect\n\t/** Clockwise degrees around the rect's top-left corner */\n\trotation: number\n\tcolor: string\n\tstrokeWidth: number\n}\n\nexport interface TextAnnotation {\n\tid: string\n\ttype: 'text' | 'sticker'\n\tx: number\n\ty: number\n\t/** Text content, or the emoji character for stickers */\n\ttext: string\n\tcolor: string\n\tfontSize: number\n\t/** Clockwise degrees around the anchor */\n\trotation: number\n}\n\nexport interface RedactAnnotation {\n\tid: string\n\ttype: 'redact'\n\t/** Region to obfuscate, in oriented image coordinates */\n\trect: Rect\n\t/** How the region is destroyed */\n\tstyle: 'pixelate' | 'blur'\n}\n\nexport type Annotation = DrawAnnotation | ArrowAnnotation | BoxAnnotation | TextAnnotation | RedactAnnotation\n\nexport interface EditorState {\n\trotation: Rotation\n\t/** Additional free rotation in degrees, -45 to 45 */\n\tfineRotation: number\n\t/** Center zoom factor, 1 or greater */\n\tzoom: number\n\tflipX: boolean\n\tflipY: boolean\n\t/** Crop rectangle in oriented image coordinates, null meaning uncropped */\n\tcrop: Rect | null\n\tadjustments: Adjustments\n\tpreset: FilterPreset\n\tannotations: Annotation[]\n}\n\n/**\n * A pristine edit state: nothing rotated, cropped, adjusted or annotated.\n */\nexport function createInitialState(): EditorState {\n\treturn {\n\t\trotation: 0,\n\t\tfineRotation: 0,\n\t\tzoom: 1,\n\t\tflipX: false,\n\t\tflipY: false,\n\t\tcrop: null,\n\t\tadjustments: { brightness: 0, contrast: 0, saturation: 0 },\n\t\tpreset: 'none',\n\t\tannotations: [],\n\t}\n}\n\n/**\n * Whether a state carries no edit at all, matching a fresh one from\n * createInitialState. Consumers can use it for a dirty check, and the\n * editor uses it to hand an untouched image back as it came in.\n *\n * @param state the state to inspect\n */\nexport function isPristine(state: EditorState): boolean {\n\tconst { adjustments } = state\n\treturn state.rotation === 0\n\t\t&& state.fineRotation === 0\n\t\t&& state.zoom === 1\n\t\t&& !state.flipX\n\t\t&& !state.flipY\n\t\t&& state.crop === null\n\t\t&& adjustments.brightness === 0\n\t\t&& adjustments.contrast === 0\n\t\t&& adjustments.saturation === 0\n\t\t&& state.preset === 'none'\n\t\t&& state.annotations.length === 0\n}\n\n/**\n * Size of the image after applying the state rotation.\n *\n * @param natural the natural image size\n * @param rotation the applied rotation\n */\nexport function orientedSize(natural: Size, rotation: Rotation): Size {\n\treturn rotation % 180 === 0\n\t\t? { width: natural.width, height: natural.height }\n\t\t: { width: natural.height, height: natural.width }\n}\n\n/**\n * Clamp a rectangle into the given bounds, keeping at least 1px of area.\n *\n * @param rect the rectangle to clamp\n * @param bounds the containing size\n */\nexport function clampRect(rect: Rect, bounds: Size): Rect {\n\tconst x = Math.min(Math.max(rect.x, 0), bounds.width - 1)\n\tconst y = Math.min(Math.max(rect.y, 0), bounds.height - 1)\n\treturn {\n\t\tx,\n\t\ty,\n\t\twidth: Math.max(1, Math.min(rect.width, bounds.width - x)),\n\t\theight: Math.max(1, Math.min(rect.height, bounds.height - y)),\n\t}\n}\n\n/**\n * Rotate a flat point list 90° clockwise: (x, y) becomes (height - y, x).\n *\n * @param points flat [x1, y1, …] list\n * @param height oriented image height before the rotation\n */\nfunction mapPointsCW(points: number[], height: number): number[] {\n\tconst mapped: number[] = []\n\tfor (let i = 0; i < points.length; i += 2) {\n\t\tmapped.push(height - (points[i + 1] ?? 0), points[i] ?? 0)\n\t}\n\treturn mapped\n}\n\n/**\n * Rotate a rectangle 90° clockwise, swapping its dimensions.\n *\n * @param rect the rectangle to rotate\n * @param height oriented image height before the rotation\n */\nfunction mapRectCW(rect: Rect, height: number): Rect {\n\treturn {\n\t\tx: height - rect.y - rect.height,\n\t\ty: rect.x,\n\t\twidth: rect.height,\n\t\theight: rect.width,\n\t}\n}\n\n/**\n * Rotate one annotation 90° clockwise.\n *\n * @param annotation the annotation to rotate\n * @param height oriented image height before the rotation\n */\nfunction mapAnnotationCW(annotation: Annotation, height: number): Annotation {\n\tswitch (annotation.type) {\n\t\tcase 'draw':\n\t\t\treturn { ...annotation, points: mapPointsCW(annotation.points, height) }\n\t\tcase 'arrow':\n\t\t\treturn { ...annotation, points: mapPointsCW(annotation.points, height) as ArrowAnnotation['points'] }\n\t\tcase 'rectangle':\n\t\tcase 'ellipse':\n\t\t\t// The anchor maps like a point and the rotation field absorbs\n\t\t\t// the quarter turn; the local frame (width/height) is untouched\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: { ...annotation.rect, x: height - annotation.rect.y, y: annotation.rect.x },\n\t\t\t\trotation: (annotation.rotation + 90) % 360,\n\t\t\t}\n\t\tcase 'redact':\n\t\t\treturn { ...annotation, rect: mapRectCW(annotation.rect, height) }\n\t\tcase 'text':\n\t\tcase 'sticker':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\tx: height - annotation.y,\n\t\t\t\ty: annotation.x,\n\t\t\t\trotation: (annotation.rotation + 90) % 360,\n\t\t\t}\n\t}\n}\n\n/**\n * Rotate the whole edit state 90° clockwise: crop and annotation\n * coordinates are remapped into the new oriented space.\n *\n * @param state the current state\n * @param oriented the oriented image size before this rotation\n */\nexport function rotateCW(state: EditorState, oriented: Size): EditorState {\n\treturn {\n\t\t...state,\n\t\trotation: (state.rotation + 90) % 360 as Rotation,\n\t\tcrop: state.crop && mapRectCW(state.crop, oriented.height),\n\t\tannotations: state.annotations.map((annotation) => mapAnnotationCW(annotation, oriented.height)),\n\t}\n}\n\n/**\n * Mirror one annotation horizontally.\n *\n * @param annotation the annotation to mirror\n * @param width current oriented image width\n */\nfunction mapAnnotationFlipX(annotation: Annotation, width: number): Annotation {\n\tswitch (annotation.type) {\n\t\tcase 'draw':\n\t\tcase 'arrow': {\n\t\t\tconst points = annotation.points.map((value, i) => (i % 2 === 0 ? width - value : value))\n\t\t\treturn { ...annotation, points } as Annotation\n\t\t}\n\t\tcase 'rectangle':\n\t\tcase 'ellipse': {\n\t\t\t// Exact mirror: the new anchor is the mirrored image of the\n\t\t\t// rotated top-right corner, with the rotation direction negated\n\t\t\tconst radians = (annotation.rotation * Math.PI) / 180\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: {\n\t\t\t\t\t...annotation.rect,\n\t\t\t\t\tx: width - annotation.rect.x - annotation.rect.width * Math.cos(radians),\n\t\t\t\t\ty: annotation.rect.y + annotation.rect.width * Math.sin(radians),\n\t\t\t\t},\n\t\t\t\trotation: (360 - annotation.rotation) % 360,\n\t\t\t}\n\t\t}\n\t\tcase 'redact':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: { ...annotation.rect, x: width - annotation.rect.x - annotation.rect.width },\n\t\t\t}\n\t\tcase 'text':\n\t\tcase 'sticker':\n\t\t\t// The anchor is mirrored but glyphs stay readable, so the\n\t\t\t// rotation direction inverts to keep the visual placement\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\tx: width - annotation.x,\n\t\t\t\trotation: (360 - annotation.rotation) % 360,\n\t\t\t}\n\t}\n}\n\n/**\n * Mirror the whole edit state horizontally in oriented space.\n *\n * @param state the current state\n * @param oriented the current oriented image size\n */\nexport function flipHorizontal(state: EditorState, oriented: Size): EditorState {\n\t// Rendering bakes the mirror in source space before rotating, so a\n\t// visually horizontal flip toggles the source vertical axis when the\n\t// image lies on its side\n\tconst sideways = state.rotation % 180 !== 0\n\treturn {\n\t\t...state,\n\t\tflipX: sideways ? state.flipX : !state.flipX,\n\t\tflipY: sideways ? !state.flipY : state.flipY,\n\t\tfineRotation: -state.fineRotation,\n\t\tcrop: state.crop && { ...state.crop, x: oriented.width - state.crop.x - state.crop.width },\n\t\tannotations: state.annotations.map((annotation) => mapAnnotationFlipX(annotation, oriented.width)),\n\t}\n}\n\n/**\n * Mirror one annotation vertically.\n *\n * @param annotation the annotation to mirror\n * @param height current oriented image height\n */\nfunction mapAnnotationFlipY(annotation: Annotation, height: number): Annotation {\n\tswitch (annotation.type) {\n\t\tcase 'draw':\n\t\tcase 'arrow': {\n\t\t\tconst points = annotation.points.map((value, i) => (i % 2 === 1 ? height - value : value))\n\t\t\treturn { ...annotation, points } as Annotation\n\t\t}\n\t\tcase 'rectangle':\n\t\tcase 'ellipse': {\n\t\t\tconst radians = (annotation.rotation * Math.PI) / 180\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: {\n\t\t\t\t\t...annotation.rect,\n\t\t\t\t\tx: annotation.rect.x - annotation.rect.height * Math.sin(radians),\n\t\t\t\t\ty: height - annotation.rect.y - annotation.rect.height * Math.cos(radians),\n\t\t\t\t},\n\t\t\t\trotation: (360 - annotation.rotation) % 360,\n\t\t\t}\n\t\t}\n\t\tcase 'redact':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: { ...annotation.rect, y: height - annotation.rect.y - annotation.rect.height },\n\t\t\t}\n\t\tcase 'text':\n\t\tcase 'sticker':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\ty: height - annotation.y,\n\t\t\t\trotation: (360 - annotation.rotation) % 360,\n\t\t\t}\n\t}\n}\n\n/**\n * Mirror the whole edit state vertically in oriented space.\n *\n * @param state the current state\n * @param oriented the current oriented image size\n */\nexport function flipVertical(state: EditorState, oriented: Size): EditorState {\n\tconst sideways = state.rotation % 180 !== 0\n\treturn {\n\t\t...state,\n\t\tflipX: sideways ? !state.flipX : state.flipX,\n\t\tflipY: sideways ? state.flipY : !state.flipY,\n\t\tfineRotation: -state.fineRotation,\n\t\tcrop: state.crop && { ...state.crop, y: oriented.height - state.crop.y - state.crop.height },\n\t\tannotations: state.annotations.map((annotation) => mapAnnotationFlipY(annotation, oriented.height)),\n\t}\n}\n\n/**\n * Move an annotation by the given delta.\n *\n * @param annotation the annotation to move\n * @param dx horizontal shift in oriented image pixels\n * @param dy vertical shift in oriented image pixels\n */\nexport function translateAnnotation(annotation: Annotation, dx: number, dy: number): Annotation {\n\tswitch (annotation.type) {\n\t\tcase 'draw':\n\t\tcase 'arrow': {\n\t\t\tconst points = annotation.points.map((value, i) => value + (i % 2 === 0 ? dx : dy))\n\t\t\treturn { ...annotation, points } as Annotation\n\t\t}\n\t\tcase 'rectangle':\n\t\tcase 'ellipse':\n\t\tcase 'redact':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: { ...annotation.rect, x: annotation.rect.x + dx, y: annotation.rect.y + dy },\n\t\t\t}\n\t\tcase 'text':\n\t\tcase 'sticker':\n\t\t\treturn { ...annotation, x: annotation.x + dx, y: annotation.y + dy }\n\t}\n}\n\n/**\n * Clone an annotation under a new id, shifted so the copy is visible\n * next to the original.\n *\n * @param annotation the annotation to duplicate\n * @param offset shift applied to the copy, in oriented image pixels\n */\nexport function duplicateAnnotation(annotation: Annotation, offset = 16): Annotation {\n\treturn { ...translateAnnotation(annotation, offset, offset), id: newId() }\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\ndefineProps<{\n\t/** Surface shape: rounded card, capsule pill or compact strip */\n\tvariant?: 'card' | 'pill' | 'strip'\n}>()\n</script>\n\n<template>\n\t<div class=\"glass-surface\" :class=\"`glass-surface--${variant ?? 'card'}`\">\n\t\t<slot />\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.glass-surface {\n\tbackground: var(--editor-glass, rgba(20, 20, 26, 0.6));\n\tbackdrop-filter: blur(24px) saturate(1.4);\n\tborder: 1px solid rgba(255, 255, 255, 0.09);\n\tbox-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);\n\n\t&--card {\n\t\tborder-radius: 20px;\n\t}\n\n\t&--strip {\n\t\tborder-radius: 16px;\n\t}\n\n\t&--pill {\n\t\tborder-radius: var(--border-radius-pill, 100px);\n\t}\n}\n</style>\n","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon contrast-circle-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,20C9.79,20 7.79,19.1 6.34,17.66L17.66,6.34C19.1,7.79 20,9.79 20,12A8,8 0 0,1 12,20M6,8H8V6H9.5V8H11.5V9.5H9.5V11.5H8V9.5H6M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,16H17V14.5H12V16Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"ContrastCircleIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon invert-colors-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,19.58V19.58C10.4,19.58 8.89,18.96 7.76,17.83C6.62,16.69 6,15.19 6,13.58C6,12 6.62,10.47 7.76,9.34L12,5.1M17.66,7.93L12,2.27V2.27L6.34,7.93C3.22,11.05 3.22,16.12 6.34,19.24C7.9,20.8 9.95,21.58 12,21.58C14.05,21.58 16.1,20.8 17.66,19.24C20.78,16.12 20.78,11.05 17.66,7.93Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"InvertColorsIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon white-balance-sunny-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M3.55 19.09L4.96 20.5L6.76 18.71L5.34 17.29M12 6C8.69 6 6 8.69 6 12S8.69 18 12 18 18 15.31 18 12C18 8.68 15.31 6 12 6M20 13H23V11H20M17.24 18.71L19.04 20.5L20.45 19.09L18.66 17.29M20.45 5L19.04 3.6L17.24 5.39L18.66 6.81M13 1H11V4H13M6.76 5.39L4.96 3.6L3.55 5L5.34 6.81L6.76 5.39M1 13H4V11H1M13 20H11V23H13\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"WhiteBalanceSunnyIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nconst props = defineProps<{\n\t/** Current value */\n\tvalue: number\n\t/** Lower bound */\n\tmin: number\n\t/** Upper bound */\n\tmax: number\n\t/** Slider step */\n\tstep: number\n\t/** Accessible name of the slider */\n\tlabel: string\n\t/** Text shown next to the slider, defaults to the raw value */\n\tdisplay?: string\n\t/** Hook for the browser test suite */\n\tdataTest?: string\n\t/** Whether the slider is disabled */\n\tdisabled?: boolean\n}>()\n\nconst emit = defineEmits<{\n\t/** Continuous value updates while dragging */\n\tinput: [value: number]\n\t/** The drag ended, record the result */\n\tcommit: []\n}>()\n\n/**\n * Forward the native input event as a numeric update.\n *\n * @param event the range input event\n */\nfunction onInput(event: Event) {\n\temit('input', Number((event.target as HTMLInputElement).value))\n}\n</script>\n\n<template>\n\t<div class=\"editor-slider\">\n\t\t<input\n\t\t\t:value=\"props.value\"\n\t\t\t:data-test=\"dataTest\"\n\t\t\t:disabled=\"disabled\"\n\t\t\t:aria-label=\"label\"\n\t\t\ttype=\"range\"\n\t\t\t:min=\"min\"\n\t\t\t:max=\"max\"\n\t\t\t:step=\"step\"\n\t\t\t@input=\"onInput\"\n\t\t\t@change=\"emit('commit')\">\n\t\t<output>\n\t\t\t<!-- Defaults to the raw value; size controls show what the\n\t\t\t\tvalue looks like on the canvas instead -->\n\t\t\t<slot name=\"preview\">{{ display ?? props.value }}</slot>\n\t\t</output>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n// Thin line slider with a round thumb and the value to its right\n.editor-slider {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline) * 3);\n\twidth: 100%;\n\n\tinput[type='range'] {\n\t\tappearance: none;\n\t\tflex: 1;\n\t\theight: 20px;\n\t\tmargin: 0;\n\t\tbackground: linear-gradient(rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.25)) center / 100% 2px no-repeat;\n\t\tcursor: ew-resize;\n\n\t\t&::-webkit-slider-thumb {\n\t\t\tappearance: none;\n\t\t\twidth: 14px;\n\t\t\theight: 14px;\n\t\t\tborder-radius: 50%;\n\t\t\tbackground: #fff;\n\t\t\tbox-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);\n\t\t}\n\n\t\t&::-moz-range-thumb {\n\t\t\twidth: 14px;\n\t\t\theight: 14px;\n\t\t\tborder: none;\n\t\t\tborder-radius: 50%;\n\t\t\tbackground: #fff;\n\t\t\tbox-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);\n\t\t}\n\n\t\t&:focus-visible {\n\t\t\toutline: 2px solid var(--color-primary-element);\n\t\t\toutline-offset: 2px;\n\t\t}\n\t}\n\n\toutput {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: flex-end;\n\t\tmin-width: 44px;\n\t\tmin-height: 44px;\n\t\ttext-align: end;\n\t\tfont-size: 13px;\n\t\tfont-variant-numeric: tabular-nums;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\ndefineProps<{\n\t/** Visible label under the icon */\n\tlabel: string\n\t/** Whether this tab is the active one */\n\tactive?: boolean\n\t/** Whether the tab is disabled */\n\tdisabled?: boolean\n\t/** Hook for the browser test suite */\n\tdataTest?: string\n}>()\n\nconst emit = defineEmits<{\n\tclick: []\n}>()\n</script>\n\n<template>\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"icon-tab\"\n\t\t:class=\"{ 'icon-tab--active': active }\"\n\t\t:disabled=\"disabled\"\n\t\t:data-test=\"dataTest\"\n\t\t:aria-pressed=\"active\"\n\t\t@click=\"emit('click')\">\n\t\t<slot />\n\t\t<span>{{ label }}</span>\n\t</button>\n</template>\n\n<style scoped lang=\"scss\">\n// Icon-above-label tab, softly tinted by the image's ambient color\n// while active\n.icon-tab {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 4px;\n\tmin-width: max(64px, var(--default-clickable-area, 44px));\n\tmin-height: var(--default-clickable-area, 44px);\n\tpadding: calc(var(--default-grid-baseline) * 2) var(--default-grid-baseline);\n\tborder: none;\n\tborder-radius: var(--border-radius-large, 12px);\n\tbackground: transparent;\n\tcolor: rgba(242, 242, 247, 0.75);\n\tfont-size: 11px;\n\tletter-spacing: 0.01em;\n\tcursor: pointer;\n\ttransition: background-color 0.12s ease, color 0.12s ease, transform 0.12s ease;\n\n\t&:active:not(:disabled) {\n\t\ttransform: scale(0.96);\n\t}\n\n\t&:hover:not(:disabled) {\n\t\tbackground-color: rgba(255, 255, 255, 0.07);\n\t\tcolor: var(--color-main-text);\n\t}\n\n\t&:focus-visible {\n\t\toutline: 2px solid var(--color-primary-element);\n\t\toutline-offset: 2px;\n\t}\n\n\t&--active {\n\t\tbackground: rgba(var(--editor-ambient, 88, 86, 112), 0.3);\n\t\tcolor: var(--color-main-text);\n\t\tbox-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 4px 16px rgba(0, 0, 0, 0.3);\n\t\tbackdrop-filter: blur(12px);\n\t}\n\n\t&:disabled {\n\t\topacity: 0.5;\n\t\tcursor: default;\n\t}\n\n\t@container editor (max-width: 600px) {\n\t\t// Narrower, but never under the pointer target\n\t\tmin-width: var(--default-clickable-area, 44px);\n\t\tpadding: var(--default-grid-baseline) 2px;\n\t\tfont-size: 10px;\n\t}\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport { getGettextBuilder } from '@nextcloud/l10n/gettext'\n\nconst gtBuilder = getGettextBuilder()\n\t.detectLocale()\n\n// @ts-expect-error __TRANSLATIONS__ is replaced by vite\n__TRANSLATIONS__.map((data) => gtBuilder.addTranslation(data.locale, data.json))\n\ninterface Gettext {\n\t/**\n\t * Get translated string (singular form), optionally with placeholders\n\t *\n\t * @param original original string to translate\n\t * @param placeholders map of placeholder key to value\n\t */\n\tgettext(original: string, placeholders?: Record<string, string | number>): string\n\n\t/**\n\t * Get translated string with plural forms\n\t *\n\t * @param singular Singular text form\n\t * @param plural Plural text form to be used if `count` requires it\n\t * @param count The number to insert into the text\n\t * @param placeholders optional map of placeholder key to value\n\t */\n\tngettext(singular: string, plural: string, count: number, placeholders?: Record<string, string | number>): string\n}\n\nconst gt = gtBuilder.build() as Gettext\n\nexport const n = gt.ngettext.bind(gt) as typeof gt.ngettext\nexport const t = gt.gettext.bind(gt) as typeof gt.gettext\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Rect, Size } from './state.ts'\n\n/** Stage margin kept free so handles at the image edge stay grabbable */\nexport const VIEW_MARGIN = 16\n\n/** The fitted view: the image is never displayed smaller than that */\nexport const MIN_ZOOM = 1\n\n/** Past this the view shows mostly interpolation */\nexport const MAX_ZOOM = 4\n\n/** Requested zooms below this snap back to the fitted view */\nexport const ZOOM_SNAP = 1.05\n\n/** Relative pinch change treated as a zoom rather than a two-finger pan */\nexport const PINCH_TOLERANCE = 0.01\n\n/** Pixels one wheel line stands for, for the engines reporting lines */\nconst WHEEL_LINE = 16\n\n/** Largest single-event travel honored, so one flick cannot jump the range */\nconst WHEEL_CLAMP = 300\n\n/** Zoom change per pixel of wheel travel */\nconst WHEEL_SENSITIVITY = 0.0015\n\nexport interface Point {\n\tx: number\n\ty: number\n}\n\n/**\n * The fitted view of the visible image area, published by the editor\n * component so the view setters can clamp against the same metrics the\n * renderer uses.\n */\nexport interface ViewFit {\n\t/** Scale fitting the visible area into the container, at zoom 1 */\n\tscale: number\n\t/** Scene-space area on display: the crop, or the whole image */\n\tvisible: Rect\n\t/** Container size in stage pixels */\n\tcontainer: Size\n\t/** Whether the view is clipped to the crop */\n\tshowCropped: boolean\n}\n\n/**\n * How far the view may be panned away from center before the content\n * edge would leave the container. Zero while the content fits, which\n * pins the fitted view in place.\n *\n * @param visible the scene-space area on display\n * @param scale the applied view scale, zoom included\n * @param container the container size in stage pixels\n */\nexport function panBounds(visible: Size, scale: number, container: Size): Point {\n\treturn {\n\t\tx: Math.max(0, (visible.width * scale - container.width) / 2 + VIEW_MARGIN),\n\t\ty: Math.max(0, (visible.height * scale - container.height) / 2 + VIEW_MARGIN),\n\t}\n}\n\n/**\n * Hold a pan offset inside the given bounds.\n *\n * @param pan the requested offset\n * @param bounds the maximum offset per axis\n */\nexport function clampPan(pan: Point, bounds: Point): Point {\n\treturn {\n\t\tx: Math.min(bounds.x, Math.max(-bounds.x, pan.x)),\n\t\ty: Math.min(bounds.y, Math.max(-bounds.y, pan.y)),\n\t}\n}\n\n/**\n * Hold a zoom factor between the fitted view and the maximum, snapping\n * near-fitted values back to exactly fitted.\n *\n * @param zoom the requested factor\n */\nexport function clampZoom(zoom: number): number {\n\treturn zoom < ZOOM_SNAP ? MIN_ZOOM : Math.min(MAX_ZOOM, zoom)\n}\n\n/**\n * The pan offset that keeps the point under the cursor fixed while the\n * zoom changes by the given factor.\n *\n * @param pan the current offset\n * @param cursor the cursor position relative to the container center\n * @param factor the new zoom divided by the previous one\n */\nexport function anchoredPan(pan: Point, cursor: Point, factor: number): Point {\n\treturn {\n\t\tx: cursor.x - factor * (cursor.x - pan.x),\n\t\ty: cursor.y - factor * (cursor.y - pan.y),\n\t}\n}\n\n/**\n * Zoom factor for one wheel event.\n *\n * The delta is normalized first: engines report pixels, lines or pages,\n * and a mouse notch carries a far larger delta than a trackpad step. A\n * fixed factor per event would make a mouse wheel crawl, so the travel\n * drives the factor, bounded so a single flick cannot cross the whole\n * zoom range.\n *\n * @param deltaY the event's vertical delta\n * @param deltaMode the event's delta unit: 0 pixels, 1 lines, 2 pages\n * @param pageHeight viewport height, only used for page deltas\n */\nexport function wheelZoomFactor(deltaY: number, deltaMode: number, pageHeight: number): number {\n\tconst scaled = deltaMode === 1\n\t\t? deltaY * WHEEL_LINE\n\t\t: deltaMode === 2\n\t\t\t? deltaY * pageHeight\n\t\t\t: deltaY\n\tconst bounded = Math.min(WHEEL_CLAMP, Math.max(-WHEEL_CLAMP, scaled))\n\t// Exponential so zooming in and out by the same travel cancels out\n\treturn Math.exp(-bounded * WHEEL_SENSITIVITY)\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { ComputedRef, InjectionKey, ShallowRef } from 'vue'\nimport type { HistoryEntry } from '../composables/useHistory.ts'\nimport type { EditorState } from './state.ts'\nimport type { Point, ViewFit } from './view.ts'\n\nimport { inject, provide, shallowRef, watch } from 'vue'\nimport { useHistory } from '../composables/useHistory.ts'\nimport { t } from '../utils/l10n.ts'\nimport { createInitialState } from './state.ts'\nimport { anchoredPan, clampPan, clampZoom, MIN_ZOOM, panBounds } from './view.ts'\n\nexport type Tool\n\t= | 'select'\n\t\t| 'crop'\n\t\t| 'adjust'\n\t\t| 'draw'\n\t\t| 'rectangle'\n\t\t| 'ellipse'\n\t\t| 'arrow'\n\t\t| 'text'\n\t\t| 'sticker'\n\t\t| 'redact'\n\n/** Top-level editor sections, presented as sidebar tabs */\nexport type EditorMode = 'select' | 'crop' | 'finetune' | 'filter' | 'annotate' | 'sticker' | 'redact'\n\n/** The canvas tool each mode starts with */\nexport const MODE_DEFAULT_TOOL: Record<EditorMode, Tool> = {\n\tselect: 'select',\n\tcrop: 'crop',\n\tfinetune: 'adjust',\n\tfilter: 'adjust',\n\tannotate: 'draw',\n\tsticker: 'sticker',\n\tredact: 'redact',\n}\n\nexport interface EditorContext {\n\tstate: Readonly<ShallowRef<EditorState>>\n\t/** Active sidebar section */\n\tactiveMode: ShallowRef<EditorMode>\n\tactiveTool: ShallowRef<Tool>\n\t/** Switch section and select its default canvas tool */\n\tsetMode(mode: EditorMode): void\n\t/** Stroke and text color for new annotations */\n\tdrawColor: ShallowRef<string>\n\t/** Stroke width for new annotations */\n\tstrokeWidth: ShallowRef<number>\n\t/** Font size for new text annotations */\n\tfontSize: ShallowRef<number>\n\t/** Emoji placed by the sticker tool */\n\tsticker: ShallowRef<string>\n\t/** Obfuscation style used by new redactions */\n\tredactStyle: ShallowRef<'pixelate' | 'blur'>\n\t/** Crop aspect lock: width/height ratio, 'original', or null = free */\n\tcropAspect: ShallowRef<number | 'original' | null>\n\t/** View-only magnification of the canvas, 1 = fit */\n\tviewZoom: ShallowRef<number>\n\t/** View-only pan offset in stage pixels, only meaningful when zoomed */\n\tviewPan: ShallowRef<Point>\n\t/**\n\t * Fit metrics of the rendered view, published by the editor\n\t * component. The view setters clamp against these, so panning stops\n\t * exactly where the renderer stops following it.\n\t */\n\tviewFit: ShallowRef<ViewFit | null>\n\t/**\n\t * True while a pan gesture owns the pointer, so canvas tools stay\n\t * out of the way\n\t */\n\tpanning: ShallowRef<boolean>\n\t/**\n\t * Magnify the view, optionally keeping a point fixed.\n\t *\n\t * @param zoom the requested factor, clamped to the allowed range\n\t * @param anchor point to keep fixed, relative to the view center\n\t */\n\tsetViewZoom(zoom: number, anchor?: Point): void\n\t/**\n\t * Pan the view, clamped so the content cannot leave the container.\n\t *\n\t * @param pan the requested offset in stage pixels\n\t */\n\tsetViewPan(pan: Point): void\n\t/** True between preview() and the next commit: a slider is scrubbing */\n\tinteracting: ShallowRef<boolean>\n\t/** Id of the annotation selected in select mode */\n\tselectedId: ShallowRef<string | null>\n\tcanUndo: ComputedRef<boolean>\n\tcanRedo: ComputedRef<boolean>\n\t/** Every recorded step, oldest first, for a history list */\n\thistoryEntries: ComputedRef<readonly HistoryEntry<EditorState>[]>\n\t/** Position of the state on screen within historyEntries */\n\thistoryIndex: ComputedRef<number>\n\t/**\n\t * Apply a new state and record it as an undoable step.\n\t *\n\t * @param next the state to apply\n\t * @param label what the user did, translated, for the history list\n\t */\n\tcommit(next: EditorState, label?: string): void\n\t/** Apply a new state without recording it (live slider previews) */\n\tpreview(next: EditorState): void\n\tundo(): void\n\tredo(): void\n\t/**\n\t * Go to an arbitrary recorded step.\n\t *\n\t * @param index position in historyEntries\n\t */\n\tjumpTo(index: number): void\n\t/**\n\t * Reset to an empty history, e.g. when the source changes.\n\t *\n\t * @param next state to start from, defaulting to a pristine one\n\t */\n\treset(next?: EditorState): void\n}\n\nconst EDITOR_CONTEXT: InjectionKey<EditorContext> = Symbol('nextcloud:image-editor')\n\n/**\n * Create the shared editor context and provide it to descendants.\n */\nexport function createEditorContext(): EditorContext {\n\tconst history = useHistory<EditorState>()\n\tconst state = shallowRef(createInitialState())\n\tconst viewZoom = shallowRef(MIN_ZOOM)\n\tconst viewPan = shallowRef<Point>({ x: 0, y: 0 })\n\tconst viewFit = shallowRef<ViewFit | null>(null)\n\t/**\n\t * How far the view may be panned at the given zoom. Clamping on\n\t * write is what keeps a pan gesture from accumulating an offset the\n\t * renderer will not follow, which used to leave the view stuck\n\t * until the overshoot was scrubbed back.\n\t *\n\t * @param zoom the zoom the pan applies to\n\t */\n\tconst boundsAt = (zoom: number): Point => {\n\t\tconst fit = viewFit.value\n\t\treturn fit === null\n\t\t\t? { x: 0, y: 0 }\n\t\t\t: panBounds(fit.visible, fit.scale * zoom, fit.container)\n\t}\n\tconst activeMode = shallowRef<EditorMode>('crop')\n\tconst activeTool = shallowRef<Tool>(MODE_DEFAULT_TOOL.crop)\n\t// Pushed by reference: every edit path builds new objects rather\n\t// than mutating, so a snapshot is already frozen in practice, and\n\t// keeping the identities lets the renderer skip the annotations an\n\t// undo did not touch\n\thistory.push(state.value, t('Original'))\n\n\tconst context: EditorContext = {\n\t\tstate,\n\t\tactiveMode,\n\t\tactiveTool,\n\t\tsetMode(mode) {\n\t\t\tactiveMode.value = mode\n\t\t\tactiveTool.value = MODE_DEFAULT_TOOL[mode]\n\t\t\tcontext.selectedId.value = null\n\t\t},\n\t\tdrawColor: shallowRef('#ff0000'),\n\t\tstrokeWidth: shallowRef(6),\n\t\tfontSize: shallowRef(24),\n\t\tsticker: shallowRef('😀'),\n\t\tredactStyle: shallowRef<'pixelate' | 'blur'>('pixelate'),\n\t\tcropAspect: shallowRef<number | 'original' | null>(null),\n\t\tviewZoom,\n\t\tviewPan,\n\t\tviewFit,\n\t\tpanning: shallowRef(false),\n\t\tsetViewZoom(zoom, anchor) {\n\t\t\tconst previous = viewZoom.value\n\t\t\tconst next = clampZoom(zoom)\n\t\t\tviewZoom.value = next\n\t\t\tif (next === MIN_ZOOM) {\n\t\t\t\t// The fitted view is centered by definition\n\t\t\t\tviewPan.value = { x: 0, y: 0 }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst panned = anchor === undefined\n\t\t\t\t? viewPan.value\n\t\t\t\t: anchoredPan(viewPan.value, anchor, next / previous)\n\t\t\tviewPan.value = clampPan(panned, boundsAt(next))\n\t\t},\n\t\tsetViewPan(pan) {\n\t\t\tviewPan.value = clampPan(pan, boundsAt(viewZoom.value))\n\t\t},\n\t\tinteracting: shallowRef(false),\n\t\tselectedId: shallowRef<string | null>(null),\n\t\tcanUndo: history.canUndo,\n\t\tcanRedo: history.canRedo,\n\t\thistoryEntries: history.entries,\n\t\thistoryIndex: history.index,\n\t\tcommit(next, label) {\n\t\t\tcontext.interacting.value = false\n\t\t\tstate.value = next\n\t\t\thistory.push(next, label)\n\t\t},\n\t\tpreview(next) {\n\t\t\tcontext.interacting.value = true\n\t\t\tstate.value = next\n\t\t},\n\t\tundo() {\n\t\t\tconst snapshot = history.undo()\n\t\t\tif (snapshot !== undefined) {\n\t\t\t\tstate.value = snapshot\n\t\t\t}\n\t\t},\n\t\tredo() {\n\t\t\tconst snapshot = history.redo()\n\t\t\tif (snapshot !== undefined) {\n\t\t\t\tstate.value = snapshot\n\t\t\t}\n\t\t},\n\t\tjumpTo(index) {\n\t\t\tconst snapshot = history.jumpTo(index)\n\t\t\tif (snapshot !== undefined) {\n\t\t\t\tstate.value = snapshot\n\t\t\t}\n\t\t},\n\t\treset(next) {\n\t\t\thistory.clear()\n\t\t\tstate.value = next ?? createInitialState()\n\t\t\tactiveMode.value = 'crop'\n\t\t\tactiveTool.value = MODE_DEFAULT_TOOL.crop\n\t\t\tcontext.selectedId.value = null\n\t\t\tviewZoom.value = MIN_ZOOM\n\t\t\tviewPan.value = { x: 0, y: 0 }\n\t\t\tcontext.panning.value = false\n\t\t\t// A seeded state is where this session starts, but it is not\n\t\t\t// the untouched image, so it is not called that\n\t\t\thistory.push(state.value, next === undefined ? t('Original') : t('Restored'))\n\t\t},\n\t}\n\n\t// A selection is only visible and editable in the select tool;\n\t// keeping it across tool switches invites invisible deletions\n\twatch(activeTool, (tool) => {\n\t\tif (tool !== 'select') {\n\t\t\tcontext.selectedId.value = null\n\t\t}\n\t})\n\n\tprovide(EDITOR_CONTEXT, context)\n\treturn context\n}\n\n/**\n * Access the editor context provided by the ImageEditor root.\n */\nexport function useEditorContext(): EditorContext {\n\tconst context = inject(EDITOR_CONTEXT, null)\n\tif (context === null) {\n\t\tthrow new Error('useEditorContext() called outside of an ImageEditor tree')\n\t}\n\treturn context\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport { computed, shallowRef } from 'vue'\nimport ContrastCircle from 'vue-material-design-icons/ContrastCircle.vue'\nimport InvertColors from 'vue-material-design-icons/InvertColors.vue'\nimport WhiteBalanceSunny from 'vue-material-design-icons/WhiteBalanceSunny.vue'\nimport EditorSlider from '../base/EditorSlider.vue'\nimport IconTab from '../base/IconTab.vue'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { t } from '../../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\n\ntype AdjustmentKey = 'brightness' | 'contrast' | 'saturation'\nconst adjustments: { id: AdjustmentKey, label: string, icon: unknown }[] = [\n\t{ id: 'brightness', label: t('Brightness'), icon: WhiteBalanceSunny },\n\t{ id: 'contrast', label: t('Contrast'), icon: ContrastCircle },\n\t{ id: 'saturation', label: t('Saturation'), icon: InvertColors },\n]\nconst activeAdjustment = shallowRef<AdjustmentKey>('brightness')\n\nconst display = computed(() => {\n\tconst value = context.state.value.adjustments[activeAdjustment.value]\n\treturn value > 0 ? `+${value}` : `${value}`\n})\n\n/**\n * Live-preview the active adjustment while the slider is dragged.\n *\n * @param value the new adjustment value\n */\nfunction onAdjustInput(value: number) {\n\tconst state = context.state.value\n\tcontext.preview({\n\t\t...state,\n\t\tadjustments: { ...state.adjustments, [activeAdjustment.value]: value },\n\t})\n}\n\n/**\n * Record the current preview as one undo step on release.\n */\nfunction onSliderCommit() {\n\tcontext.commit(context.state.value, adjustments.find((entry) => entry.id === activeAdjustment.value)!.label)\n}\n</script>\n\n<template>\n\t<div class=\"adjust-panel\">\n\t\t<div class=\"adjust-panel__tabs\">\n\t\t\t<IconTab\n\t\t\t\tv-for=\"adjustment in adjustments\"\n\t\t\t\t:key=\"adjustment.id\"\n\t\t\t\t:label=\"adjustment.label\"\n\t\t\t\t:active=\"activeAdjustment === adjustment.id\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\t:data-test=\"`tab-${adjustment.id}`\"\n\t\t\t\t@click=\"activeAdjustment = adjustment.id\">\n\t\t\t\t<component :is=\"adjustment.icon\" :size=\"20\" />\n\t\t\t</IconTab>\n\t\t</div>\n\t\t<EditorSlider\n\t\t\t:value=\"context.state.value.adjustments[activeAdjustment]\"\n\t\t\t:min=\"-100\"\n\t\t\t:max=\"100\"\n\t\t\t:step=\"1\"\n\t\t\t:label=\"adjustments.find((entry) => entry.id === activeAdjustment)!.label\"\n\t\t\t:display=\"display\"\n\t\t\t:data-test=\"`adjust-${activeAdjustment}`\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\t@input=\"onAdjustInput\"\n\t\t\t@commit=\"onSliderCommit\" />\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.adjust-panel {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\twidth: 100%;\n\n\t&__tabs {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tgap: calc(var(--default-grid-baseline) * 2);\n\t}\n}\n</style>\n","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon arrow-top-right-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M5,17.59L15.59,7H9V5H19V15H17V8.41L6.41,19L5,17.59Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"ArrowTopRightIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon ellipse-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,6C16.41,6 20,8.69 20,12C20,15.31 16.41,18 12,18C7.59,18 4,15.31 4,12C4,8.69 7.59,6 12,6M12,4C6.5,4 2,7.58 2,12C2,16.42 6.5,20 12,20C17.5,20 22,16.42 22,12C22,7.58 17.5,4 12,4Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"EllipseOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon format-text-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M18.5,4L19.66,8.35L18.7,8.61C18.25,7.74 17.79,6.87 17.26,6.43C16.73,6 16.11,6 15.5,6H13V16.5C13,17 13,17.5 13.33,17.75C13.67,18 14.33,18 15,18V19H9V18C9.67,18 10.33,18 10.67,17.75C11,17.5 11,17 11,16.5V6H8.5C7.89,6 7.27,6 6.74,6.43C6.21,6.87 5.75,7.74 5.3,8.61L4.34,8.35L5.5,4H18.5Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"FormatTextIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon pencil-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"PencilIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon rectangle-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M4,6V19H20V6H4M18,17H6V8H18V17Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"RectangleOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { EditorContext } from '../editor/context.ts'\n\nimport { t } from '../utils/l10n.ts'\n\nexport interface AnnotationColor {\n\t/**\n\t * Follow the color control while it is being dragged: the selected\n\t * annotation changes color without recording a step.\n\t *\n\t * @param color the color under the pointer\n\t */\n\tpreview(color: string): void\n\t/**\n\t * Record the color the user settled on as one undoable step.\n\t *\n\t * @param color the chosen color\n\t */\n\tcommit(color: string): void\n}\n\n/**\n * The stroke and text color, and its effect on the current selection.\n *\n * A native color input reports every color the pointer passes over, so\n * committing each one buried the undo history under dozens of steps\n * for a single pick. The intermediate colors are previewed and only\n * the released one is recorded, which is how the sliders already\n * behave.\n *\n * @param context the editor context\n */\nexport function useAnnotationColor(context: EditorContext): AnnotationColor {\n\t/**\n\t * The selected annotation, if its color is the user's to change.\n\t * Stickers render an emoji glyph and redactions destroy pixels, so\n\t * neither has a color worth writing.\n\t */\n\tfunction recolorable() {\n\t\tconst annotation = context.state.value.annotations\n\t\t\t.find((entry) => entry.id === context.selectedId.value)\n\t\treturn annotation !== undefined\n\t\t\t&& 'color' in annotation\n\t\t\t&& annotation.type !== 'sticker'\n\t\t\t? annotation\n\t\t\t: undefined\n\t}\n\n\t/**\n\t * @param color the color to apply to the selection\n\t */\n\tfunction apply(color: string): void {\n\t\tconst annotation = recolorable()\n\t\tif (annotation === undefined || annotation.color === color) {\n\t\t\treturn\n\t\t}\n\t\tconst state = context.state.value\n\t\tcontext.preview({\n\t\t\t...state,\n\t\t\tannotations: state.annotations.map((entry) => entry.id === annotation.id ? { ...entry, color } : entry),\n\t\t})\n\t}\n\n\treturn {\n\t\tpreview(color) {\n\t\t\tcontext.drawColor.value = color\n\t\t\tapply(color)\n\t\t},\n\t\tcommit(color) {\n\t\t\tcontext.drawColor.value = color\n\t\t\tapply(color)\n\t\t\t// Nothing to record where the color only affects the next\n\t\t\t// annotation the user draws\n\t\t\tif (recolorable() !== undefined) {\n\t\t\t\tcontext.commit(context.state.value, t('Color'))\n\t\t\t}\n\t\t},\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport type { Tool } from '../../editor/context.ts'\n\nimport { computed } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport ArrowTopRight from 'vue-material-design-icons/ArrowTopRight.vue'\nimport EllipseOutline from 'vue-material-design-icons/EllipseOutline.vue'\nimport FormatText from 'vue-material-design-icons/FormatText.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\nimport RectangleOutline from 'vue-material-design-icons/RectangleOutline.vue'\nimport EditorSlider from '../base/EditorSlider.vue'\nimport { useAnnotationColor } from '../../composables/useAnnotationColor.ts'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { t } from '../../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\nconst color = useAnnotationColor(context)\n\nconst labels = {\n\tcolor: t('Color'),\n\tstrokeWidth: t('Stroke width'),\n\tfontSize: t('Font size'),\n}\n\n// Stands in for the text being sized. Deliberately not translated: it\n// is a glyph whose shape shows a size, not a word to read.\nconst FONT_SAMPLE = 'A'\n\nconst subTools: { id: Tool, label: string, icon: unknown }[] = [\n\t{ id: 'draw', label: t('Draw'), icon: Pencil },\n\t{ id: 'rectangle', label: t('Rectangle'), icon: RectangleOutline },\n\t{ id: 'ellipse', label: t('Ellipse'), icon: EllipseOutline },\n\t{ id: 'arrow', label: t('Arrow'), icon: ArrowTopRight },\n\t{ id: 'text', label: t('Text'), icon: FormatText },\n]\n\nconst showStrokeOptions = computed(() => ['draw', 'rectangle', 'ellipse', 'arrow'].includes(context.activeTool.value))\n\n/** Largest preview that still fits the control card */\nconst PREVIEW_CAP = 44\n\n/** On-screen pixels per image pixel, so previews match the canvas */\nconst viewScale = computed(() => (context.viewFit.value?.scale ?? 1) * context.viewZoom.value)\n\n// Stroke width and font size are image pixels, which say nothing on\n// their own: show the mark at the size it will be drawn instead\nconst strokePreview = computed(() => Math.min(PREVIEW_CAP, Math.max(2, context.strokeWidth.value * viewScale.value)))\nconst fontPreview = computed(() => Math.min(PREVIEW_CAP, Math.max(8, context.fontSize.value * viewScale.value)))\n</script>\n\n<template>\n\t<div class=\"annotate-panel\">\n\t\t<div class=\"annotate-panel__row\">\n\t\t\t<NcButton\n\t\t\t\tv-for=\"tool in subTools\"\n\t\t\t\t:key=\"tool.id\"\n\t\t\t\t:aria-label=\"tool.label\"\n\t\t\t\t:title=\"tool.label\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\t:pressed=\"context.activeTool.value === tool.id\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"context.activeTool.value = tool.id\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<component :is=\"tool.icon\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\n\t\t\t<span class=\"annotate-panel__divider\" />\n\n\t\t\t<label class=\"annotate-panel__option\">\n\t\t\t\t{{ labels.color }}\n\t\t\t\t<!-- Native input: @nextcloud/vue offers no compact color field -->\n\t\t\t\t<input\n\t\t\t\t\t:value=\"context.drawColor.value\"\n\t\t\t\t\ttype=\"color\"\n\t\t\t\t\tdata-test=\"color\"\n\t\t\t\t\t@input=\"color.preview(($event.target as HTMLInputElement).value)\"\n\t\t\t\t\t@change=\"color.commit(($event.target as HTMLInputElement).value)\">\n\t\t\t</label>\n\t\t</div>\n\t\t<EditorSlider\n\t\t\tv-if=\"showStrokeOptions\"\n\t\t\t:value=\"context.strokeWidth.value\"\n\t\t\t:min=\"1\"\n\t\t\t:max=\"32\"\n\t\t\t:step=\"1\"\n\t\t\t:label=\"labels.strokeWidth\"\n\t\t\t@input=\"context.strokeWidth.value = $event\"\n\t\t\t@commit=\"() => {}\">\n\t\t\t<template #preview>\n\t\t\t\t<span\n\t\t\t\t\tclass=\"annotate-panel__dot\"\n\t\t\t\t\tdata-test=\"stroke-preview\"\n\t\t\t\t\t:style=\"{\n\t\t\t\t\t\tinlineSize: `${strokePreview}px`,\n\t\t\t\t\t\tblockSize: `${strokePreview}px`,\n\t\t\t\t\t\tbackgroundColor: context.drawColor.value,\n\t\t\t\t\t}\" />\n\t\t\t</template>\n\t\t</EditorSlider>\n\t\t<EditorSlider\n\t\t\tv-else-if=\"context.activeTool.value === 'text'\"\n\t\t\t:value=\"context.fontSize.value\"\n\t\t\t:min=\"8\"\n\t\t\t:max=\"128\"\n\t\t\t:step=\"1\"\n\t\t\t:label=\"labels.fontSize\"\n\t\t\t@input=\"context.fontSize.value = $event\"\n\t\t\t@commit=\"() => {}\">\n\t\t\t<template #preview>\n\t\t\t\t<span\n\t\t\t\t\tclass=\"annotate-panel__glyph\"\n\t\t\t\t\tdata-test=\"font-preview\"\n\t\t\t\t\t:style=\"{\n\t\t\t\t\t\tfontSize: `${fontPreview}px`,\n\t\t\t\t\t\tcolor: context.drawColor.value,\n\t\t\t\t\t}\">{{ FONT_SAMPLE }}</span>\n\t\t\t</template>\n\t\t</EditorSlider>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.annotate-panel {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\twidth: 100%;\n\n\t&__row {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tflex-wrap: wrap;\n\t\tgap: calc(var(--default-grid-baseline) * 2);\n\t}\n\n\t&__divider {\n\t\twidth: 1px;\n\t\theight: 24px;\n\t\tbackground-color: rgba(255, 255, 255, 0.12);\n\t}\n\n\t&__option {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: var(--default-grid-baseline);\n\t\tfont-size: 12px;\n\t\topacity: 0.9;\n\t}\n\n\t// A ring so the mark stays visible whatever color it is drawn in\n\t&__dot {\n\t\tdisplay: block;\n\t\tborder-radius: 50%;\n\t\tbox-shadow: 0 0 0 1px rgba(255, 255, 255, 0.5);\n\t}\n\n\t&__glyph {\n\t\t// Matches the canvas text nodes so the sample is honest\n\t\tfont-family: Helvetica, Arial, sans-serif;\n\t\tline-height: 1;\n\t\ttext-shadow: 0 0 2px rgba(0, 0, 0, 0.6);\n\t}\n}\n</style>\n","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon flip-horizontal-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M15 21H17V19H15M19 9H21V7H19M3 5V19C3 20.1 3.9 21 5 21H9V19H5V5H9V3H5C3.9 3 3 3.9 3 5M19 3V5H21C21 3.9 20.1 3 19 3M11 23H13V1H11M19 17H21V15H19M15 5H17V3H15M19 13H21V11H19M19 21C20.1 21 21 20.1 21 19H19Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"FlipHorizontalIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon flip-vertical-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M3 15V17H5V15M15 19V21H17V19M19 3H5C3.9 3 3 3.9 3 5V9H5V5H19V9H21V5C21 3.9 20.1 3 19 3M21 19H19V21C20.1 21 21 20.1 21 19M1 11V13H23V11M7 19V21H9V19M19 15V17H21V15M11 19V21H13V19M3 19C3 20.1 3.9 21 5 21V19Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"FlipVerticalIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon rotate-left-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M13,4.07V1L8.45,5.55L13,10V6.09C15.84,6.57 18,9.03 18,12C18,14.97 15.84,17.43 13,17.91V19.93C16.95,19.44 20,16.08 20,12C20,7.92 16.95,4.56 13,4.07M7.1,18.32C8.26,19.22 9.61,19.76 11,19.93V17.9C10.13,17.75 9.29,17.41 8.54,16.87L7.1,18.32M6.09,13H4.07C4.24,14.39 4.79,15.73 5.69,16.89L7.1,15.47C6.58,14.72 6.23,13.88 6.09,13M7.11,8.53L5.7,7.11C4.8,8.27 4.24,9.61 4.07,11H6.09C6.23,10.13 6.58,9.28 7.11,8.53Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"RotateLeftIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon rotate-right-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M16.89,15.5L18.31,16.89C19.21,15.73 19.76,14.39 19.93,13H17.91C17.77,13.87 17.43,14.72 16.89,15.5M13,17.9V19.92C14.39,19.75 15.74,19.21 16.9,18.31L15.46,16.87C14.71,17.41 13.87,17.76 13,17.9M19.93,11C19.76,9.61 19.21,8.27 18.31,7.11L16.89,8.53C17.43,9.28 17.77,10.13 17.91,11M15.55,5.55L11,1V4.07C7.06,4.56 4,7.92 4,12C4,16.08 7.05,19.44 11,19.93V17.91C8.16,17.43 6,14.97 6,12C6,9.03 8.16,6.57 11,6.09V10L15.55,5.55Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"RotateRightIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { InjectionKey } from 'vue'\n\nimport { inject, provide } from 'vue'\n\n/**\n * Imperative editor commands. State-reading controls talk to the\n * context directly; operations that need the host component's stage\n * (orientation size, transitions, the live crop overlay) go through\n * this command surface instead of bubbling event chains.\n */\nexport interface EditorCommands {\n\trotateCW(): void\n\trotateCCW(): void\n\tflipHorizontal(): void\n\tflipVertical(): void\n\t/** Apply the live crop overlay's rectangle */\n\tapplyCrop(): void\n\t/** Drop the crop entirely */\n\tresetCrop(): void\n\t/** Revert every edit as one undoable step */\n\trevert(): void\n}\n\nconst EDITOR_COMMANDS: InjectionKey<EditorCommands> = Symbol('nextcloud:image-editor:commands')\n\n/**\n * Provide the command surface to descendant panels.\n *\n * @param commands the host component's implementations\n */\nexport function provideEditorCommands(commands: EditorCommands): EditorCommands {\n\tprovide(EDITOR_COMMANDS, commands)\n\treturn commands\n}\n\n/**\n * Access the command surface provided by the ImageEditor root.\n */\nexport function useEditorCommands(): EditorCommands {\n\tconst commands = inject(EDITOR_COMMANDS, null)\n\tif (commands === null) {\n\t\tthrow new Error('useEditorCommands() called outside of an ImageEditor tree')\n\t}\n\treturn commands\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport { computed, shallowRef } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport FlipHorizontal from 'vue-material-design-icons/FlipHorizontal.vue'\nimport FlipVertical from 'vue-material-design-icons/FlipVertical.vue'\nimport RotateLeft from 'vue-material-design-icons/RotateLeft.vue'\nimport RotateRight from 'vue-material-design-icons/RotateRight.vue'\nimport EditorSlider from '../base/EditorSlider.vue'\nimport { useEditorCommands } from '../../editor/commands.ts'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { t } from '../../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\nconst commands = useEditorCommands()\n\nconst labels = {\n\trotateLeft: t('Rotate left'),\n\trotateRight: t('Rotate right'),\n\tflipHorizontal: t('Flip horizontal'),\n\tflipVertical: t('Flip vertical'),\n\tapplyCrop: t('Apply crop'),\n\tresetCrop: t('Reset crop'),\n\trotation: t('Rotation'),\n\tscale: t('Scale'),\n}\n\nconst aspectPresets: { id: number | 'original' | null, label: string }[] = [\n\t{ id: null, label: t('Free') },\n\t{ id: 'original', label: t('Original') },\n\t{ id: 1, label: '1:1' },\n\t{ id: 4 / 3, label: '4:3' },\n\t{ id: 16 / 9, label: '16:9' },\n]\n\ntype CropControl = 'rotation' | 'scale'\nconst cropControls: { id: CropControl, label: string }[] = [\n\t{ id: 'rotation', label: labels.rotation },\n\t{ id: 'scale', label: labels.scale },\n]\nconst activeCropControl = shallowRef<CropControl>('rotation')\n\nconst display = computed(() => activeCropControl.value === 'rotation'\n\t? `${context.state.value.fineRotation}°`\n\t: `×${context.state.value.zoom.toFixed(2)}`)\n\n/**\n * Live-preview fine rotation or zoom while the slider is dragged.\n *\n * @param value the new transform value\n */\nfunction onTransformInput(value: number) {\n\tcontext.preview(activeCropControl.value === 'rotation'\n\t\t? { ...context.state.value, fineRotation: value }\n\t\t: { ...context.state.value, zoom: value })\n}\n\n/**\n * Record the current preview as one undo step on release.\n */\nfunction onSliderCommit() {\n\tcontext.commit(context.state.value, activeCropControl.value === 'rotation' ? labels.rotation : labels.scale)\n}\n</script>\n\n<template>\n\t<div class=\"crop-panel\">\n\t\t<div class=\"crop-panel__row\">\n\t\t\t<NcButton\n\t\t\t\tv-for=\"preset in aspectPresets\"\n\t\t\t\t:key=\"String(preset.id)\"\n\t\t\t\t:data-test=\"`aspect-${preset.id === null ? 'free' : preset.id === 'original' ? 'original' : preset.label}`\"\n\t\t\t\t:pressed=\"context.cropAspect.value === preset.id\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"context.cropAspect.value = preset.id\">\n\t\t\t\t{{ preset.label }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div class=\"crop-panel__row\">\n\t\t\t<NcButton\n\t\t\t\t:aria-label=\"labels.rotateLeft\"\n\t\t\t\t:title=\"labels.rotateLeft\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"commands.rotateCCW()\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<RotateLeft :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\t:aria-label=\"labels.rotateRight\"\n\t\t\t\t:title=\"labels.rotateRight\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"commands.rotateCW()\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<RotateRight :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\t:aria-label=\"labels.flipHorizontal\"\n\t\t\t\t:title=\"labels.flipHorizontal\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"commands.flipHorizontal()\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<FlipHorizontal :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\t:aria-label=\"labels.flipVertical\"\n\t\t\t\t:title=\"labels.flipVertical\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"commands.flipVertical()\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<FlipVertical :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\n\t\t\t<span class=\"crop-panel__divider\" />\n\n\t\t\t<NcButton\n\t\t\t\tv-for=\"control in cropControls\"\n\t\t\t\t:key=\"control.id\"\n\t\t\t\t:data-test=\"`tab-${control.id}`\"\n\t\t\t\t:pressed=\"activeCropControl === control.id\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"activeCropControl = control.id\">\n\t\t\t\t{{ control.label }}\n\t\t\t</NcButton>\n\n\t\t\t<span class=\"crop-panel__divider\" />\n\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"reset-crop\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"!loaded || context.state.value.crop === null\"\n\t\t\t\t@click=\"commands.resetCrop()\">\n\t\t\t\t{{ labels.resetCrop }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"apply-crop\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\t@click=\"commands.applyCrop()\">\n\t\t\t\t{{ labels.applyCrop }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<EditorSlider\n\t\t\tv-if=\"activeCropControl === 'rotation'\"\n\t\t\t:value=\"context.state.value.fineRotation\"\n\t\t\t:min=\"-45\"\n\t\t\t:max=\"45\"\n\t\t\t:step=\"1\"\n\t\t\t:label=\"labels.rotation\"\n\t\t\t:display=\"display\"\n\t\t\tdata-test=\"fine-rotation\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\t@input=\"onTransformInput\"\n\t\t\t@commit=\"onSliderCommit\" />\n\t\t<EditorSlider\n\t\t\tv-else\n\t\t\t:value=\"context.state.value.zoom\"\n\t\t\t:min=\"1\"\n\t\t\t:max=\"3\"\n\t\t\t:step=\"0.05\"\n\t\t\t:label=\"labels.scale\"\n\t\t\t:display=\"display\"\n\t\t\tdata-test=\"zoom\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\t@input=\"onTransformInput\"\n\t\t\t@commit=\"onSliderCommit\" />\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.crop-panel {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\twidth: 100%;\n\n\t&__row {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tflex-wrap: wrap;\n\t\tgap: calc(var(--default-grid-baseline) * 2);\n\t}\n\n\t&__divider {\n\t\twidth: 1px;\n\t\theight: 24px;\n\t\tbackground-color: rgba(255, 255, 255, 0.12);\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\ndefineProps<{\n\t/** Preview image data URL */\n\turl: string\n\t/** Visible label under the preview */\n\tlabel: string\n\t/** Whether this preset is the active one */\n\tactive?: boolean\n\t/** Whether the chip is disabled */\n\tdisabled?: boolean\n\t/** Hook for the browser test suite */\n\tdataTest?: string\n}>()\n\nconst emit = defineEmits<{\n\tclick: []\n}>()\n</script>\n\n<template>\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"preset-chip\"\n\t\t:class=\"{ 'preset-chip--active': active }\"\n\t\t:disabled=\"disabled\"\n\t\t:data-test=\"dataTest\"\n\t\t:aria-pressed=\"active\"\n\t\t:title=\"label\"\n\t\t@click=\"emit('click')\">\n\t\t<img :src=\"url\" :alt=\"label\">\n\t\t<span>{{ label }}</span>\n\t</button>\n</template>\n\n<style scoped lang=\"scss\">\n.preset-chip {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 2px;\n\tpadding: 0;\n\tborder: none;\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 10px;\n\tcursor: pointer;\n\n\timg {\n\t\twidth: 64px;\n\t\taspect-ratio: 4 / 3;\n\t\tobject-fit: cover;\n\t\tborder-radius: 10px;\n\t\tbox-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1);\n\t\ttransition: box-shadow 0.12s ease, transform 0.12s ease;\n\t}\n\n\t&:hover img {\n\t\ttransform: scale(1.03);\n\t}\n\n\t&--active img,\n\t&:focus-visible img {\n\t\tbox-shadow: 0 0 0 2px var(--color-primary-element);\n\t}\n\n\t&:focus-visible {\n\t\toutline: none;\n\t}\n\n\t&:disabled {\n\t\topacity: 0.5;\n\t\tcursor: default;\n\t}\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/** The subset of ImageData the pixel filters operate on */\nexport interface PixelData {\n\tdata: Uint8ClampedArray\n}\n\n/** Konva calls a filter with the node it belongs to as `this` */\nexport interface FilterNode {\n\t/** Amount between -1 and 1, 0 meaning unchanged */\n\tsaturation(): number\n}\n\n/**\n * Rec. 601 luma, the gray a pixel collapses to.\n *\n * @param r the red channel\n * @param g the green channel\n * @param b the blue channel\n */\nfunction luma(r: number, g: number, b: number): number {\n\treturn 0.299 * r + 0.587 * g + 0.114 * b\n}\n\n/**\n * Linear saturation: each channel moves away from the pixel's luma by\n * the given factor. Konva's own HSL filter raises 2 to the amount, so\n * it can lighten or deepen colors but never reaches gray, which left\n * the saturation slider unable to do the one thing its lower half\n * promises.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function saturate(this: FilterNode, imageData: PixelData): void {\n\tconst { data } = imageData\n\t// -1 collapses to gray, 0 is unchanged, 1 doubles the distance\n\tconst factor = this.saturation() + 1\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst gray = luma(data[i]!, data[i + 1]!, data[i + 2]!)\n\t\tdata[i] = gray + (data[i]! - gray) * factor\n\t\tdata[i + 1] = gray + (data[i + 1]! - gray) * factor\n\t\tdata[i + 2] = gray + (data[i + 2]! - gray) * factor\n\t}\n}\n\n/**\n * Warm tint: lifts red, dampens blue.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function warm(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tdata[i] = Math.min(255, data[i]! * 1.12)\n\t\tdata[i + 2] = data[i + 2]! * 0.9\n\t}\n}\n\n/**\n * Cool tint: lifts blue, dampens red.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function cool(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tdata[i] = data[i]! * 0.9\n\t\tdata[i + 2] = Math.min(255, data[i + 2]! * 1.12)\n\t}\n}\n\n/**\n * Faded film look: lifted blacks, mild desaturation, a touch of warmth.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function fade(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst luma = 0.299 * data[i]! + 0.587 * data[i + 1]! + 0.114 * data[i + 2]!\n\t\t// 70% original + 30% luma, compressed into a lifted range\n\t\tdata[i] = 28 + (0.7 * data[i]! + 0.3 * luma) * 0.86 * 1.04\n\t\tdata[i + 1] = 28 + (0.7 * data[i + 1]! + 0.3 * luma) * 0.86\n\t\tdata[i + 2] = 28 + (0.7 * data[i + 2]! + 0.3 * luma) * 0.86 * 0.96\n\t}\n}\n\n/**\n * High-contrast black and white.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function noir(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst luma = 0.299 * data[i]! + 0.587 * data[i + 1]! + 0.114 * data[i + 2]!\n\t\t// Steepened S-curve around the midpoint\n\t\tconst value = Math.min(255, Math.max(0, (luma - 128) * 1.35 + 118))\n\t\tdata[i] = value\n\t\tdata[i + 1] = value\n\t\tdata[i + 2] = value\n\t}\n}\n\n/**\n * Golden hour: warm amber highlights and gently dampened blues.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function golden(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tdata[i] = data[i]! * 1.12 + 12\n\t\tdata[i + 1] = data[i + 1]! * 1.04 + 5\n\t\tdata[i + 2] = data[i + 2]! * 0.82\n\t}\n}\n\n/**\n * Bright coastal look: punchy contrast with teal-tinted shadows.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function coast(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst luma = 0.299 * data[i]! + 0.587 * data[i + 1]! + 0.114 * data[i + 2]!\n\t\t// The teal cast only reaches into the shadows\n\t\tconst shadow = Math.max(0, 1 - luma / 140)\n\t\tdata[i] = (data[i]! - 128) * 1.12 + 132\n\t\tdata[i + 1] = (data[i + 1]! - 128) * 1.12 + 132 + 10 * shadow\n\t\tdata[i + 2] = (data[i + 2]! - 128) * 1.12 + 132 + 22 * shadow\n\t}\n}\n\n/**\n * Soft matte look: desaturated, lifted blacks, compressed highlights.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function mist(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst luma = 0.299 * data[i]! + 0.587 * data[i + 1]! + 0.114 * data[i + 2]!\n\t\t// 60% original + 40% luma, squeezed into a matte range\n\t\tdata[i] = 22 + (0.6 * data[i]! + 0.4 * luma) * 0.84\n\t\tdata[i + 1] = 22 + (0.6 * data[i + 1]! + 0.4 * luma) * 0.84\n\t\tdata[i + 2] = 26 + (0.6 * data[i + 2]! + 0.4 * luma) * 0.84\n\t}\n}\n\n/**\n * Moody plum tint: magenta cast with deepened shadows.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function berry(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tdata[i] = (data[i]! - 128) * 1.08 + 128 + 10\n\t\tdata[i + 1] = (data[i + 1]! - 128) * 1.08 + 128 - 12\n\t\tdata[i + 2] = (data[i + 2]! - 128) * 1.08 + 128 + 8\n\t}\n}\n\n/**\n * Film grade: orange-leaning highlights against teal shadows.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function cinema(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst luma = 0.299 * data[i]! + 0.587 * data[i + 1]! + 0.114 * data[i + 2]!\n\t\t// -1 in the deepest shadows, +1 in the brightest highlights\n\t\tconst balance = (luma - 128) / 128\n\t\tdata[i] = (data[i]! - 128) * 1.06 + 128 + 16 * balance\n\t\tdata[i + 1] = (data[i + 1]! - 128) * 1.06 + 128\n\t\tdata[i + 2] = (data[i + 2]! - 128) * 1.06 + 128 - 20 * balance\n\t}\n}\n\n/**\n * Silvery monochrome: soft black and white with lifted shadows.\n *\n * @param imageData the pixels to mutate in place\n */\nexport function luna(imageData: PixelData): void {\n\tconst { data } = imageData\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst luma = 0.299 * data[i]! + 0.587 * data[i + 1]! + 0.114 * data[i + 2]!\n\t\t// Gentle roll-off instead of noir's hard S-curve\n\t\tconst value = 18 + luma * 0.9\n\t\tdata[i] = value\n\t\tdata[i + 1] = value\n\t\tdata[i + 2] = value + 4\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Annotation, EditorState, Size } from './state.ts'\n\nimport Konva from 'konva'\nimport { berry, cinema, coast, cool, fade, golden, luna, mist, noir, saturate, warm } from './filters.ts'\n\n/**\n * The part of the oriented image currently visible: the crop, or all of it.\n *\n * @param state the edit state\n * @param oriented the oriented image size\n */\nexport function visibleRect(state: EditorState, oriented: Size) {\n\treturn state.crop ?? { x: 0, y: 0, ...oriented }\n}\n\n/**\n * 2D context of a canvas, or an error where none is available, matching\n * how orient.ts reports the same condition.\n *\n * @param canvas the canvas to draw on\n */\nfunction context2d(canvas: HTMLCanvasElement): CanvasRenderingContext2D {\n\tconst context = canvas.getContext('2d')\n\tif (context === null) {\n\t\tthrow new Error('Canvas 2D context unavailable')\n\t}\n\treturn context\n}\n\n/**\n * Whether a 2D context honors the `filter` property. WebKit only\n * shipped it in Safari 18; where it is missing, the assignment is\n * ignored and the getter keeps reporting 'none'.\n *\n * @param context the context to probe, null when none is available\n */\nexport function supportsContextFilter(context: Pick<CanvasRenderingContext2D, 'filter'> | null): boolean {\n\tif (context === null) {\n\t\treturn false\n\t}\n\tcontext.filter = 'blur(1px)'\n\treturn context.filter !== 'none'\n}\n\n/** Probed once: the answer cannot change within a document */\nlet contextFilterSupport: boolean | null = null\n\n/**\n * Memoized probe of canvas filter support in this browser.\n */\nfunction contextFilterAvailable(): boolean {\n\tcontextFilterSupport ??= supportsContextFilter(document.createElement('canvas').getContext('2d'))\n\treturn contextFilterSupport\n}\n\n/**\n * Obfuscate a region of the oriented image: pixelate averages it into\n * coarse blocks, blur applies a strong gaussian. Either way the\n * information is destroyed in the exported pixels, not overlaid.\n *\n * Blur needs canvas filter support. Without it the region would be\n * drawn untouched while the interface claims it is redacted, so the\n * style silently degrades to pixelation: obfuscating differently than\n * asked is recoverable, exporting readable pixels is not.\n *\n * @param oriented the orientation-baked source canvas\n * @param rect the region to obfuscate\n * @param rect.x horizontal region origin\n * @param rect.y vertical region origin\n * @param rect.width region width\n * @param rect.height region height\n * @param style pixelate or blur\n */\nfunction obfuscate(\n\toriented: HTMLCanvasElement,\n\trect: { x: number, y: number, width: number, height: number },\n\tstyle: 'pixelate' | 'blur',\n): HTMLCanvasElement {\n\tconst strength = Math.max(4, Math.round(Math.min(oriented.width, oriented.height) / 40))\n\tconst out = document.createElement('canvas')\n\tout.width = Math.max(1, Math.ceil(rect.width))\n\tout.height = Math.max(1, Math.ceil(rect.height))\n\tconst context = context2d(out)\n\n\tif (style === 'blur' && contextFilterAvailable()) {\n\t\t// Draw with padding so the blur does not bleed transparency in\n\t\t// from the edges, the canvas bounds crop the padding again\n\t\tconst pad = strength * 2\n\t\tcontext.filter = `blur(${strength}px)`\n\t\tcontext.drawImage(\n\t\t\toriented,\n\t\t\trect.x - pad,\n\t\t\trect.y - pad,\n\t\t\trect.width + pad * 2,\n\t\t\trect.height + pad * 2,\n\t\t\t-pad,\n\t\t\t-pad,\n\t\t\tout.width + pad * 2,\n\t\t\tout.height + pad * 2,\n\t\t)\n\t\treturn out\n\t}\n\n\tconst small = document.createElement('canvas')\n\tsmall.width = Math.max(1, Math.ceil(rect.width / strength))\n\tsmall.height = Math.max(1, Math.ceil(rect.height / strength))\n\tcontext2d(small)\n\t\t.drawImage(oriented, rect.x, rect.y, rect.width, rect.height, 0, 0, small.width, small.height)\n\tcontext.imageSmoothingEnabled = false\n\tcontext.drawImage(small, 0, 0, out.width, out.height)\n\treturn out\n}\n\n/**\n * Build the Konva node for one annotation. Nodes carry the annotation id\n * and the 'annotation' name so tools can map them back to state entries.\n *\n * @param annotation the annotation to render\n * @param oriented the orientation-baked source canvas, needed by redact\n */\nexport function buildAnnotationNode(annotation: Annotation, oriented?: HTMLCanvasElement): Konva.Shape {\n\tconst base = { id: annotation.id, name: 'annotation' }\n\tswitch (annotation.type) {\n\t\tcase 'draw':\n\t\t\treturn new Konva.Line({\n\t\t\t\t...base,\n\t\t\t\tpoints: annotation.points,\n\t\t\t\tstroke: annotation.color,\n\t\t\t\tstrokeWidth: annotation.strokeWidth,\n\t\t\t\tlineCap: 'round',\n\t\t\t\tlineJoin: 'round',\n\t\t\t})\n\t\tcase 'arrow':\n\t\t\treturn new Konva.Arrow({\n\t\t\t\t...base,\n\t\t\t\tpoints: [...annotation.points],\n\t\t\t\tstroke: annotation.color,\n\t\t\t\tfill: annotation.color,\n\t\t\t\tstrokeWidth: annotation.strokeWidth,\n\t\t\t\tpointerLength: annotation.strokeWidth * 4,\n\t\t\t\tpointerWidth: annotation.strokeWidth * 4,\n\t\t\t})\n\t\tcase 'rectangle':\n\t\t\treturn new Konva.Rect({\n\t\t\t\t...base,\n\t\t\t\t...annotation.rect,\n\t\t\t\trotation: annotation.rotation,\n\t\t\t\tstroke: annotation.color,\n\t\t\t\tstrokeWidth: annotation.strokeWidth,\n\t\t\t})\n\t\tcase 'ellipse':\n\t\t\t// Positioned at the rect's top-left with a negative offset so\n\t\t\t// the rotation pivots on the same anchor as rectangles\n\t\t\treturn new Konva.Ellipse({\n\t\t\t\t...base,\n\t\t\t\tx: annotation.rect.x,\n\t\t\t\ty: annotation.rect.y,\n\t\t\t\toffsetX: -annotation.rect.width / 2,\n\t\t\t\toffsetY: -annotation.rect.height / 2,\n\t\t\t\tradiusX: annotation.rect.width / 2,\n\t\t\t\tradiusY: annotation.rect.height / 2,\n\t\t\t\trotation: annotation.rotation,\n\t\t\t\tstroke: annotation.color,\n\t\t\t\tstrokeWidth: annotation.strokeWidth,\n\t\t\t})\n\t\tcase 'text':\n\t\tcase 'sticker':\n\t\t\treturn new Konva.Text({\n\t\t\t\t...base,\n\t\t\t\tx: annotation.x,\n\t\t\t\ty: annotation.y,\n\t\t\t\ttext: annotation.text,\n\t\t\t\tfill: annotation.color,\n\t\t\t\tfontSize: annotation.fontSize,\n\t\t\t\trotation: annotation.rotation,\n\t\t\t\t// Kept in sync with the text overlay for WYSIWYG editing\n\t\t\t\tfontFamily: 'Helvetica, Arial, sans-serif',\n\t\t\t})\n\t\tcase 'redact': {\n\t\t\tif (oriented === undefined) {\n\t\t\t\tthrow new Error('Redaction requires the oriented image')\n\t\t\t}\n\t\t\treturn new Konva.Image({\n\t\t\t\t...base,\n\t\t\t\timage: obfuscate(oriented, annotation.rect, annotation.style),\n\t\t\t\tx: annotation.rect.x,\n\t\t\t\ty: annotation.rect.y,\n\t\t\t})\n\t\t}\n\t}\n}\n\n/**\n * Apply adjustments and the filter preset to the image node.\n * Konva filters require the node to be cached; the cache is dropped\n * again when no filter is active.\n *\n * @param node the Konva image node\n * @param state the edit state\n * @param pixelRatio cache resolution: 1 for exports, the view scale for\n * interactive rendering so slider drags stay smooth on large images\n */\nexport function applyFilters(node: Konva.Image, state: EditorState, pixelRatio = 1): void {\n\tconst { brightness, contrast, saturation } = state.adjustments\n\tconst filters = []\n\n\tif (brightness !== 0) {\n\t\tfilters.push(Konva.Filters.Brighten)\n\t}\n\tif (contrast !== 0) {\n\t\tfilters.push(Konva.Filters.Contrast)\n\t}\n\tif (saturation !== 0) {\n\t\tfilters.push(saturate)\n\t}\n\tconst presetFilters = {\n\t\tnone: null,\n\t\tgrayscale: Konva.Filters.Grayscale,\n\t\tnoir,\n\t\tluna,\n\t\tsepia: Konva.Filters.Sepia,\n\t\tfade,\n\t\twarm,\n\t\tcool,\n\t\tgolden,\n\t\tcoast,\n\t\tmist,\n\t\tberry,\n\t\tcinema,\n\t\tinvert: Konva.Filters.Invert,\n\t\tsolarize: Konva.Filters.Solarize,\n\t\tposterize: Konva.Filters.Posterize,\n\t\tpop: Konva.Filters.Enhance,\n\t}[state.preset]\n\tif (presetFilters !== null) {\n\t\tfilters.push(presetFilters)\n\t}\n\n\tif (filters.length === 0) {\n\t\tnode.filters([])\n\t\tnode.clearCache()\n\t\treturn\n\t}\n\n\tnode.filters(filters)\n\tnode.brightness(brightness / 100)\n\tnode.contrast(contrast)\n\tnode.saturation(saturation / 100)\n\tif (state.preset === 'posterize') {\n\t\t// Konva maps levels() over 254 steps: 0.02 gives about six bands\n\t\tnode.levels(0.02)\n\t}\n\tif (state.preset === 'pop') {\n\t\tnode.enhance(0.25)\n\t}\n\tnode.cache({ pixelRatio })\n}\n\n/**\n * What a set of preset thumbnails depends on, the preset aside: the\n * visible area and the adjustments baked into every one of them.\n * Picking a preset or editing an annotation changes neither, so the\n * thumbnails do not have to be redrawn for those.\n *\n * @param state the current edit state\n */\nexport function thumbnailKey(state: EditorState): string {\n\tconst { crop, adjustments } = state\n\treturn [\n\t\tcrop?.x,\n\t\tcrop?.y,\n\t\tcrop?.width,\n\t\tcrop?.height,\n\t\tadjustments.brightness,\n\t\tadjustments.contrast,\n\t\tadjustments.saturation,\n\t].join('|')\n}\n\n/**\n * Small data-URL preview of the visible image with a preset applied,\n * for the filter picker chips.\n *\n * @param oriented the orientation-baked source canvas\n * @param state the current edit state\n * @param preset the preset to preview instead of the active one\n * @param size bound for the longest thumbnail edge\n */\nexport function presetThumbnail(oriented: HTMLCanvasElement, state: EditorState, preset: EditorState['preset'], size = 96): string {\n\tconst visible = visibleRect(state, { width: oriented.width, height: oriented.height })\n\tconst scale = Math.min(size / visible.width, size / visible.height)\n\tconst thumb = document.createElement('canvas')\n\tthumb.width = Math.max(1, Math.round(visible.width * scale))\n\tthumb.height = Math.max(1, Math.round(visible.height * scale))\n\tcontext2d(thumb)\n\t\t.drawImage(oriented, visible.x, visible.y, visible.width, visible.height, 0, 0, thumb.width, thumb.height)\n\n\tconst stage = new Konva.Stage({\n\t\tcontainer: document.createElement('div'),\n\t\twidth: thumb.width,\n\t\theight: thumb.height,\n\t})\n\ttry {\n\t\tconst node = new Konva.Image({ image: thumb, listening: false })\n\t\tapplyFilters(node, { ...state, preset })\n\t\tconst layer = new Konva.Layer()\n\t\tlayer.add(node)\n\t\tstage.add(layer)\n\t\treturn stage.toDataURL()\n\t} finally {\n\t\tstage.destroy()\n\t}\n}\n\nexport interface SceneOptions {\n\t/** Uniform view scale applied to the content */\n\tscale: number\n\t/** Stage-space position of the visible area's top-left corner */\n\toffset: { x: number, y: number }\n\t/** Clip to the crop rect; disabled while the crop tool shows context */\n\tshowCropped: boolean\n\t/**\n\t * Cache filters at display resolution instead of full resolution.\n\t * Only wanted while a slider is actively scrubbing: it keeps drags\n\t * smooth on large images, at rest the cache must be full quality.\n\t */\n\tfastFilters?: boolean\n}\n\nexport interface Scene {\n\t/** Carries the view transform and the crop clip; owned by update() */\n\tviewGroup: Konva.Group\n\t/**\n\t * The group transitions animate: identity outside a transition, so\n\t * tweens and reconciliation never write the same attributes\n\t */\n\tcontentGroup: Konva.Group\n\timageNode: Konva.Image\n\t/** Reconcile the stage content with the given state and view */\n\tupdate(oriented: HTMLCanvasElement, state: EditorState, options: SceneOptions): void\n\tdestroy(): void\n}\n\n/**\n * Create a persistent scene on the stage. update() reconciles instead\n * of rebuilding: the image node survives every call, annotation nodes\n * are keyed by id and only rebuilt when their state entry changed, and\n * the filter cache is only redone when its inputs changed. One code\n * path still renders both the interactive view and the export.\n *\n * @param stage the target stage\n */\nexport function createScene(stage: Konva.Stage): Scene {\n\tconst layer = new Konva.Layer()\n\tconst viewGroup = new Konva.Group({ name: 'view' })\n\tconst contentGroup = new Konva.Group({ name: 'content' })\n\tconst imageNode = new Konva.Image({ image: undefined, listening: false })\n\tcontentGroup.add(imageNode)\n\tviewGroup.add(contentGroup)\n\tlayer.add(viewGroup)\n\tstage.add(layer)\n\n\t// Which state entry each node was built from, and the inputs of the\n\t// current filter cache: reference equality decides whether work is due\n\tconst built = new Map<string, { annotation: Annotation, node: Konva.Shape }>()\n\tlet filterKey = ''\n\n\tconst update = (oriented: HTMLCanvasElement, state: EditorState, options: SceneOptions): void => {\n\t\tconst orientedChanged = imageNode.image() !== oriented\n\t\tif (orientedChanged) {\n\t\t\timageNode.image(oriented)\n\t\t}\n\n\t\t// While the crop tool shows the full image for context, the view\n\t\t// origin is the image corner instead of the crop corner\n\t\tconst origin = options.showCropped\n\t\t\t? visibleRect(state, { width: oriented.width, height: oriented.height })\n\t\t\t: { x: 0, y: 0 }\n\t\tviewGroup.position({\n\t\t\tx: options.offset.x - origin.x * options.scale,\n\t\t\ty: options.offset.y - origin.y * options.scale,\n\t\t})\n\t\tviewGroup.scale({ x: options.scale, y: options.scale })\n\t\tif (options.showCropped && state.crop !== null) {\n\t\t\tviewGroup.clip(state.crop)\n\t\t} else {\n\t\t\t// Konva clips whenever clipWidth is set: unset it to disable\n\t\t\tviewGroup.clipWidth(undefined as unknown as number)\n\t\t\tviewGroup.clipHeight(undefined as unknown as number)\n\t\t}\n\n\t\tconst pixelRatio = options.fastFilters\n\t\t\t? Math.min(1, options.scale * (globalThis.devicePixelRatio || 1))\n\t\t\t: 1\n\t\tconst { brightness, contrast, saturation } = state.adjustments\n\t\tconst nextFilterKey = `${brightness}|${contrast}|${saturation}|${state.preset}|${pixelRatio}`\n\t\tif (orientedChanged || nextFilterKey !== filterKey) {\n\t\t\tapplyFilters(imageNode, state, pixelRatio)\n\t\t\tfilterKey = nextFilterKey\n\t\t}\n\n\t\t// Keyed reconciliation: a changed entry reference means the node\n\t\t// is stale; a new oriented canvas invalidates every node because\n\t\t// redactions sample its pixels\n\t\tconst seen = new Set<string>()\n\t\tfor (const annotation of state.annotations) {\n\t\t\tseen.add(annotation.id)\n\t\t\tconst entry = built.get(annotation.id)\n\t\t\tif (entry !== undefined && entry.annotation === annotation && !orientedChanged) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tentry?.node.destroy()\n\t\t\tconst node = buildAnnotationNode(annotation, oriented)\n\t\t\tcontentGroup.add(node)\n\t\t\tbuilt.set(annotation.id, { annotation, node })\n\t\t}\n\t\tfor (const [id, entry] of built) {\n\t\t\tif (!seen.has(id)) {\n\t\t\t\tentry.node.destroy()\n\t\t\t\tbuilt.delete(id)\n\t\t\t}\n\t\t}\n\n\t\t// Stacking order: image at the bottom, annotations in state order\n\t\timageNode.zIndex(0)\n\t\tstate.annotations.forEach((annotation, index) => built.get(annotation.id)!.node.zIndex(index + 1))\n\t}\n\n\treturn {\n\t\tviewGroup,\n\t\tcontentGroup,\n\t\timageNode,\n\t\tupdate,\n\t\tdestroy: () => {\n\t\t\tbuilt.clear()\n\t\t\tlayer.destroy()\n\t\t},\n\t}\n}\n\n/**\n * One-shot render of the edit state onto a fresh stage, for exports and\n * thumbnails where nothing needs to persist.\n *\n * @param stage the target stage, expected to be empty\n * @param oriented the orientation-baked source canvas\n * @param state the edit state\n * @param options view transform and crop behavior\n */\nexport function renderScene(\n\tstage: Konva.Stage,\n\toriented: HTMLCanvasElement,\n\tstate: EditorState,\n\toptions: SceneOptions,\n): Scene {\n\tconst scene = createScene(stage)\n\tscene.update(oriented, state, options)\n\treturn scene\n}\n\n/**\n * Render the edit state to a canvas at natural resolution, optionally\n * downscaled so its longest edge is at most maxSize.\n *\n * @param oriented the orientation-baked source canvas\n * @param state the edit state\n * @param maxSize optional bound for the longest output edge\n */\nexport function renderToCanvas(oriented: HTMLCanvasElement, state: EditorState, maxSize?: number): HTMLCanvasElement {\n\tconst visible = visibleRect(state, { width: oriented.width, height: oriented.height })\n\tconst pixelRatio = maxSize === undefined\n\t\t? 1\n\t\t: Math.min(1, maxSize / Math.max(visible.width, visible.height))\n\n\tconst stage = new Konva.Stage({\n\t\t// Detached container: the export stage is never displayed\n\t\tcontainer: document.createElement('div'),\n\t\twidth: visible.width,\n\t\theight: visible.height,\n\t})\n\ttry {\n\t\trenderScene(stage, oriented, state, {\n\t\t\tscale: 1,\n\t\t\toffset: { x: 0, y: 0 },\n\t\t\tshowCropped: true,\n\t\t})\n\t\treturn stage.toCanvas({ pixelRatio })\n\t} finally {\n\t\tstage.destroy()\n\t}\n}\n\n/**\n * Convert a stage-space pointer position to oriented image coordinates.\n *\n * @param pointer the stage pointer position\n * @param pointer.x horizontal stage coordinate\n * @param pointer.y vertical stage coordinate\n * @param state the edit state\n * @param oriented the oriented image size\n * @param options the current view transform\n */\nexport function toImageCoords(\n\tpointer: { x: number, y: number },\n\tstate: EditorState,\n\toriented: Size,\n\toptions: SceneOptions,\n): { x: number, y: number } {\n\tconst visible = visibleRect(state, oriented)\n\treturn {\n\t\tx: (pointer.x - options.offset.x) / options.scale + (options.showCropped ? visible.x : 0),\n\t\ty: (pointer.y - options.offset.y) / options.scale + (options.showCropped ? visible.y : 0),\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport type { FilterPreset } from '../../editor/state.ts'\n\nimport { shallowRef, watch } from 'vue'\nimport GlassSurface from '../base/GlassSurface.vue'\nimport PresetChip from '../base/PresetChip.vue'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { presetThumbnail, thumbnailKey } from '../../editor/render.ts'\nimport { t } from '../../utils/l10n.ts'\n\nconst props = defineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n\t/** Orientation-baked source canvas, for the previews */\n\toriented?: HTMLCanvasElement | null\n}>()\n\nconst context = useEditorContext()\n\nconst presets: { id: FilterPreset, label: string }[] = [\n\t{ id: 'none', label: t('No filter') },\n\t{ id: 'pop', label: t('Pop') },\n\t{ id: 'golden', label: t('Golden') },\n\t{ id: 'coast', label: t('Coast') },\n\t{ id: 'cinema', label: t('Cinema') },\n\t{ id: 'berry', label: t('Berry') },\n\t{ id: 'mist', label: t('Mist') },\n\t{ id: 'warm', label: t('Warm') },\n\t{ id: 'cool', label: t('Cool') },\n\t{ id: 'fade', label: t('Fade') },\n\t{ id: 'grayscale', label: t('Grayscale') },\n\t{ id: 'noir', label: t('Noir') },\n\t{ id: 'luna', label: t('Luna') },\n\t{ id: 'sepia', label: t('Sepia') },\n\t{ id: 'invert', label: t('Invert') },\n\t{ id: 'solarize', label: t('Solarize') },\n\t{ id: 'posterize', label: t('Posterize') },\n]\n\n// Live preview chips: each preset applied to the current image.\n// Redrawing all seventeen means seventeen filter passes and as many\n// data URLs, so they are only redrawn when what they show changes,\n// which is the image, the crop and the adjustments. Picking a preset\n// or drawing an annotation leaves them alone.\nconst presetPreviews = shallowRef<{ id: FilterPreset, label: string, url: string }[]>([])\n\nwatch(\n\t[() => props.oriented, () => thumbnailKey(context.state.value)],\n\t([oriented]) => {\n\t\tpresetPreviews.value = oriented\n\t\t\t? presets.map((preset) => ({\n\t\t\t\t\t...preset,\n\t\t\t\t\turl: presetThumbnail(oriented, context.state.value, preset.id),\n\t\t\t\t}))\n\t\t\t: []\n\t},\n\t{ immediate: true },\n)\n\n/**\n * Apply a filter preset.\n *\n * @param preset the preset to apply\n * @param label the preset's translated name, for the history list\n */\nfunction setPreset(preset: FilterPreset, label: string) {\n\tcontext.commit({ ...context.state.value, preset }, label)\n}\n</script>\n\n<template>\n\t<GlassSurface variant=\"strip\" class=\"filter-strip\">\n\t\t<PresetChip\n\t\t\tv-for=\"preset in presetPreviews\"\n\t\t\t:key=\"preset.id\"\n\t\t\t:url=\"preset.url\"\n\t\t\t:label=\"preset.label\"\n\t\t\t:active=\"context.state.value.preset === preset.id\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\t:data-test=\"`preset-${preset.id}`\"\n\t\t\t@click=\"setPreset(preset.id, preset.label)\" />\n\t</GlassSurface>\n</template>\n\n<style scoped lang=\"scss\">\n.filter-strip {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\tpadding: calc(var(--default-grid-baseline) * 2);\n\toverflow-y: auto;\n\tmax-height: 100%;\n\n\t// Slim glass-fitting scrollbar\n\tscrollbar-width: thin;\n\tscrollbar-color: rgba(255, 255, 255, 0.25) transparent;\n\n\t&::-webkit-scrollbar {\n\t\twidth: 6px;\n\t\theight: 6px;\n\t}\n\n\t&::-webkit-scrollbar-thumb {\n\t\tbackground: rgba(255, 255, 255, 0.22);\n\t\tborder-radius: 3px;\n\t}\n\n\t&::-webkit-scrollbar-track {\n\t\tbackground: transparent;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { t } from '../../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\n\nconst labels = {\n\tpixelate: t('Pixelate'),\n\tblur: t('Blur'),\n}\n</script>\n\n<template>\n\t<div class=\"redact-panel\">\n\t\t<NcButton\n\t\t\tdata-test=\"redact-pixelate\"\n\t\t\t:pressed=\"context.redactStyle.value === 'pixelate'\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"context.redactStyle.value = 'pixelate'\">\n\t\t\t{{ labels.pixelate }}\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tdata-test=\"redact-blur\"\n\t\t\t:pressed=\"context.redactStyle.value === 'blur'\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"context.redactStyle.value = 'blur'\">\n\t\t\t{{ labels.blur }}\n\t\t</NcButton>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.redact-panel {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: calc(var(--default-grid-baseline) * 2);\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useAnnotationColor } from '../../composables/useAnnotationColor.ts'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { t } from '../../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\nconst color = useAnnotationColor(context)\n\nconst colorLabel = t('Color')\nconst hint = t('Click an annotation to move, resize or recolor it')\nconst transformHint = t('Drag to move, use the handles to resize')\n\nconst selectedAnnotation = computed(() => context.state.value.annotations\n\t.find((annotation) => annotation.id === context.selectedId.value) ?? null)\n\n// Stickers render the emoji glyph and redactions destroy pixels:\n// neither has a visible color, so the picker would mislead\nconst recolorable = computed(() => selectedAnnotation.value !== null\n\t&& selectedAnnotation.value.type !== 'sticker'\n\t&& selectedAnnotation.value.type !== 'redact')\n</script>\n\n<template>\n\t<div class=\"select-panel\">\n\t\t<label v-if=\"recolorable\" class=\"select-panel__option\">\n\t\t\t{{ colorLabel }}\n\t\t\t<!-- Native input: @nextcloud/vue offers no compact color field -->\n\t\t\t<input\n\t\t\t\t:value=\"context.drawColor.value\"\n\t\t\t\ttype=\"color\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tdata-test=\"color\"\n\t\t\t\t@input=\"color.preview(($event.target as HTMLInputElement).value)\"\n\t\t\t\t@change=\"color.commit(($event.target as HTMLInputElement).value)\">\n\t\t</label>\n\t\t<span v-else-if=\"selectedAnnotation !== null\" class=\"select-panel__hint\">{{ transformHint }}</span>\n\t\t<span v-else class=\"select-panel__hint\">{{ hint }}</span>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.select-panel {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\n\t&__option {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: var(--default-grid-baseline);\n\t\tfont-size: 12px;\n\t\topacity: 0.9;\n\t}\n\n\t&__hint {\n\t\tfont-size: 12px;\n\t\topacity: 0.65;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport { emojiSearch } from '@nextcloud/vue/functions/emoji'\nimport { computed } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcEmojiPicker from '@nextcloud/vue/components/NcEmojiPicker'\nimport { useEditorContext } from '../../editor/context.ts'\nimport { t } from '../../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\n\nconst moreLabel = t('More emojis')\n\nconst FALLBACK_STICKERS = ['😀', '😍', '🎉', '👍', '❤️', '⭐', '🔥', '💡', '✅', '❌', '❓', '⚠️']\n\n/**\n * The user's frequently used emojis, falling back to a curated set\n * when there is no usage history yet.\n */\nfunction frequentStickers(): string[] {\n\ttry {\n\t\tconst frequent = emojiSearch('', 12)\n\t\t\t.map((emoji) => (emoji as { native?: string }).native)\n\t\t\t.filter((native): native is string => typeof native === 'string' && native !== '')\n\t\treturn frequent.length >= 6 ? frequent : FALLBACK_STICKERS\n\t} catch {\n\t\treturn FALLBACK_STICKERS\n\t}\n}\n\nconst DEFAULT_STICKERS = frequentStickers()\n\n// The picked emoji joins the quick row when it came from the picker\nconst stickers = computed(() => DEFAULT_STICKERS.includes(context.sticker.value)\n\t? DEFAULT_STICKERS\n\t: [context.sticker.value, ...DEFAULT_STICKERS.slice(0, 11)])\n</script>\n\n<template>\n\t<div class=\"sticker-panel\">\n\t\t<NcButton\n\t\t\tv-for=\"sticker in stickers\"\n\t\t\t:key=\"sticker\"\n\t\t\t:aria-label=\"sticker\"\n\t\t\t:pressed=\"context.sticker.value === sticker\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\tclass=\"sticker-panel__emoji\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"context.sticker.value = sticker\">\n\t\t\t{{ sticker }}\n\t\t</NcButton>\n\t\t<NcEmojiPicker @select=\"context.sticker.value = $event\">\n\t\t\t<NcButton data-test=\"emoji-picker\" variant=\"tertiary\">\n\t\t\t\t{{ moreLabel }}\n\t\t\t</NcButton>\n\t\t</NcEmojiPicker>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.sticker-panel {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex-wrap: wrap;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\n\t// The emoji is the button's label, so it inherits the editor's small\n\t// chrome font and leaves the target too short to hit. Size the glyph\n\t// to fill the pointer target instead.\n\t:deep(.sticker-panel__emoji) {\n\t\tmin-height: var(--default-clickable-area, 44px);\n\t\tfont-size: 22px;\n\t\tline-height: 1;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport GlassSurface from './base/GlassSurface.vue'\nimport AdjustPanel from './panels/AdjustPanel.vue'\nimport AnnotatePanel from './panels/AnnotatePanel.vue'\nimport CropPanel from './panels/CropPanel.vue'\nimport FilterStrip from './panels/FilterStrip.vue'\nimport RedactPanel from './panels/RedactPanel.vue'\nimport SelectPanel from './panels/SelectPanel.vue'\nimport StickerPanel from './panels/StickerPanel.vue'\nimport { useEditorContext } from '../editor/context.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n\t/** Orientation-baked source canvas, for the filter previews */\n\toriented?: HTMLCanvasElement | null\n}>()\n\nconst context = useEditorContext()\n</script>\n\n<template>\n\t<!-- Filter mode gets a vertical preview strip, everything else the\n\t\tbottom control card; each mode's controls live in its own panel -->\n\t<FilterStrip\n\t\tv-if=\"context.activeMode.value === 'filter'\"\n\t\t:loaded=\"loaded\"\n\t\t:oriented=\"oriented\" />\n\n\t<GlassSurface v-else variant=\"card\" class=\"editor-card\">\n\t\t<CropPanel v-if=\"context.activeMode.value === 'crop'\" :loaded=\"loaded\" />\n\t\t<AdjustPanel v-else-if=\"context.activeMode.value === 'finetune'\" :loaded=\"loaded\" />\n\t\t<AnnotatePanel v-else-if=\"context.activeMode.value === 'annotate'\" :loaded=\"loaded\" />\n\t\t<SelectPanel v-else-if=\"context.activeMode.value === 'select'\" :loaded=\"loaded\" />\n\t\t<StickerPanel v-else-if=\"context.activeMode.value === 'sticker'\" :loaded=\"loaded\" />\n\t\t<RedactPanel v-else-if=\"context.activeMode.value === 'redact'\" :loaded=\"loaded\" />\n\t</GlassSurface>\n</template>\n\n<style scoped lang=\"scss\">\n.editor-card {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\tmin-width: min(420px, 92cqw);\n\tmax-width: min(680px, 94cqw);\n\tpadding: calc(var(--default-grid-baseline) * 3) calc(var(--default-grid-baseline) * 5);\n\n\t@container editor (max-width: 600px) {\n\t\tmin-width: 0;\n\t\twidth: 100%;\n\t\tmax-width: none;\n\t\tpadding-inline: calc(var(--default-grid-baseline) * 3);\n\t}\n}\n</style>\n","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon blur-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M14,8.5A1.5,1.5 0 0,0 12.5,10A1.5,1.5 0 0,0 14,11.5A1.5,1.5 0 0,0 15.5,10A1.5,1.5 0 0,0 14,8.5M14,12.5A1.5,1.5 0 0,0 12.5,14A1.5,1.5 0 0,0 14,15.5A1.5,1.5 0 0,0 15.5,14A1.5,1.5 0 0,0 14,12.5M10,17A1,1 0 0,0 9,18A1,1 0 0,0 10,19A1,1 0 0,0 11,18A1,1 0 0,0 10,17M10,8.5A1.5,1.5 0 0,0 8.5,10A1.5,1.5 0 0,0 10,11.5A1.5,1.5 0 0,0 11.5,10A1.5,1.5 0 0,0 10,8.5M14,20.5A0.5,0.5 0 0,0 13.5,21A0.5,0.5 0 0,0 14,21.5A0.5,0.5 0 0,0 14.5,21A0.5,0.5 0 0,0 14,20.5M14,17A1,1 0 0,0 13,18A1,1 0 0,0 14,19A1,1 0 0,0 15,18A1,1 0 0,0 14,17M21,13.5A0.5,0.5 0 0,0 20.5,14A0.5,0.5 0 0,0 21,14.5A0.5,0.5 0 0,0 21.5,14A0.5,0.5 0 0,0 21,13.5M18,5A1,1 0 0,0 17,6A1,1 0 0,0 18,7A1,1 0 0,0 19,6A1,1 0 0,0 18,5M18,9A1,1 0 0,0 17,10A1,1 0 0,0 18,11A1,1 0 0,0 19,10A1,1 0 0,0 18,9M18,17A1,1 0 0,0 17,18A1,1 0 0,0 18,19A1,1 0 0,0 19,18A1,1 0 0,0 18,17M18,13A1,1 0 0,0 17,14A1,1 0 0,0 18,15A1,1 0 0,0 19,14A1,1 0 0,0 18,13M10,12.5A1.5,1.5 0 0,0 8.5,14A1.5,1.5 0 0,0 10,15.5A1.5,1.5 0 0,0 11.5,14A1.5,1.5 0 0,0 10,12.5M10,7A1,1 0 0,0 11,6A1,1 0 0,0 10,5A1,1 0 0,0 9,6A1,1 0 0,0 10,7M10,3.5A0.5,0.5 0 0,0 10.5,3A0.5,0.5 0 0,0 10,2.5A0.5,0.5 0 0,0 9.5,3A0.5,0.5 0 0,0 10,3.5M10,20.5A0.5,0.5 0 0,0 9.5,21A0.5,0.5 0 0,0 10,21.5A0.5,0.5 0 0,0 10.5,21A0.5,0.5 0 0,0 10,20.5M3,13.5A0.5,0.5 0 0,0 2.5,14A0.5,0.5 0 0,0 3,14.5A0.5,0.5 0 0,0 3.5,14A0.5,0.5 0 0,0 3,13.5M14,3.5A0.5,0.5 0 0,0 14.5,3A0.5,0.5 0 0,0 14,2.5A0.5,0.5 0 0,0 13.5,3A0.5,0.5 0 0,0 14,3.5M14,7A1,1 0 0,0 15,6A1,1 0 0,0 14,5A1,1 0 0,0 13,6A1,1 0 0,0 14,7M21,10.5A0.5,0.5 0 0,0 21.5,10A0.5,0.5 0 0,0 21,9.5A0.5,0.5 0 0,0 20.5,10A0.5,0.5 0 0,0 21,10.5M6,5A1,1 0 0,0 5,6A1,1 0 0,0 6,7A1,1 0 0,0 7,6A1,1 0 0,0 6,5M3,9.5A0.5,0.5 0 0,0 2.5,10A0.5,0.5 0 0,0 3,10.5A0.5,0.5 0 0,0 3.5,10A0.5,0.5 0 0,0 3,9.5M6,9A1,1 0 0,0 5,10A1,1 0 0,0 6,11A1,1 0 0,0 7,10A1,1 0 0,0 6,9M6,17A1,1 0 0,0 5,18A1,1 0 0,0 6,19A1,1 0 0,0 7,18A1,1 0 0,0 6,17M6,13A1,1 0 0,0 5,14A1,1 0 0,0 6,15A1,1 0 0,0 7,14A1,1 0 0,0 6,13Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"BlurIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon crop-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M7,17V1H5V5H1V7H5V17A2,2 0 0,0 7,19H17V23H19V19H23V17M17,15H19V7C19,5.89 18.1,5 17,5H9V7H17V15Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CropIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon cursor-default-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M10.07,14.27C10.57,14.03 11.16,14.25 11.4,14.75L13.7,19.74L15.5,18.89L13.19,13.91C12.95,13.41 13.17,12.81 13.67,12.58L13.95,12.5L16.25,12.05L8,5.12V15.9L9.82,14.43L10.07,14.27M13.64,21.97C13.14,22.21 12.54,22 12.31,21.5L10.13,16.76L7.62,18.78C7.45,18.92 7.24,19 7,19A1,1 0 0,1 6,18V3A1,1 0 0,1 7,2C7.24,2 7.47,2.09 7.64,2.23L7.65,2.22L19.14,11.86C19.57,12.22 19.62,12.85 19.27,13.27C19.12,13.45 18.91,13.57 18.7,13.61L15.54,14.23L17.74,18.96C18,19.46 17.76,20.05 17.26,20.28L13.64,21.97Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CursorDefaultOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon palette-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2C17.5,2 22,6 22,11A6,6 0 0,1 16,17H14.2C13.9,17 13.7,17.2 13.7,17.5C13.7,17.6 13.8,17.7 13.8,17.8C14.2,18.3 14.4,18.9 14.4,19.5C14.5,20.9 13.4,22 12,22M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C12.3,20 12.5,19.8 12.5,19.5C12.5,19.3 12.4,19.2 12.4,19.1C12,18.6 11.8,18.1 11.8,17.5C11.8,16.1 12.9,15 14.3,15H16A4,4 0 0,0 20,11C20,7.1 16.4,4 12,4M6.5,10C7.3,10 8,10.7 8,11.5C8,12.3 7.3,13 6.5,13C5.7,13 5,12.3 5,11.5C5,10.7 5.7,10 6.5,10M9.5,6C10.3,6 11,6.7 11,7.5C11,8.3 10.3,9 9.5,9C8.7,9 8,8.3 8,7.5C8,6.7 8.7,6 9.5,6M14.5,6C15.3,6 16,6.7 16,7.5C16,8.3 15.3,9 14.5,9C13.7,9 13,8.3 13,7.5C13,6.7 13.7,6 14.5,6M17.5,10C18.3,10 19,10.7 19,11.5C19,12.3 18.3,13 17.5,13C16.7,13 16,12.3 16,11.5C16,10.7 16.7,10 17.5,10Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"PaletteOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon sticker-emoji-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M5.5,2C3.56,2 2,3.56 2,5.5V18.5C2,20.44 3.56,22 5.5,22H16L22,16V5.5C22,3.56 20.44,2 18.5,2H5.5M5.75,4H18.25A1.75,1.75 0 0,1 20,5.75V15H18.5C16.56,15 15,16.56 15,18.5V20H5.75A1.75,1.75 0 0,1 4,18.25V5.75A1.75,1.75 0 0,1 5.75,4M14.44,6.77C14.28,6.77 14.12,6.79 13.97,6.83C13.03,7.09 12.5,8.05 12.74,9C12.79,9.15 12.86,9.3 12.95,9.44L16.18,8.56C16.18,8.39 16.16,8.22 16.12,8.05C15.91,7.3 15.22,6.77 14.44,6.77M8.17,8.5C8,8.5 7.85,8.5 7.7,8.55C6.77,8.81 6.22,9.77 6.47,10.7C6.5,10.86 6.59,11 6.68,11.16L9.91,10.28C9.91,10.11 9.89,9.94 9.85,9.78C9.64,9 8.95,8.5 8.17,8.5M16.72,11.26L7.59,13.77C8.91,15.3 11,15.94 12.95,15.41C14.9,14.87 16.36,13.25 16.72,11.26Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"StickerEmojiIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon tune-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M3,17V19H9V17H3M3,5V7H13V5H3M13,21V19H21V17H13V15H11V21H13M7,9V11H3V13H7V15H9V9H7M21,13V11H11V13H21M15,9H17V7H21V5H17V3H15V9Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"TuneIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport type { EditorMode } from '../editor/context.ts'\n\nimport Blur from 'vue-material-design-icons/Blur.vue'\nimport Crop from 'vue-material-design-icons/Crop.vue'\nimport CursorDefaultOutline from 'vue-material-design-icons/CursorDefaultOutline.vue'\nimport PaletteOutline from 'vue-material-design-icons/PaletteOutline.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\nimport StickerEmoji from 'vue-material-design-icons/StickerEmoji.vue'\nimport Tune from 'vue-material-design-icons/Tune.vue'\nimport IconTab from './base/IconTab.vue'\nimport { useEditorContext } from '../editor/context.ts'\nimport { t } from '../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst context = useEditorContext()\n\nconst modes: { id: EditorMode, label: string, icon: unknown }[] = [\n\t{ id: 'select', label: t('Select'), icon: CursorDefaultOutline },\n\t{ id: 'crop', label: t('Crop'), icon: Crop },\n\t{ id: 'finetune', label: t('Adjust'), icon: Tune },\n\t{ id: 'filter', label: t('Filter'), icon: PaletteOutline },\n\t{ id: 'annotate', label: t('Annotate'), icon: Pencil },\n\t{ id: 'sticker', label: t('Sticker'), icon: StickerEmoji },\n\t{ id: 'redact', label: t('Redact'), icon: Blur },\n]\n</script>\n\n<template>\n\t<nav class=\"editor-sidebar\">\n\t\t<IconTab\n\t\t\tv-for=\"mode in modes\"\n\t\t\t:key=\"mode.id\"\n\t\t\t:label=\"mode.label\"\n\t\t\t:active=\"context.activeMode.value === mode.id\"\n\t\t\t:disabled=\"!loaded\"\n\t\t\t@click=\"context.setMode(mode.id)\">\n\t\t\t<component :is=\"mode.icon\" :size=\"20\" />\n\t\t</IconTab>\n\t</nav>\n</template>\n\n<style scoped lang=\"scss\">\n// Vertical labeled tool rail: icon above label, the active tab softly\n// tinted by the image's ambient color (see IconTab)\n.editor-sidebar {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline) * 2);\n\tpadding: var(--default-grid-baseline);\n}\n</style>\n","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon check-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CheckIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon close-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CloseIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon history-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M13.5,8H12V13L16.28,15.54L17,14.33L13.5,12.25V8M13,3A9,9 0 0,0 4,12H1L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"HistoryIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon magnify-minus-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M15.5,14H14.71L14.43,13.73C15.41,12.59 16,11.11 16,9.5A6.5,6.5 0 0,0 9.5,3A6.5,6.5 0 0,0 3,9.5A6.5,6.5 0 0,0 9.5,16C11.11,16 12.59,15.41 13.73,14.43L14,14.71V15.5L19,20.5L20.5,19L15.5,14M9.5,14C7,14 5,12 5,9.5C5,7 7,5 9.5,5C12,5 14,7 14,9.5C14,12 12,14 9.5,14M7,9H12V10H7V9Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"MagnifyMinusOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon magnify-plus-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M15.5,14L20.5,19L19,20.5L14,15.5V14.71L13.73,14.43C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.43,13.73L14.71,14H15.5M9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14M12,10H10V12H9V10H7V9H9V7H10V9H12V10Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"MagnifyPlusOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon redo-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M18.4,10.6C16.55,9 14.15,8 11.5,8C6.85,8 2.92,11.03 1.54,15.22L3.9,16C4.95,12.81 7.95,10.5 11.5,10.5C13.45,10.5 15.23,11.22 16.62,12.38L13,16H22V7L18.4,10.6Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"RedoIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon restore-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M13,3A9,9 0 0,0 4,12H1L4.89,15.89L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"RestoreIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon undo-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12.5,8C9.85,8 7.45,9 5.6,10.6L2,7V16H11L7.38,12.38C8.77,11.22 10.54,10.5 12.5,10.5C16.04,10.5 19.05,12.81 20.1,16L22.47,15.22C21.08,11.03 17.15,8 12.5,8Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"UndoIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport { showConfirmation } from '@nextcloud/dialogs'\nimport { computed } from 'vue'\nimport NcActionButton from '@nextcloud/vue/components/NcActionButton'\nimport NcActions from '@nextcloud/vue/components/NcActions'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport HistoryIcon from 'vue-material-design-icons/History.vue'\nimport MagnifyMinusOutline from 'vue-material-design-icons/MagnifyMinusOutline.vue'\nimport MagnifyPlusOutline from 'vue-material-design-icons/MagnifyPlusOutline.vue'\nimport Redo from 'vue-material-design-icons/Redo.vue'\nimport Restore from 'vue-material-design-icons/Restore.vue'\nimport Undo from 'vue-material-design-icons/Undo.vue'\nimport { useEditorCommands } from '../editor/commands.ts'\nimport { useEditorContext } from '../editor/context.ts'\nimport { MAX_ZOOM, MIN_ZOOM } from '../editor/view.ts'\nimport { t } from '../utils/l10n.ts'\n\ndefineProps<{\n\t/** Whether an image is loaded and the tools are usable */\n\tloaded: boolean\n}>()\n\nconst emit = defineEmits<{\n\tsave: []\n\tcancel: []\n}>()\n\nconst context = useEditorContext()\nconst commands = useEditorCommands()\n\nconst labels = {\n\tundo: t('Undo'),\n\tredo: t('Redo'),\n\trevert: t('Revert all changes'),\n\trevertText: t('All edits will be discarded. This cannot be undone by closing the dialog.'),\n\tzoomIn: t('Zoom in'),\n\tzoomOut: t('Zoom out'),\n\tresetZoom: t('Reset zoom'),\n\tsave: t('Save'),\n\tcancel: t('Cancel'),\n\thistory: t('Edit history'),\n\tstep: t('Edit'),\n}\n\n// Newest first, which is the order the user thinks in when going back\nconst historySteps = computed(() => context.historyEntries.value\n\t.map((entry, index) => ({\n\t\tindex,\n\t\tlabel: entry.label ?? labels.step,\n\t\tactive: index === context.historyIndex.value,\n\t}))\n\t.reverse())\n\n/**\n * Step the view magnification, snapping back to the fitted view.\n *\n * @param direction 1 to zoom in, -1 to zoom out\n */\nfunction stepZoom(direction: 1 | -1) {\n\tconst factor = direction === 1 ? 1.5 : 1 / 1.5\n\tcontext.setViewZoom(context.viewZoom.value * factor)\n}\n\n/**\n * Reset the view to the fitted state.\n */\nfunction resetZoom() {\n\tcontext.setViewZoom(MIN_ZOOM)\n}\n\n/**\n * Confirm before discarding every edit. The shared dialog keeps this\n * consistent with the destructive confirmations the rest of Nextcloud\n * puts in front of the user.\n */\nasync function onRevert() {\n\tif (await showConfirmation({\n\t\tname: labels.revert,\n\t\ttext: labels.revertText,\n\t\tlabelConfirm: labels.revert,\n\t\tlabelReject: labels.cancel,\n\t\tseverity: 'warning',\n\t})) {\n\t\tcommands.revert()\n\t}\n}\n</script>\n\n<template>\n\t<div class=\"editor-topbar\">\n\t\t<span class=\"editor-topbar__spacer\" />\n\n\t\t<div class=\"editor-topbar__history\">\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"revert\"\n\t\t\t\t:aria-label=\"labels.revert\"\n\t\t\t\t:title=\"labels.revert\"\n\t\t\t\t:disabled=\"!loaded || !context.canUndo.value\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"onRevert\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Restore :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\n\t\t\t<span class=\"editor-topbar__separator\" />\n\n\t\t\t<NcButton\n\t\t\t\t:aria-label=\"labels.undo\"\n\t\t\t\t:title=\"labels.undo\"\n\t\t\t\t:disabled=\"!loaded || !context.canUndo.value\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"context.undo()\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Undo :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\t:aria-label=\"labels.redo\"\n\t\t\t\t:title=\"labels.redo\"\n\t\t\t\t:disabled=\"!loaded || !context.canRedo.value\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"context.redo()\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Redo :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\n\t\t\t<NcActions\n\t\t\t\t:aria-label=\"labels.history\"\n\t\t\t\t:title=\"labels.history\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\tdata-test=\"history\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<HistoryIcon :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t<NcActionButton\n\t\t\t\t\tv-for=\"step in historySteps\"\n\t\t\t\t\t:key=\"step.index\"\n\t\t\t\t\t:data-test=\"`history-step-${step.index}`\"\n\t\t\t\t\t:aria-current=\"step.active\"\n\t\t\t\t\t@click=\"context.jumpTo(step.index)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Check v-if=\"step.active\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ step.label }}\n\t\t\t\t</NcActionButton>\n\t\t\t</NcActions>\n\n\t\t\t<span class=\"editor-topbar__separator\" />\n\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"zoom-out\"\n\t\t\t\t:aria-label=\"labels.zoomOut\"\n\t\t\t\t:title=\"labels.zoomOut\"\n\t\t\t\t:disabled=\"!loaded || context.viewZoom.value <= MIN_ZOOM\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"stepZoom(-1)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<MagnifyMinusOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"editor-topbar__zoom\"\n\t\t\t\tdata-test=\"zoom-reset\"\n\t\t\t\t:aria-label=\"labels.resetZoom\"\n\t\t\t\t:title=\"labels.resetZoom\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\t@click=\"resetZoom\">\n\t\t\t\t{{ Math.round(context.viewZoom.value * 100) }}%\n\t\t\t</button>\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"zoom-in\"\n\t\t\t\t:aria-label=\"labels.zoomIn\"\n\t\t\t\t:title=\"labels.zoomIn\"\n\t\t\t\t:disabled=\"!loaded || context.viewZoom.value >= MAX_ZOOM\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"stepZoom(1)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<MagnifyPlusOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<div class=\"editor-topbar__actions\">\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"cancel\"\n\t\t\t\tclass=\"editor-topbar__cancel-text\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"emit('cancel')\">\n\t\t\t\t{{ labels.cancel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"cancel-icon\"\n\t\t\t\tclass=\"editor-topbar__cancel-icon\"\n\t\t\t\t:aria-label=\"labels.cancel\"\n\t\t\t\t:title=\"labels.cancel\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t@click=\"emit('cancel')\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Close :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tdata-test=\"save\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!loaded\"\n\t\t\t\t@click=\"emit('save')\">\n\t\t\t\t{{ labels.save }}\n\t\t\t</NcButton>\n\t\t</div>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.editor-topbar {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: calc(var(--default-grid-baseline) * 2) calc(var(--default-grid-baseline) * 6);\n\n\t&__history {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 2px;\n\t\tpadding: 2px;\n\t\tborder-radius: var(--border-radius-pill, 100px);\n\t\tbackground: var(--editor-glass, rgba(22, 22, 26, 0.6));\n\t\tbackdrop-filter: blur(24px) saturate(1.4);\n\t\tborder: 1px solid rgba(255, 255, 255, 0.09);\n\t}\n\n\t&__separator {\n\t\twidth: 1px;\n\t\theight: 20px;\n\t\tbackground-color: var(--color-border);\n\t}\n\n\t&__zoom {\n\t\tmin-width: 48px;\n\t\tborder: none;\n\t\tbackground: transparent;\n\t\tcolor: var(--color-main-text);\n\t\tfont-size: 12px;\n\t\tfont-variant-numeric: tabular-nums;\n\t\topacity: 0.8;\n\t\tcursor: pointer;\n\t\tpadding: 0 4px;\n\n\t\t&:hover:not(:disabled) {\n\t\t\topacity: 1;\n\t\t}\n\n\t\t&:focus-visible {\n\t\t\toutline: 2px solid var(--color-primary-element);\n\t\t\toutline-offset: 2px;\n\t\t}\n\n\t\t&:disabled {\n\t\t\tcursor: default;\n\t\t\topacity: 0.4;\n\t\t}\n\t}\n\n\t// Both sides flex equally so the history pill stays centered\n\t&__spacer,\n\t&__actions {\n\t\tflex: 1;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: var(--default-grid-baseline);\n\t}\n\n\t&__actions {\n\t\tjustify-content: flex-end;\n\t}\n\n\t// Text cancel on wide layouts, icon-only on narrow ones\n\t&__cancel-icon {\n\t\tdisplay: none !important;\n\t}\n\n\t@container editor (max-width: 600px) {\n\t\tpadding-inline: calc(var(--default-grid-baseline) * 2);\n\n\t\t&__cancel-text {\n\t\t\tdisplay: none !important;\n\t\t}\n\n\t\t&__cancel-icon {\n\t\t\tdisplay: inline-flex !important;\n\t\t}\n\n\t\t&__zoom {\n\t\t\tmin-width: 40px;\n\t\t}\n\t}\n}\n</style>\n","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon content-copy-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"ContentCopyIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon delete-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"DeleteIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport ContentCopy from 'vue-material-design-icons/ContentCopy.vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport GlassSurface from './base/GlassSurface.vue'\nimport { t } from '../utils/l10n.ts'\n\ndefineProps<{\n\t/** Stage-space bounds of the selected annotation */\n\tbox: { x: number, y: number, width: number, height: number }\n}>()\n\nconst emit = defineEmits<{\n\tduplicate: []\n\tdelete: []\n}>()\n\nconst duplicateLabel = t('Duplicate')\nconst deleteLabel = t('Delete')\n</script>\n\n<template>\n\t<GlassSurface\n\t\tvariant=\"pill\"\n\t\tclass=\"selection-toolbar\"\n\t\tdata-test=\"selection-toolbar\"\n\t\t:style=\"{\n\t\t\tinsetInlineStart: `${box.x + box.width / 2}px`,\n\t\t\t// Above the selection as designed, clearing the rotate handle;\n\t\t\t// below only when the top edge would clip it\n\t\t\tinsetBlockStart: box.y - 76 >= 4\n\t\t\t\t? `${box.y - 76}px`\n\t\t\t\t: `${box.y + box.height + 12}px`,\n\t\t}\">\n\t\t<NcButton\n\t\t\tdata-test=\"duplicate\"\n\t\t\t:aria-label=\"duplicateLabel\"\n\t\t\t:title=\"duplicateLabel\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"emit('duplicate')\">\n\t\t\t<template #icon>\n\t\t\t\t<ContentCopy :size=\"18\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tdata-test=\"delete\"\n\t\t\t:aria-label=\"deleteLabel\"\n\t\t\t:title=\"deleteLabel\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"emit('delete')\">\n\t\t\t<template #icon>\n\t\t\t\t<Delete :size=\"18\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t</GlassSurface>\n</template>\n\n<style scoped>\n.selection-toolbar {\n\tposition: absolute;\n\tdisplay: flex;\n\tgap: 2px;\n\tpadding: 2px;\n\ttransform: translateX(-50%);\n\tz-index: 1;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport { onMounted, ref, useTemplateRef } from 'vue'\nimport { t } from '../utils/l10n.ts'\n\nconst props = defineProps<{\n\t/** Horizontal screen position inside the editor, in pixels */\n\tx: number\n\t/** Vertical screen position inside the editor, in pixels */\n\ty: number\n\t/** Screen font size in pixels */\n\tfontSize: number\n\t/** Text color */\n\tcolor: string\n\t/** Text to edit, empty when creating */\n\tinitial: string\n}>()\n\nconst emit = defineEmits<{\n\tconfirm: [text: string]\n\tcancel: []\n}>()\n\nconst inputLabel = t('Annotation text')\n\nconst value = ref(props.initial)\nconst input = useTemplateRef<HTMLTextAreaElement>('input')\n\n/**\n * Grow the field with its content so the box never crops the text.\n */\nfunction autosize() {\n\tconst element = input.value\n\tif (element === null) {\n\t\treturn\n\t}\n\telement.style.width = '0'\n\telement.style.height = '0'\n\telement.style.width = `${Math.max(element.scrollWidth + 4, props.fontSize * 2)}px`\n\telement.style.height = `${Math.max(element.scrollHeight, props.fontSize * 1.2)}px`\n}\n\nonMounted(() => {\n\tautosize()\n\tinput.value!.focus()\n\tinput.value!.select()\n})\n\n/**\n * Confirm unless the enter stroke was meant as a line break.\n *\n * @param event the keyboard event\n */\nfunction onEnter(event: KeyboardEvent) {\n\tif (!event.shiftKey) {\n\t\tevent.preventDefault()\n\t\temit('confirm', value.value)\n\t}\n}\n</script>\n\n<template>\n\t<textarea\n\t\tref=\"input\"\n\t\tv-model=\"value\"\n\t\tclass=\"text-overlay\"\n\t\t:aria-label=\"inputLabel\"\n\t\tdata-test=\"text-overlay\"\n\t\t:style=\"{\n\t\t\tinsetInlineStart: `${x}px`,\n\t\t\tinsetBlockStart: `${y}px`,\n\t\t\tfontSize: `${fontSize}px`,\n\t\t\tcolor: color,\n\t\t}\"\n\t\trows=\"1\"\n\t\t@input=\"autosize\"\n\t\t@keydown.enter=\"onEnter\"\n\t\t@keydown.esc.stop=\"emit('cancel')\"\n\t\t@blur=\"emit('confirm', value)\" />\n</template>\n\n<style scoped>\n.text-overlay {\n\tposition: absolute;\n\t/* Kept in sync with the Konva text nodes for WYSIWYG editing */\n\tfont-family: Helvetica, Arial, sans-serif;\n\tline-height: 1;\n\tpadding: 0;\n\tmargin: 0;\n\tborder: none;\n\tborder-radius: 2px;\n\tbackground: transparent;\n\toutline: 1.5px solid var(--color-primary-element, #5b5cf0);\n\toutline-offset: 4px;\n\tbox-shadow: 0 0 0 4px rgba(0, 0, 0, 0.15);\n\tcaret-color: var(--color-primary-element, #5b5cf0);\n\tresize: none;\n\toverflow: hidden;\n\twhite-space: pre;\n\tz-index: 1;\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/**\n * The Nextcloud primary color of the active theme, for canvas chrome\n * that cannot use CSS variables directly.\n */\nexport function primaryColor(): string {\n\tconst value = getComputedStyle(document.body).getPropertyValue('--color-primary-element').trim()\n\treturn value !== '' ? value : '#0082c9'\n}\n\n/**\n * Dominant color of an image as an \"r, g, b\" triplet for CSS rgba()\n * composition. Averages a tiny downsample, weighting colorful pixels\n * so the tint follows the subject rather than gray backgrounds.\n *\n * @param canvas the image to sample\n */\nexport function ambientColor(canvas: HTMLCanvasElement | HTMLImageElement): string {\n\tconst sample = document.createElement('canvas')\n\tsample.width = 8\n\tsample.height = 8\n\tconst context = sample.getContext('2d')\n\tif (context === null) {\n\t\treturn '88, 86, 112'\n\t}\n\tcontext.drawImage(canvas, 0, 0, 8, 8)\n\n\t// Reading back the pixels of an image fetched without CORS throws:\n\t// the chrome tint is decoration, so it takes the neutral one rather\n\t// than bringing the editor down with it\n\tlet data: Uint8ClampedArray\n\ttry {\n\t\tdata = context.getImageData(0, 0, 8, 8).data\n\t} catch {\n\t\treturn '88, 86, 112'\n\t}\n\tlet r = 0\n\tlet g = 0\n\tlet b = 0\n\tlet total = 0\n\tfor (let i = 0; i < data.length; i += 4) {\n\t\tconst saturation = Math.max(data[i]!, data[i + 1]!, data[i + 2]!)\n\t\t\t- Math.min(data[i]!, data[i + 1]!, data[i + 2]!)\n\t\tconst weight = saturation + 8\n\t\tr += data[i]! * weight\n\t\tg += data[i + 1]! * weight\n\t\tb += data[i + 2]! * weight\n\t\ttotal += weight\n\t}\n\treturn `${Math.round(r / total)}, ${Math.round(g / total)}, ${Math.round(b / total)}`\n}\n\n/**\n * Tiny blurred copy of the image as a data URL, used as the ambient\n * backdrop behind the editor card.\n *\n * @param canvas the image to sample\n */\nexport function ambientBackdrop(canvas: HTMLCanvasElement | HTMLImageElement): string {\n\tconst sample = document.createElement('canvas')\n\tconst width = canvas instanceof HTMLImageElement ? canvas.naturalWidth : canvas.width\n\tconst height = canvas instanceof HTMLImageElement ? canvas.naturalHeight : canvas.height\n\t// An SVG without intrinsic size decodes with zero dimensions\n\tif (width === 0 || height === 0) {\n\t\treturn ''\n\t}\n\tsample.width = 24\n\tsample.height = Math.max(1, Math.round((24 * height) / width))\n\tconst context = sample.getContext('2d')\n\tif (context === null) {\n\t\treturn ''\n\t}\n\tcontext.drawImage(canvas, 0, 0, sample.width, sample.height)\n\ttry {\n\t\treturn sample.toDataURL()\n\t} catch {\n\t\t// Same as above: a tainted canvas cannot be exported, and the\n\t\t// wallpaper is not worth an exception\n\t\treturn ''\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Ref, ShallowRef } from 'vue'\n\nimport { ref, watch } from 'vue'\nimport { ambientBackdrop, ambientColor } from '../utils/theme.ts'\n\nexport interface Ambient {\n\t/** Dominant image color as an \"r, g, b\" triplet for CSS rgba() */\n\tambient: Ref<string>\n\t/** Tiny blurred copy of the image as a data URL, or empty */\n\tbackdrop: Ref<string>\n}\n\n/**\n * Track the ambient chrome tint derived from the original image.\n * Deliberately fed by the untouched source: rotating or flipping the\n * edit must not make the wallpaper jump around.\n *\n * @param source the decoded source image\n */\nexport function useAmbient(source: ShallowRef<HTMLImageElement | null>): Ambient {\n\tconst ambient = ref('88, 86, 112')\n\tconst backdrop = ref('')\n\n\twatch(source, (image) => {\n\t\tif (image !== null) {\n\t\t\tambient.value = ambientColor(image)\n\t\t\tbackdrop.value = ambientBackdrop(image)\n\t\t}\n\t})\n\n\treturn { ambient, backdrop }\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Ref } from 'vue'\nimport type { EditorContext } from '../editor/context.ts'\n\nimport { ref, watch } from 'vue'\nimport { t } from '../utils/l10n.ts'\n\n/**\n * Screen-reader announcements for state changes that have no visible\n * text of their own: mode switches, annotations appearing or\n * disappearing, and preset changes. The returned message feeds an\n * aria-live region.\n *\n * @param context the editor context\n */\nexport function useAnnouncements(context: EditorContext): Ref<string> {\n\tconst message = ref('')\n\n\tconst modeLabels: Record<string, string> = {\n\t\tselect: t('Select'),\n\t\tcrop: t('Crop'),\n\t\tfinetune: t('Adjust'),\n\t\tfilter: t('Filter'),\n\t\tannotate: t('Annotate'),\n\t\tsticker: t('Sticker'),\n\t\tredact: t('Redact'),\n\t}\n\n\twatch(context.activeMode, (mode) => {\n\t\tmessage.value = t('{mode} mode', { mode: modeLabels[mode] ?? mode })\n\t})\n\n\tlet annotationCount = 0\n\twatch(context.state, (state) => {\n\t\tif (state.annotations.length > annotationCount) {\n\t\t\tmessage.value = t('Annotation added')\n\t\t} else if (state.annotations.length < annotationCount) {\n\t\t\tmessage.value = t('Annotation removed')\n\t\t}\n\t\tannotationCount = state.annotations.length\n\t})\n\n\twatch(() => context.state.value.preset, (preset) => {\n\t\tmessage.value = preset === 'none'\n\t\t\t? t('Filter removed')\n\t\t\t: t('Filter applied')\n\t})\n\n\treturn message\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/** Controls that consume typing, so editor shortcuts must stay out */\nconst TEXT_ENTRY = 'input, textarea, select, [contenteditable]'\n\n/** Controls the space bar activates, so it cannot double as a modifier */\nconst ACTIVATABLE = 'button, [role=\"button\"], a[href], summary'\n\n/**\n * Whether the event target is a control that owns text input.\n *\n * @param target the event target\n */\nexport function ownsTextEntry(target: EventTarget | null): boolean {\n\treturn target instanceof HTMLElement && target.closest(TEXT_ENTRY) !== null\n}\n\n/**\n * Whether the event target is a control the space bar belongs to,\n * either because it takes text or because space activates it.\n *\n * @param target the event target\n */\nexport function ownsSpaceKey(target: EventTarget | null): boolean {\n\treturn target instanceof HTMLElement\n\t\t&& target.closest(`${TEXT_ENTRY}, ${ACTIVATABLE}`) !== null\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { EditorContext } from '../editor/context.ts'\n\nimport { onBeforeUnmount, onMounted } from 'vue'\nimport { translateAnnotation } from '../editor/state.ts'\nimport { ownsTextEntry } from '../utils/dom.ts'\nimport { t } from '../utils/l10n.ts'\n\nexport interface ShortcutDeps {\n\tcontext: EditorContext\n\t/** Whether the text overlay currently captures the keyboard */\n\tisTextEditing(): boolean\n\t/** Delete the selected annotation */\n\tonDelete(): void\n\t/** Escape pressed with nothing else to dismiss */\n\tonEscape(): void\n}\n\nconst NUDGE_KEYS: Record<string, [number, number]> = {\n\tArrowLeft: [-1, 0],\n\tArrowRight: [1, 0],\n\tArrowUp: [0, -1],\n\tArrowDown: [0, 1],\n}\n\n/**\n * Global editor shortcuts: undo/redo, delete, escape and arrow-key\n * nudging of the selection. Nudges preview live and commit once on key\n * release, so holding a key stays a single undo step.\n *\n * @param deps context and editor callbacks\n */\nexport function useEditorShortcuts(deps: ShortcutDeps): void {\n\tconst { context } = deps\n\tlet nudging = false\n\n\t/**\n\t * Move the selected annotation with the arrow keys.\n\t *\n\t * @param event the keyboard event\n\t */\n\tfunction nudgeSelection(event: KeyboardEvent): void {\n\t\tconst id = context.selectedId.value\n\t\tconst direction = NUDGE_KEYS[event.key]\n\t\tif (id === null || direction === undefined) {\n\t\t\treturn\n\t\t}\n\t\tevent.preventDefault()\n\t\tconst step = event.shiftKey ? 10 : 1\n\t\tconst state = context.state.value\n\t\tnudging = true\n\t\tcontext.preview({\n\t\t\t...state,\n\t\t\tannotations: state.annotations.map((annotation) => annotation.id === id\n\t\t\t\t? translateAnnotation(annotation, direction[0] * step, direction[1] * step)\n\t\t\t\t: annotation),\n\t\t})\n\t}\n\n\t/**\n\t * Undo/redo, nudge, delete and escape handling.\n\t *\n\t * @param event the keyboard event\n\t */\n\tfunction onKeydown(event: KeyboardEvent): void {\n\t\tif (deps.isTextEditing() || ownsTextEntry(event.target)) {\n\t\t\treturn\n\t\t}\n\t\tconst meta = event.ctrlKey || event.metaKey\n\t\tif (meta && !event.shiftKey && event.key.toLowerCase() === 'z') {\n\t\t\tevent.preventDefault()\n\t\t\tcontext.undo()\n\t\t\treturn\n\t\t}\n\t\tif ((meta && event.shiftKey && event.key.toLowerCase() === 'z')\n\t\t\t|| (meta && event.key.toLowerCase() === 'y')) {\n\t\t\tevent.preventDefault()\n\t\t\tcontext.redo()\n\t\t\treturn\n\t\t}\n\t\tif (event.key === '+' || event.key === '=') {\n\t\t\tcontext.setViewZoom(context.viewZoom.value * 1.25)\n\t\t\treturn\n\t\t}\n\t\tif (event.key === '-') {\n\t\t\tcontext.setViewZoom(context.viewZoom.value / 1.25)\n\t\t\treturn\n\t\t}\n\t\tif (event.key in NUDGE_KEYS && context.selectedId.value !== null) {\n\t\t\tnudgeSelection(event)\n\t\t\treturn\n\t\t}\n\t\tif ((event.key === 'Delete' || event.key === 'Backspace') && context.selectedId.value !== null) {\n\t\t\tevent.preventDefault()\n\t\t\tdeps.onDelete()\n\t\t} else if (event.key === 'Escape') {\n\t\t\tdeps.onEscape()\n\t\t}\n\t}\n\n\t/**\n\t * Commit a finished nudge as a single undo step.\n\t *\n\t * @param event the keyboard event\n\t */\n\tfunction onKeyup(event: KeyboardEvent): void {\n\t\tif (ownsTextEntry(event.target)) {\n\t\t\treturn\n\t\t}\n\t\tif (nudging && event.key in NUDGE_KEYS) {\n\t\t\tnudging = false\n\t\t\tcontext.commit(context.state.value, t('Move or resize'))\n\t\t}\n\t}\n\n\tonMounted(() => {\n\t\twindow.addEventListener('keydown', onKeydown)\n\t\twindow.addEventListener('keyup', onKeyup)\n\t})\n\tonBeforeUnmount(() => {\n\t\twindow.removeEventListener('keydown', onKeydown)\n\t\twindow.removeEventListener('keyup', onKeyup)\n\t})\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { t } from './l10n.ts'\n\n/**\n * Whether a URL points at another origin, in which case the image has\n * to be fetched with CORS or it taints the canvas and exporting throws\n * a SecurityError.\n *\n * Only genuinely remote sources qualify. Marking a same-origin request\n * anonymous strips the session cookie from it, and Nextcloud hands out\n * absolute same-origin URLs as a matter of course: generateRemoteUrl()\n * returns one, and a WebDAV address without credentials is a 401.\n *\n * @param url the source URL, absolute or relative\n */\nfunction needsCors(url: string): boolean {\n\tlet target: URL\n\ttry {\n\t\ttarget = new URL(url, window.location.href)\n\t} catch {\n\t\treturn false\n\t}\n\treturn (target.protocol === 'http:' || target.protocol === 'https:')\n\t\t&& target.origin !== window.location.origin\n}\n\n/**\n * Load a decoded image element from a Blob, File or URL.\n *\n * @param source the image to load\n */\nexport async function loadImage(source: Blob | string): Promise<HTMLImageElement> {\n\tconst url = typeof source === 'string' ? source : URL.createObjectURL(source)\n\ttry {\n\t\treturn await new Promise((resolve, reject) => {\n\t\t\tconst image = new Image()\n\t\t\tif (needsCors(url)) {\n\t\t\t\timage.crossOrigin = 'anonymous'\n\t\t\t}\n\t\t\timage.onload = () => resolve(image)\n\t\t\timage.onerror = () => reject(new Error(t('Image could not be decoded')))\n\t\t\timage.src = url\n\t\t})\n\t} finally {\n\t\tif (typeof source !== 'string') {\n\t\t\tURL.revokeObjectURL(url)\n\t\t}\n\t}\n}\n\n/**\n * Promisified HTMLCanvasElement.toBlob.\n *\n * @param canvas the canvas to encode\n * @param type target MIME type\n * @param quality encoder quality between 0 and 1, only for lossy formats\n */\nexport async function canvasToBlob(canvas: HTMLCanvasElement, type = 'image/png', quality?: number): Promise<Blob> {\n\treturn new Promise((resolve, reject) => {\n\t\tcanvas.toBlob((blob) => {\n\t\t\tif (blob === null) {\n\t\t\t\treject(new Error(t('Canvas could not be encoded')))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresolve(blob)\n\t\t}, type, quality)\n\t})\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { EditorState } from '../editor/state.ts'\nimport type { ExportOptions, ExportResult } from '../types/export.ts'\n\nimport { renderToCanvas } from '../editor/render.ts'\nimport { isPristine } from '../editor/state.ts'\nimport { canvasToBlob } from '../utils/image.ts'\nimport { t } from '../utils/l10n.ts'\n\nexport interface ExportDeps {\n\t/** The orientation-baked source canvas */\n\toriented(): HTMLCanvasElement | null\n\tgetState(): EditorState\n\t/**\n\t * The source bytes, where the editor was handed bytes rather than a\n\t * URL. An untouched image is returned from here instead of being\n\t * rendered again.\n\t */\n\tsource(): Blob | null\n\t/** Format, quality and size bound the save button asks for */\n\tsaveOptions(): ExportOptions\n\tonSaved(result: ExportResult): void\n\tonError(error: Error): void\n}\n\nexport interface ExportImage {\n\t/**\n\t * Export the edited image.\n\t *\n\t * @param options target format, quality and size bound\n\t */\n\texportImage(options?: ExportOptions): Promise<ExportResult>\n\t/** Export and hand the result to the save callback */\n\tsave(): Promise<void>\n}\n\n/**\n * Exporting runs through the same scene renderer as the interactive\n * view, at natural resolution.\n *\n * @param deps image access and result callbacks\n */\nexport function useExportImage(deps: ExportDeps): ExportImage {\n\t/**\n\t * Render the state at natural resolution and encode it.\n\t *\n\t * @param options target format, quality and size bound\n\t */\n\tasync function exportImage(options: ExportOptions = {}): Promise<ExportResult> {\n\t\tconst oriented = deps.oriented()\n\t\tif (oriented === null) {\n\t\t\tthrow new Error('No image loaded')\n\t\t}\n\n\t\t// Nothing was edited and nothing was asked of the encoder, so the\n\t\t// source is already the answer. Re-encoding it would cost a\n\t\t// generation of quality and throw away the metadata, EXIF and\n\t\t// colour profile included, for no change at all.\n\t\tconst source = deps.source()\n\t\tif (source !== null\n\t\t\t&& source.type !== ''\n\t\t\t&& isPristine(deps.getState())\n\t\t\t&& options.maxSize === undefined\n\t\t\t&& (options.format === undefined || options.format === source.type)) {\n\t\t\treturn { blob: source, width: oriented.width, height: oriented.height, mimeType: source.type }\n\t\t}\n\n\t\tconst canvas = renderToCanvas(oriented, deps.getState(), options.maxSize)\n\t\tconst mimeType = options.format ?? 'image/png'\n\t\ttry {\n\t\t\tconst blob = await canvasToBlob(canvas, mimeType, options.quality)\n\t\t\treturn { blob, width: canvas.width, height: canvas.height, mimeType }\n\t\t} catch (error) {\n\t\t\t// A canvas holding pixels from an image fetched without CORS\n\t\t\t// cannot be read back at all. The encoder's SecurityError says\n\t\t\t// nothing about why, and the answer is in how the source was\n\t\t\t// served rather than anything the user did.\n\t\t\tif (error instanceof DOMException && error.name === 'SecurityError') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tt('The image cannot be exported because it was loaded without cross-origin access'),\n\t\t\t\t\t{ cause: error },\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Export and hand the result to the save callback.\n\t */\n\tasync function save(): Promise<void> {\n\t\ttry {\n\t\t\tdeps.onSaved(await exportImage(deps.saveOptions()))\n\t\t} catch (error) {\n\t\t\tdeps.onError(error instanceof Error ? error : new Error(String(error)))\n\t\t}\n\t}\n\n\treturn { exportImage, save }\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Ref } from 'vue'\nimport type { EditorContext } from '../editor/context.ts'\nimport type { SceneOptions } from '../editor/render.ts'\nimport type { TextAnnotation } from '../editor/state.ts'\n\nimport { ref } from 'vue'\nimport { visibleRect } from '../editor/render.ts'\nimport { newId } from '../utils/id.ts'\nimport { t } from '../utils/l10n.ts'\n\nexport interface TextEdit {\n\tsceneX: number\n\tsceneY: number\n\tscreenX: number\n\tscreenY: number\n\tscreenFontSize: number\n\tcolor: string\n\tvalue: string\n\t/** Existing annotation being edited, null when creating */\n\tid: string | null\n}\n\nexport interface TextEditingDeps {\n\tcontext: EditorContext\n\t/** The current view transform, null before the first render */\n\tviewOptions(): SceneOptions | null\n\t/** The orientation-baked source canvas */\n\toriented(): HTMLCanvasElement | null\n}\n\nexport interface TextEditing {\n\ttextEdit: Ref<TextEdit | null>\n\t/**\n\t * Open the text overlay at a scene position, optionally editing an\n\t * existing annotation.\n\t *\n\t * @param position scene coordinates of the text anchor\n\t * @param position.x horizontal scene coordinate\n\t * @param position.y vertical scene coordinate\n\t * @param existing annotation to edit instead of creating one\n\t */\n\tstartTextEdit(position: { x: number, y: number }, existing?: TextAnnotation): void\n\t/**\n\t * Commit the text overlay content into the state.\n\t *\n\t * @param text the entered text\n\t */\n\tconfirmTextEdit(text: string): void\n}\n\n/**\n * The floating text overlay's state and lifecycle: opening it at the\n * right screen position and folding the entered text back into the\n * annotations.\n *\n * @param deps context plus view accessors\n */\nexport function useTextEditing(deps: TextEditingDeps): TextEditing {\n\tconst { context } = deps\n\tconst textEdit = ref<TextEdit | null>(null)\n\n\t/**\n\t * Open the overlay at a scene position.\n\t *\n\t * @param position scene coordinates of the text anchor\n\t * @param position.x horizontal scene coordinate\n\t * @param position.y vertical scene coordinate\n\t * @param existing annotation to edit instead of creating one\n\t */\n\tfunction startTextEdit(position: { x: number, y: number }, existing?: TextAnnotation): void {\n\t\tconst options = deps.viewOptions()\n\t\tconst oriented = deps.oriented()\n\t\tif (options === null || oriented === null) {\n\t\t\treturn\n\t\t}\n\t\tconst origin = options.showCropped\n\t\t\t? visibleRect(context.state.value, { width: oriented.width, height: oriented.height })\n\t\t\t: { x: 0, y: 0 }\n\t\ttextEdit.value = {\n\t\t\tsceneX: position.x,\n\t\t\tsceneY: position.y,\n\t\t\tscreenX: options.offset.x + (position.x - origin.x) * options.scale,\n\t\t\tscreenY: options.offset.y + (position.y - origin.y) * options.scale,\n\t\t\tscreenFontSize: (existing?.fontSize ?? context.fontSize.value) * options.scale,\n\t\t\tcolor: existing?.color ?? context.drawColor.value,\n\t\t\tvalue: existing?.text ?? '',\n\t\t\tid: existing?.id ?? null,\n\t\t}\n\t}\n\n\t/**\n\t * Fold the entered text back into the annotations.\n\t *\n\t * @param text the entered text\n\t */\n\tfunction confirmTextEdit(text: string): void {\n\t\tconst edit = textEdit.value\n\t\ttextEdit.value = null\n\t\tif (edit === null) {\n\t\t\treturn\n\t\t}\n\t\tconst state = context.state.value\n\t\tconst trimmed = text.trim()\n\n\t\tif (edit.id !== null) {\n\t\t\tcontext.commit({\n\t\t\t\t...state,\n\t\t\t\tannotations: trimmed === ''\n\t\t\t\t\t? state.annotations.filter((annotation) => annotation.id !== edit.id)\n\t\t\t\t\t: state.annotations.map((annotation) => annotation.id === edit.id ? { ...annotation, text: trimmed } : annotation),\n\t\t\t}, trimmed === '' ? t('Delete') : t('Text'))\n\t\t} else if (trimmed !== '') {\n\t\t\tcontext.commit({\n\t\t\t\t...state,\n\t\t\t\tannotations: [...state.annotations, {\n\t\t\t\t\tid: newId(),\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\tx: edit.sceneX,\n\t\t\t\t\ty: edit.sceneY,\n\t\t\t\t\ttext: trimmed,\n\t\t\t\t\tcolor: edit.color,\n\t\t\t\t\tfontSize: context.fontSize.value,\n\t\t\t\t\trotation: 0,\n\t\t\t\t}],\n\t\t\t}, t('Text'))\n\t\t}\n\t}\n\n\treturn { textEdit, startTextEdit, confirmTextEdit }\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { ComputedRef, Ref } from 'vue'\nimport type { EditorContext } from '../editor/context.ts'\nimport type { Point } from '../editor/view.ts'\n\nimport { computed, onBeforeUnmount, onMounted, shallowRef } from 'vue'\nimport { MIN_ZOOM, PINCH_TOLERANCE, wheelZoomFactor } from '../editor/view.ts'\nimport { ownsSpaceKey } from '../utils/dom.ts'\n\nexport interface WheelControls {\n\t/** Whether a pan gesture would be taken right now, for the cursor */\n\tpanArmed: ComputedRef<boolean>\n}\n\n/** Both active touch points of a pinch, in client coordinates */\ninterface Pinch {\n\tdistance: number\n\tcentroid: Point\n}\n\n/**\n * View gestures on the canvas.\n *\n * The wheel always zooms at the cursor, which is what a canvas editor\n * is expected to do and what a trackpad pinch already sent as\n * ctrl+wheel. Panning is therefore on the drag gestures: the middle\n * button or a held space bar in every mode, plus a plain drag in the\n * modes where no canvas tool owns one. Two fingers zoom or pan\n * depending on whether they change distance.\n *\n * A claimed gesture stops the event from reaching the Konva stage, so\n * panning can never draw, move an annotation or resize the crop.\n *\n * @param element the canvas container\n * @param context the editor context holding the view state\n */\nexport function useWheelControls(element: Ref<HTMLElement | null>, context: EditorContext): WheelControls {\n\tlet dragFrom: { pointer: Point, pan: Point } | null = null\n\tlet pinch: Pinch | null = null\n\tconst pointers = new Map<number, Point>()\n\tconst spaceHeld = shallowRef(false)\n\n\t/** Modes without a canvas tool: a plain drag is free to pan */\n\tconst toolFreeDrag = () => context.activeTool.value === 'adjust'\n\tconst zoomed = () => context.viewZoom.value > MIN_ZOOM\n\n\tconst panArmed = computed(() => context.viewZoom.value > MIN_ZOOM\n\t\t&& (spaceHeld.value || context.activeTool.value === 'adjust'))\n\n\t/**\n\t * Turn a client position into an offset from the container center,\n\t * which is the anchor the zoom math works in.\n\t *\n\t * @param position the client position\n\t */\n\tfunction anchorAt(position: Point): Point | undefined {\n\t\tconst rect = element.value?.getBoundingClientRect()\n\t\tif (rect === undefined) {\n\t\t\treturn undefined\n\t\t}\n\t\treturn {\n\t\t\tx: position.x - rect.x - rect.width / 2,\n\t\t\ty: position.y - rect.y - rect.height / 2,\n\t\t}\n\t}\n\n\t/**\n\t * Distance and midpoint of the two active touch points.\n\t */\n\tfunction currentPinch(): Pinch | null {\n\t\tif (pointers.size !== 2) {\n\t\t\treturn null\n\t\t}\n\t\tconst [a, b] = [...pointers.values()] as [Point, Point]\n\t\treturn {\n\t\t\tdistance: Math.hypot(a.x - b.x, a.y - b.y),\n\t\t\tcentroid: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },\n\t\t}\n\t}\n\n\t/**\n\t * The wheel zooms at the cursor. The canvas owns the gesture, so the\n\t * page behind the editor never scrolls and the browser never zooms.\n\t *\n\t * @param event the wheel event\n\t */\n\tfunction onWheel(event: WheelEvent): void {\n\t\tevent.preventDefault()\n\t\tif (event.deltaY === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst height = element.value?.clientHeight ?? window.innerHeight\n\t\tconst factor = wheelZoomFactor(event.deltaY, event.deltaMode, height)\n\t\tcontext.setViewZoom(context.viewZoom.value * factor, anchorAt({ x: event.clientX, y: event.clientY }))\n\t}\n\n\t/**\n\t * @param event the pointer event\n\t */\n\tfunction onPointerDown(event: PointerEvent): void {\n\t\tif (event.pointerType === 'touch') {\n\t\t\tpointers.set(event.pointerId, { x: event.clientX, y: event.clientY })\n\t\t\tif (pointers.size === 2) {\n\t\t\t\tpinch = currentPinch()\n\t\t\t\t// Two fingers drive the view: whatever the tool started on\n\t\t\t\t// the first finger is abandoned rather than committed\n\t\t\t\tcontext.panning.value = true\n\t\t\t\tevent.stopPropagation()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\t// The middle button pans anywhere; the left button only where no\n\t\t// tool owns the drag, or while the space bar is held\n\t\tconst wantsPan = event.button === 1 || (event.button === 0 && (spaceHeld.value || toolFreeDrag()))\n\t\tif (!wantsPan || !zoomed()) {\n\t\t\treturn\n\t\t}\n\t\t// Claim the gesture before the stage sees it\n\t\tevent.preventDefault()\n\t\tevent.stopPropagation()\n\t\tdragFrom = {\n\t\t\tpointer: { x: event.clientX, y: event.clientY },\n\t\t\tpan: context.viewPan.value,\n\t\t}\n\t\tcontext.panning.value = true\n\t\telement.value?.setPointerCapture(event.pointerId)\n\t}\n\n\t/**\n\t * @param event the pointer event\n\t */\n\tfunction onPointerMove(event: PointerEvent): void {\n\t\tif (event.pointerType === 'touch' && pointers.has(event.pointerId)) {\n\t\t\tpointers.set(event.pointerId, { x: event.clientX, y: event.clientY })\n\t\t\tconst next = currentPinch()\n\t\t\tif (next === null || pinch === null) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.stopPropagation()\n\t\t\tconst ratio = next.distance / pinch.distance\n\t\t\tif (Math.abs(ratio - 1) > PINCH_TOLERANCE) {\n\t\t\t\tcontext.setViewZoom(context.viewZoom.value * ratio, anchorAt(next.centroid))\n\t\t\t} else {\n\t\t\t\tcontext.setViewPan({\n\t\t\t\t\tx: context.viewPan.value.x + next.centroid.x - pinch.centroid.x,\n\t\t\t\t\ty: context.viewPan.value.y + next.centroid.y - pinch.centroid.y,\n\t\t\t\t})\n\t\t\t}\n\t\t\tpinch = next\n\t\t\treturn\n\t\t}\n\t\tif (dragFrom === null) {\n\t\t\treturn\n\t\t}\n\t\tevent.stopPropagation()\n\t\tcontext.setViewPan({\n\t\t\tx: dragFrom.pan.x + (event.clientX - dragFrom.pointer.x),\n\t\t\ty: dragFrom.pan.y + (event.clientY - dragFrom.pointer.y),\n\t\t})\n\t}\n\n\t/**\n\t * @param event the pointer event, absent when invoked as a reset\n\t */\n\tfunction onPointerUp(event?: PointerEvent): void {\n\t\tif (event !== undefined) {\n\t\t\tpointers.delete(event.pointerId)\n\t\t}\n\t\tpinch = currentPinch()\n\t\tdragFrom = null\n\t\tif (pointers.size < 2) {\n\t\t\tcontext.panning.value = false\n\t\t}\n\t}\n\n\t/**\n\t * @param event the keyboard event\n\t */\n\tfunction onKeydown(event: KeyboardEvent): void {\n\t\tif (event.code !== 'Space' || ownsSpaceKey(event.target)) {\n\t\t\treturn\n\t\t}\n\t\t// Space is the pan modifier here, not a page scroll\n\t\tevent.preventDefault()\n\t\tspaceHeld.value = true\n\t}\n\n\t/**\n\t * @param event the keyboard event\n\t */\n\tfunction onKeyup(event: KeyboardEvent): void {\n\t\tif (event.code === 'Space') {\n\t\t\tspaceHeld.value = false\n\t\t}\n\t}\n\n\tonMounted(() => {\n\t\tconst target = element.value\n\t\ttarget?.addEventListener('wheel', onWheel, { passive: false })\n\t\t// Capture phase: the stage listens on a descendant, so a claimed\n\t\t// gesture has to be intercepted on the way down\n\t\ttarget?.addEventListener('pointerdown', onPointerDown, { capture: true })\n\t\ttarget?.addEventListener('pointermove', onPointerMove, { capture: true })\n\t\ttarget?.addEventListener('pointerup', onPointerUp)\n\t\ttarget?.addEventListener('pointercancel', onPointerUp)\n\t\twindow.addEventListener('keydown', onKeydown)\n\t\twindow.addEventListener('keyup', onKeyup)\n\t})\n\tonBeforeUnmount(() => {\n\t\tconst target = element.value\n\t\ttarget?.removeEventListener('wheel', onWheel)\n\t\ttarget?.removeEventListener('pointerdown', onPointerDown, { capture: true })\n\t\ttarget?.removeEventListener('pointermove', onPointerMove, { capture: true })\n\t\ttarget?.removeEventListener('pointerup', onPointerUp)\n\t\ttarget?.removeEventListener('pointercancel', onPointerUp)\n\t\twindow.removeEventListener('keydown', onKeydown)\n\t\twindow.removeEventListener('keyup', onKeyup)\n\t})\n\n\treturn { panArmed }\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Point } from './view.ts'\n\nimport Konva from 'konva'\n\nexport type TransitionKind\n\t= | 'load'\n\t\t| 'rotate-cw'\n\t\t| 'rotate-ccw'\n\t\t| 'flip-h'\n\t\t| 'flip-v'\n\t\t| 'crop'\n\nexport interface TransitionContext {\n\t/** View scale before the change */\n\tpreviousScale: number\n\t/** Stage offset of the previous view */\n\tpreviousOffset: { x: number, y: number }\n\t/** Scene-space origin of the previous view (crop corner or 0,0) */\n\tpreviousOrigin: { x: number, y: number }\n}\n\n/**\n * One node carried by a transition, in its own coordinate space.\n *\n * The content lives in scene space under the view group, while the crop\n * overlay lives in stage space on its own layer. Both have to play the\n * same visual transition, so each target says where its pivot is and\n * how to read a stage-pixel distance in its own units.\n */\nexport interface TransitionTarget {\n\t/**\n\t * The node to tween: it starts at the inverse of the edit and eases\n\t * to identity, so the tween never touches the view transform the\n\t * reconciler owns\n\t */\n\tnode: Konva.Node\n\t/** The visible center, in this node's own coordinate space */\n\tpivot: Point\n\t/** This node's units per stage pixel: 1 in stage space */\n\tunit: number\n}\n\nexport interface TransitionDeps {\n\t/** Every node playing this transition */\n\ttargets: TransitionTarget[]\n\t/** View scale after the change */\n\tscale: number\n\t/** Stage offset of the view after the change */\n\toffset: Point\n\t/** Scene-space origin of the view after the change */\n\torigin: Point\n}\n\nconst DURATION = 0.3\n\n/**\n * Whether animations should be skipped for this user.\n */\nexport function prefersReducedMotion(): boolean {\n\treturn typeof window.matchMedia === 'function'\n\t\t&& window.matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\n/**\n * Re-anchor a node so its transform pivots on the visible center while\n * rendering identically. Enables rotation and scale tweens around the\n * visual center instead of the node origin.\n *\n * @param target the node to re-anchor\n */\nfunction pivotOnCenter(target: TransitionTarget): void {\n\ttarget.node.offset(target.pivot)\n\ttarget.node.position(target.pivot)\n}\n\n/**\n * Play a cosmetic transition on the freshly reconciled scene: the\n * content group starts at the inverse transform of the edit and eases\n * to identity. State is already committed and the view transform lives\n * on the parent group, so skipping or interrupting the tween can never\n * corrupt anything; an interrupted tween still ends at identity.\n *\n * @param kind which edit happened\n * @param deps the reconciled scene and view\n * @param context metrics of the view before the edit\n */\nexport function playTransition(kind: TransitionKind, deps: TransitionDeps, context: TransitionContext): void {\n\tif (prefersReducedMotion()) {\n\t\treturn\n\t}\n\n\tconst { scale } = deps\n\tconst easing = Konva.Easings.EaseInOut\n\t// How much larger the previous view was, in content units\n\tconst ratio = context.previousScale / scale\n\n\tfor (const target of deps.targets) {\n\t\tconst { node } = target\n\t\t// Neutral base: a previous transition may have left its pivot behind\n\t\tnode.setAttrs({ x: 0, y: 0, offsetX: 0, offsetY: 0, rotation: 0, scaleX: 1, scaleY: 1, opacity: 1 })\n\n\t\tswitch (kind) {\n\t\t\tcase 'load':\n\t\t\t\tpivotOnCenter(target)\n\t\t\t\tnode.opacity(0)\n\t\t\t\tnode.scale({ x: 0.96, y: 0.96 })\n\t\t\t\tnode.to({ opacity: 1, scaleX: 1, scaleY: 1, duration: DURATION, easing })\n\t\t\t\tbreak\n\t\t\tcase 'rotate-cw':\n\t\t\tcase 'rotate-ccw':\n\t\t\t\tpivotOnCenter(target)\n\t\t\t\tnode.rotation(kind === 'rotate-cw' ? -90 : 90)\n\t\t\t\tnode.scale({ x: ratio, y: ratio })\n\t\t\t\tnode.to({ rotation: 0, scaleX: 1, scaleY: 1, duration: DURATION, easing })\n\t\t\t\tbreak\n\t\t\tcase 'flip-h':\n\t\t\t\tpivotOnCenter(target)\n\t\t\t\tnode.scaleX(-1)\n\t\t\t\tnode.to({ scaleX: 1, duration: DURATION, easing })\n\t\t\t\tbreak\n\t\t\tcase 'flip-v':\n\t\t\t\tpivotOnCenter(target)\n\t\t\t\tnode.scaleY(-1)\n\t\t\t\tnode.to({ scaleY: 1, duration: DURATION, easing })\n\t\t\t\tbreak\n\t\t\tcase 'crop': {\n\t\t\t\t// Start exactly at the previous view, expressed relative to\n\t\t\t\t// the new one, and ease to identity\n\t\t\t\tconst { previousScale, previousOffset, previousOrigin } = context\n\t\t\t\tnode.scale({ x: ratio, y: ratio })\n\t\t\t\tnode.position({\n\t\t\t\t\tx: ((previousOffset.x - previousOrigin.x * previousScale) - (deps.offset.x - deps.origin.x * scale)) * target.unit,\n\t\t\t\t\ty: ((previousOffset.y - previousOrigin.y * previousScale) - (deps.offset.y - deps.origin.y * scale)) * target.unit,\n\t\t\t\t})\n\t\t\t\tnode.to({ x: 0, y: 0, scaleX: 1, scaleY: 1, duration: DURATION, easing })\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Rect, Size } from './state.ts'\n\nimport Konva from 'konva'\nimport { clampRect } from './state.ts'\n\nexport interface CropOverlayDeps {\n\tstage: Konva.Stage\n\t/** Oriented image size in scene coordinates */\n\toriented: Size\n\t/** View transform mapping scene to stage coordinates */\n\tscale: number\n\toffset: { x: number, y: number }\n\t/** Crop rect to start from, defaults to the full image */\n\tinitial: Rect | null\n}\n\nexport interface CropBox {\n\tx: number\n\ty: number\n\twidth: number\n\theight: number\n}\n\n/**\n * Clamp a transformer bound box to the image so a resize keeps\n * following the cursor and only stops at the border. Under an aspect\n * lock the box keeps its ratio, anchored on the untouched edge.\n *\n * @param bounds the image bounds in stage coordinates\n * @param oldBox the box before this gesture step\n * @param newBox the requested box\n * @param keepRatio whether an aspect lock is active\n */\nexport function clampCropBox(bounds: CropBox, oldBox: CropBox, newBox: CropBox, keepRatio: boolean): CropBox {\n\tconst right = bounds.x + bounds.width\n\tconst bottom = bounds.y + bounds.height\n\tlet { x, y, width, height } = newBox\n\n\tif (x < bounds.x) {\n\t\twidth -= bounds.x - x\n\t\tx = bounds.x\n\t}\n\tif (y < bounds.y) {\n\t\theight -= bounds.y - y\n\t\ty = bounds.y\n\t}\n\twidth = Math.min(width, right - x)\n\theight = Math.min(height, bottom - y)\n\n\tif (keepRatio && oldBox.height > 0) {\n\t\tconst ratio = oldBox.width / oldBox.height\n\t\tif (width / height > ratio) {\n\t\t\twidth = height * ratio\n\t\t} else {\n\t\t\theight = width / ratio\n\t\t}\n\t\tif (Math.abs(newBox.x - oldBox.x) > 0.01) {\n\t\t\tx = Math.min(newBox.x + newBox.width, right) - width\n\t\t}\n\t\tif (Math.abs(newBox.y - oldBox.y) > 0.01) {\n\t\t\ty = Math.min(newBox.y + newBox.height, bottom) - height\n\t\t}\n\t}\n\n\treturn {\n\t\t...newBox,\n\t\tx,\n\t\ty,\n\t\twidth: Math.max(8, width),\n\t\theight: Math.max(8, height),\n\t}\n}\n\n/** The view transform the overlay projects its rectangle through */\nexport interface CropView {\n\t/** Oriented image size in scene coordinates */\n\toriented: Size\n\tscale: number\n\toffset: { x: number, y: number }\n}\n\nexport interface CropOverlay {\n\t/**\n\t * The overlay's own layer. It lives in stage space, outside the\n\t * animated content, so view transitions have to carry it along\n\t * explicitly or the handles jump while the image eases.\n\t */\n\tlayer: Konva.Layer\n\t/** Current crop rectangle in scene coordinates */\n\tgetRect(): Rect\n\t/**\n\t * Follow a view change, keeping the rectangle on the same scene\n\t * coordinates. Panning, zooming or resizing the container must not\n\t * cost the user the selection they were drawing.\n\t *\n\t * @param view the new view transform\n\t */\n\tupdate(view: CropView): void\n\t/**\n\t * Lock the crop to an aspect ratio, resizing the current rect to\n\t * match, or free it again with null.\n\t *\n\t * @param aspect width divided by height, or null for freeform\n\t */\n\tsetAspect(aspect: number | null): void\n\tdestroy(): void\n}\n\n/**\n * Interactive crop overlay: a draggable, resizable rectangle with the\n * surrounding area dimmed. Works in stage coordinates on its own layer.\n *\n * @param deps stage, view transform and initial rect\n */\nexport function attachCropOverlay(deps: CropOverlayDeps): CropOverlay {\n\t// Mutable: the overlay outlives the view it was built for\n\tconst view: CropView = { oriented: deps.oriented, scale: deps.scale, offset: deps.offset }\n\n\tconst toStage = (rect: Rect): Rect => ({\n\t\tx: view.offset.x + rect.x * view.scale,\n\t\ty: view.offset.y + rect.y * view.scale,\n\t\twidth: rect.width * view.scale,\n\t\theight: rect.height * view.scale,\n\t})\n\tconst toScene = (rect: Rect): Rect => ({\n\t\tx: (rect.x - view.offset.x) / view.scale,\n\t\ty: (rect.y - view.offset.y) / view.scale,\n\t\twidth: rect.width / view.scale,\n\t\theight: rect.height / view.scale,\n\t})\n\n\tlet imageBounds = toStage({ x: 0, y: 0, ...view.oriented })\n\tconst layer = new Konva.Layer({ name: 'crop' })\n\n\tconst makeShade = () => new Konva.Rect({\n\t\tfill: 'rgba(0, 0, 0, 0.5)',\n\t\tlistening: false,\n\t})\n\tconst shadeTop = makeShade()\n\tconst shadeLeft = makeShade()\n\tconst shadeRight = makeShade()\n\tconst shadeBottom = makeShade()\n\tfor (const shade of [shadeTop, shadeLeft, shadeRight, shadeBottom]) {\n\t\tlayer.add(shade)\n\t}\n\n\tconst cropNode = new Konva.Rect({\n\t\t// Named so it can be told apart from the four shade rects\n\t\tname: 'crop-rect',\n\t\t...toStage(clampRect(deps.initial ?? { x: 0, y: 0, ...view.oriented }, view.oriented)),\n\t\tstroke: 'rgba(255, 255, 255, 0.9)',\n\t\tstrokeWidth: 1,\n\t\tdraggable: true,\n\t\tstrokeScaleEnabled: false,\n\t})\n\tlayer.add(cropNode)\n\n\t/** The crop node's box in stage coordinates, scale folded in */\n\tconst stageRect = (): Rect => ({\n\t\tx: cropNode.x(),\n\t\ty: cropNode.y(),\n\t\twidth: cropNode.width() * cropNode.scaleX(),\n\t\theight: cropNode.height() * cropNode.scaleY(),\n\t})\n\n\t// Rule-of-thirds guides inside the crop rect\n\tconst gridLines = Array.from({ length: 4 }, () => new Konva.Line({\n\t\tstroke: 'rgba(255, 255, 255, 0.35)',\n\t\tstrokeWidth: 1,\n\t\tlistening: false,\n\t}))\n\tfor (const line of gridLines) {\n\t\tlayer.add(line)\n\t}\n\n\tconst clampToImage = (rect: Rect): Rect => {\n\t\tconst x = Math.min(Math.max(rect.x, imageBounds.x), imageBounds.x + imageBounds.width - rect.width)\n\t\tconst y = Math.min(Math.max(rect.y, imageBounds.y), imageBounds.y + imageBounds.height - rect.height)\n\t\treturn { ...rect, x, y }\n\t}\n\n\tconst updateOverlay = () => {\n\t\tconst rect = stageRect()\n\t\tconst { x, y, width, height } = imageBounds\n\t\tshadeTop.setAttrs({ x, y, width, height: rect.y - y })\n\t\tshadeLeft.setAttrs({ x, y: rect.y, width: rect.x - x, height: rect.height })\n\t\tshadeRight.setAttrs({ x: rect.x + rect.width, y: rect.y, width: x + width - rect.x - rect.width, height: rect.height })\n\t\tshadeBottom.setAttrs({ x, y: rect.y + rect.height, width, height: y + height - rect.y - rect.height })\n\n\t\t// Thirds guides: two vertical, two horizontal\n\t\tgridLines[0]!.points([rect.x + rect.width / 3, rect.y, rect.x + rect.width / 3, rect.y + rect.height])\n\t\tgridLines[1]!.points([rect.x + (rect.width * 2) / 3, rect.y, rect.x + (rect.width * 2) / 3, rect.y + rect.height])\n\t\tgridLines[2]!.points([rect.x, rect.y + rect.height / 3, rect.x + rect.width, rect.y + rect.height / 3])\n\t\tgridLines[3]!.points([rect.x, rect.y + (rect.height * 2) / 3, rect.x + rect.width, rect.y + (rect.height * 2) / 3])\n\t}\n\n\t// Mirrors the transformer's keepRatio: reading it back inside its\n\t// own boundBoxFunc would make the initializer self-referential\n\tlet ratioLocked = false\n\n\tconst transformer = new Konva.Transformer({\n\t\tnodes: [cropNode],\n\t\trotateEnabled: false,\n\t\tflipEnabled: false,\n\t\tkeepRatio: false,\n\t\t// Pintura-style solid round corner dots\n\t\tenabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],\n\t\tanchorSize: 14,\n\t\tanchorCornerRadius: 7,\n\t\tanchorFill: '#111',\n\t\tanchorStroke: '#111',\n\t\tanchorStrokeWidth: 1,\n\t\tborderStroke: 'rgba(255, 255, 255, 0.7)',\n\t\tboundBoxFunc: (oldBox, newBox) => ({ ...newBox, ...clampCropBox(imageBounds, oldBox, newBox, ratioLocked) }),\n\n\t})\n\tlayer.add(transformer)\n\n\tcropNode.dragBoundFunc((position) => clampToImage({\n\t\t...position,\n\t\twidth: cropNode.width() * cropNode.scaleX(),\n\t\theight: cropNode.height() * cropNode.scaleY(),\n\t}))\n\tcropNode.on('dragmove transform', updateOverlay)\n\n\t/**\n\t * Resize the crop rect to the given ratio around its center, kept\n\t * inside the image, and lock the transformer to it.\n\t *\n\t * @param aspect width divided by height, or null for freeform\n\t */\n\tconst setAspect = (aspect: number | null): void => {\n\t\tratioLocked = aspect !== null\n\t\ttransformer.keepRatio(ratioLocked)\n\t\tif (aspect === null) {\n\t\t\treturn\n\t\t}\n\t\tconst current = stageRect()\n\t\t// Largest rect with the wanted ratio that fits the image bounds,\n\t\t// no bigger than the current selection's longest edge\n\t\tconst width = Math.min(\n\t\t\tMath.max(current.width, current.height * aspect),\n\t\t\timageBounds.width,\n\t\t\timageBounds.height * aspect,\n\t\t)\n\t\tconst height = width / aspect\n\t\tconst center = { x: current.x + current.width / 2, y: current.y + current.height / 2 }\n\t\tconst position = clampToImage({\n\t\t\tx: center.x - width / 2,\n\t\t\ty: center.y - height / 2,\n\t\t\twidth,\n\t\t\theight,\n\t\t})\n\t\tcropNode.setAttrs({ ...position, width, height, scaleX: 1, scaleY: 1 })\n\t\ttransformer.forceUpdate()\n\t\tupdateOverlay()\n\t}\n\n\tupdateOverlay()\n\tdeps.stage.add(layer)\n\n\treturn {\n\t\tlayer,\n\t\tsetAspect,\n\t\tupdate(next) {\n\t\t\t// Read the selection in scene units before the transform moves\n\t\t\tconst scene = toScene(stageRect())\n\t\t\tview.oriented = next.oriented\n\t\t\tview.scale = next.scale\n\t\t\tview.offset = next.offset\n\t\t\timageBounds = toStage({ x: 0, y: 0, ...view.oriented })\n\t\t\tcropNode.setAttrs({ ...toStage(scene), scaleX: 1, scaleY: 1 })\n\t\t\ttransformer.forceUpdate()\n\t\t\tupdateOverlay()\n\t\t},\n\t\tgetRect() {\n\t\t\tconst scene = toScene(stageRect())\n\t\t\treturn clampRect({\n\t\t\t\tx: Math.round(scene.x),\n\t\t\t\ty: Math.round(scene.y),\n\t\t\t\twidth: Math.round(scene.width),\n\t\t\t\theight: Math.round(scene.height),\n\t\t\t}, view.oriented)\n\t\t},\n\t\tdestroy() {\n\t\t\ttransformer.destroy()\n\t\t\tlayer.destroy()\n\t\t},\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nexport interface Box {\n\twidth: number\n\theight: number\n}\n\nexport interface FitResult {\n\t/** Applied uniform scale factor */\n\tscale: number\n\t/** Scaled content width */\n\twidth: number\n\t/** Scaled content height */\n\theight: number\n\t/** Horizontal offset centering the content in the container */\n\tx: number\n\t/** Vertical offset centering the content in the container */\n\ty: number\n}\n\n/**\n * Scale content to fit inside a container, preserving aspect ratio.\n * Content is centered and never upscaled beyond its natural size.\n *\n * @param content natural content dimensions\n * @param container available container dimensions\n */\n/**\n * Scale factor needed so a box rotated by the given angle still fully\n * covers its own unrotated bounds (no exposed corners).\n *\n * @param box the box dimensions\n * @param degrees rotation angle in degrees\n */\nexport function coverScale(box: Box, degrees: number): number {\n\tif (box.width <= 0 || box.height <= 0) {\n\t\tthrow new RangeError('Dimensions must be positive')\n\t}\n\tconst radians = (degrees * Math.PI) / 180\n\tconst cos = Math.abs(Math.cos(radians))\n\tconst sin = Math.abs(Math.sin(radians))\n\treturn Math.max(\n\t\t(box.width * cos + box.height * sin) / box.width,\n\t\t(box.width * sin + box.height * cos) / box.height,\n\t)\n}\n\n/**\n * Scale content to fit inside a container, preserving aspect ratio.\n * Content is centered and never upscaled beyond its natural size.\n *\n * @param content natural content dimensions\n * @param container available container dimensions\n */\nexport function fitContain(content: Box, container: Box): FitResult {\n\tif (content.width <= 0 || content.height <= 0\n\t\t|| container.width <= 0 || container.height <= 0) {\n\t\tthrow new RangeError('Dimensions must be positive')\n\t}\n\n\tconst scale = Math.min(\n\t\tcontainer.width / content.width,\n\t\tcontainer.height / content.height,\n\t\t1,\n\t)\n\tconst width = content.width * scale\n\tconst height = content.height * scale\n\n\treturn {\n\t\tscale,\n\t\twidth,\n\t\theight,\n\t\tx: (container.width - width) / 2,\n\t\ty: (container.height - height) / 2,\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { EditorState } from './state.ts'\n\nimport { coverScale } from '../utils/geometry.ts'\nimport { orientedSize } from './state.ts'\n\n/**\n * Bake orientation, fine rotation and zoom into a canvas copy of the\n * source image. The canvas always keeps the 90°-oriented dimensions:\n * fine rotation and zoom scale the content up to cover the full frame,\n * so every downstream coordinate lives in one stable, unrotated space.\n *\n * @param image the decoded source image\n * @param state the orientation-affecting parts of the edit state\n */\nexport function orientImage(\n\timage: HTMLImageElement,\n\tstate: Pick<EditorState, 'rotation' | 'flipX' | 'flipY' | 'fineRotation' | 'zoom'>,\n): HTMLCanvasElement {\n\tconst natural = { width: image.naturalWidth, height: image.naturalHeight }\n\tconst oriented = orientedSize(natural, state.rotation)\n\n\tconst canvas = document.createElement('canvas')\n\tcanvas.width = oriented.width\n\tcanvas.height = oriented.height\n\n\tconst context = canvas.getContext('2d')\n\tif (context === null) {\n\t\tthrow new Error('Canvas 2D context unavailable')\n\t}\n\n\tconst cover = coverScale(oriented, state.fineRotation) * Math.max(1, state.zoom)\n\n\tcontext.translate(oriented.width / 2, oriented.height / 2)\n\tcontext.rotate((state.fineRotation * Math.PI) / 180)\n\tcontext.scale(cover, cover)\n\tcontext.rotate((state.rotation * Math.PI) / 180)\n\tcontext.scale(state.flipX ? -1 : 1, state.flipY ? -1 : 1)\n\tcontext.drawImage(image, -natural.width / 2, -natural.height / 2)\n\n\treturn canvas\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Annotation, EditorState, TextAnnotation } from './state.ts'\n\nimport Konva from 'konva'\nimport { t } from '../utils/l10n.ts'\nimport { primaryColor } from '../utils/theme.ts'\n\nexport interface SelectionDeps {\n\tstage: Konva.Stage\n\tgetState(): EditorState\n\tcommit(state: EditorState, label?: string): void\n\tselect(id: string | null): void\n\tgetSelectedId(): string | null\n\t/** Open the text overlay to edit an existing annotation */\n\teditText(annotation: TextAnnotation): void\n\t/**\n\t * Report the selected node's stage-space bounds, null on deselect\n\t *\n\t * @param rect the bounds in stage pixels\n\t * @param rect.x horizontal position\n\t * @param rect.y vertical position\n\t * @param rect.width bound width\n\t * @param rect.height bound height\n\t */\n\tonSelectionRect(rect: { x: number, y: number, width: number, height: number } | null): void\n}\n\n/**\n * The transform readers the fold needs. Konva's nodes satisfy this, and\n * so does anything else that can report a transform: picking the\n * getters off Konva.Node instead drags in its setter overloads, which\n * makes the type impossible to satisfy by hand.\n */\nexport interface NodeTransform {\n\tx(): number\n\ty(): number\n\tscaleX(): number\n\tscaleY(): number\n\trotation(): number\n}\n\nexport interface Selection {\n\t/**\n\t * Re-bind to the scene after it reconciled: a changed annotation is\n\t * rendered by a new node, and the transformer has to follow it.\n\t */\n\tsync(): void\n\tdetach(): void\n}\n\n/**\n * Map a flat point list through the node's transform, in Konva's\n * application order: scale, then rotation, then translation.\n *\n * @param points flat [x1, y1, …] list\n * @param node the transformed Konva node\n */\nfunction transformPoints(points: number[], node: NodeTransform): number[] {\n\tconst radians = (node.rotation() * Math.PI) / 180\n\tconst cos = Math.cos(radians)\n\tconst sin = Math.sin(radians)\n\tconst result: number[] = []\n\tfor (let i = 0; i < points.length; i += 2) {\n\t\tconst x = points[i]! * node.scaleX()\n\t\tconst y = points[i + 1]! * node.scaleY()\n\t\tresult.push(node.x() + x * cos - y * sin, node.y() + x * sin + y * cos)\n\t}\n\treturn result\n}\n\n/**\n * Fold the node transform applied by dragging or the transformer handles\n * back into the annotation data, so the node itself stays untransformed.\n *\n * @param annotation the annotation to update\n * @param node its Konva node after the interaction\n */\nexport function applyNodeTransform(annotation: Annotation, node: NodeTransform): Annotation {\n\tswitch (annotation.type) {\n\t\tcase 'draw':\n\t\tcase 'arrow': {\n\t\t\t// Scale and rotation fold into the point list itself, so the\n\t\t\t// annotation needs no transform fields of its own\n\t\t\tconst points = transformPoints(annotation.points, node)\n\t\t\tconst scale = (Math.abs(node.scaleX()) + Math.abs(node.scaleY())) / 2\n\t\t\tconst strokeWidth = Math.max(1, annotation.strokeWidth * scale)\n\t\t\treturn { ...annotation, points, strokeWidth } as Annotation\n\t\t}\n\t\tcase 'redact':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: {\n\t\t\t\t\tx: node.x(),\n\t\t\t\t\ty: node.y(),\n\t\t\t\t\twidth: Math.max(1, annotation.rect.width * node.scaleX()),\n\t\t\t\t\theight: Math.max(1, annotation.rect.height * node.scaleY()),\n\t\t\t\t},\n\t\t\t}\n\t\tcase 'rectangle':\n\t\tcase 'ellipse':\n\t\t\t// Both shapes anchor at the rect's top-left (the ellipse via\n\t\t\t// its negative offset), so the fold is identical\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\trect: {\n\t\t\t\t\tx: node.x(),\n\t\t\t\t\ty: node.y(),\n\t\t\t\t\twidth: Math.max(1, annotation.rect.width * node.scaleX()),\n\t\t\t\t\theight: Math.max(1, annotation.rect.height * node.scaleY()),\n\t\t\t\t},\n\t\t\t\trotation: node.rotation(),\n\t\t\t}\n\t\tcase 'text':\n\t\tcase 'sticker':\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\tx: node.x(),\n\t\t\t\ty: node.y(),\n\t\t\t\tfontSize: Math.max(4, annotation.fontSize * node.scaleY()),\n\t\t\t\trotation: node.rotation(),\n\t\t\t}\n\t}\n}\n\n/**\n * Attach click-to-select, drag and transform behavior for annotation\n * nodes.\n *\n * @param deps stage access and state callbacks\n */\nexport function attachSelection(deps: SelectionDeps): Selection {\n\tconst accent = primaryColor()\n\tconst transformer = new Konva.Transformer({\n\t\trotateEnabled: true,\n\t\tflipEnabled: false,\n\t\tignoreStroke: true,\n\t\t// A plain square with four corner handles\n\t\tenabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],\n\t\tanchorSize: 12,\n\t\tanchorCornerRadius: 6,\n\t\tanchorFill: '#fff',\n\t\tanchorStroke: accent,\n\t\tborderStroke: accent,\n\t\trotateAnchorOffset: 24,\n\t\trotationSnaps: [0, 45, 90, 135, 180, 225, 270, 315],\n\t\trotationSnapTolerance: 6,\n\t})\n\tconst layer = new Konva.Layer({ name: 'selection' })\n\tlayer.add(transformer)\n\tdeps.stage.add(layer)\n\n\tconst findAnnotation = (id: string): Annotation | undefined => deps.getState().annotations.find((annotation) => annotation.id === id)\n\n\t// Konva id selectors match literally, and CSS.escape would mangle\n\t// UUIDs starting with a digit, so compare ids directly\n\tconst findNode = (id: string | null) => id === null ? null : deps.stage.find('.annotation').find((node) => node.id() === id) ?? null\n\n\tconst reportRect = () => {\n\t\tconst node = findNode(deps.getSelectedId())\n\t\tdeps.onSelectionRect(node ? node.getClientRect() : null)\n\t}\n\n\tconst syncTransformer = () => {\n\t\tconst id = deps.getSelectedId()\n\t\tconst node = findNode(id)\n\t\tif (node === null || node === undefined) {\n\t\t\ttransformer.nodes([])\n\t\t\tdeps.onSelectionRect(null)\n\t\t\treturn\n\t\t}\n\t\tconst annotation = findAnnotation(id!)\n\t\t// Every annotation resizes; freehand and arrow fold scale and\n\t\t// rotation into their point lists. Redactions stay axis-aligned:\n\t\t// their pixel sampling has no notion of an angle.\n\t\ttransformer.rotateEnabled(annotation !== undefined && annotation.type !== 'redact')\n\t\ttransformer.nodes([node])\n\t\tdeps.onSelectionRect(node.getClientRect())\n\t}\n\n\tconst sync = () => {\n\t\tdeps.stage.find('.annotation').forEach((node) => node.draggable(true))\n\t\tsyncTransformer()\n\t}\n\tsync()\n\n\tconst onWriteBack = (event: Konva.KonvaEventObject<Event>) => {\n\t\tconst node = event.target\n\t\tconst annotation = findAnnotation(node.id())\n\t\tif (annotation === undefined) {\n\t\t\treturn\n\t\t}\n\t\tconst state = deps.getState()\n\t\tdeps.commit({\n\t\t\t...state,\n\t\t\tannotations: state.annotations.map((entry) => entry.id === annotation.id ? applyNodeTransform(annotation, node) : entry),\n\t\t}, t('Move or resize'))\n\t}\n\n\tconst onClick = (event: Konva.KonvaEventObject<MouseEvent>) => {\n\t\tif (event.target.hasName('annotation')) {\n\t\t\tdeps.select(event.target.id())\n\t\t} else if (event.target === deps.stage || event.target instanceof Konva.Image) {\n\t\t\tdeps.select(null)\n\t\t}\n\t\tsyncTransformer()\n\t}\n\n\tconst onDblClick = (event: Konva.KonvaEventObject<MouseEvent>) => {\n\t\tconst annotation = findAnnotation(event.target.id())\n\t\tif (annotation?.type === 'text') {\n\t\t\tdeps.editText(annotation)\n\t\t}\n\t}\n\n\tdeps.stage.on('click.selection tap.selection', onClick)\n\tdeps.stage.on('dblclick.selection dbltap.selection', onDblClick)\n\tdeps.stage.on('dragend.selection transformend.selection', onWriteBack)\n\tdeps.stage.on('dragmove.selection transform.selection', reportRect)\n\n\treturn {\n\t\tsync,\n\t\tdetach() {\n\t\t\tdeps.stage.off('.selection')\n\t\t\tdeps.stage.find('.annotation').forEach((node) => node.draggable(false))\n\t\t\tdeps.onSelectionRect(null)\n\t\t\ttransformer.destroy()\n\t\t\tlayer.destroy()\n\t\t},\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type Konva from 'konva'\nimport type { Tool } from './context.ts'\nimport type { Annotation, EditorState, TextAnnotation } from './state.ts'\n\nimport { newId } from '../utils/id.ts'\nimport { t } from '../utils/l10n.ts'\nimport { buildAnnotationNode } from './render.ts'\n\nexport interface ToolOptions {\n\tcolor: string\n\tstrokeWidth: number\n\tfontSize: number\n\tsticker: string\n\tredactStyle: 'pixelate' | 'blur'\n}\n\nexport interface PointerToolDeps {\n\tstage: Konva.Stage\n\t/** Content group receiving the live preview node while dragging */\n\tcontentGroup(): Konva.Group | null\n\tgetState(): EditorState\n\tcommit(state: EditorState, label?: string): void\n\t/** Convert a stage pointer position to oriented image coordinates */\n\ttoScene(pointer: { x: number, y: number }): { x: number, y: number }\n\t/** The orientation-baked source canvas, needed by redact previews */\n\toriented(): HTMLCanvasElement | null\n\toptions(): ToolOptions\n\t/** Whether a view pan currently owns the pointer */\n\tpanning(): boolean\n\t/** Open the text editing overlay at the given scene position */\n\tstartTextEdit(position: { x: number, y: number }): void\n}\n\n/** What each tool calls the step it records, for the history list */\nconst TOOL_LABELS: Partial<Record<Tool, string>> = {\n\tdraw: t('Draw'),\n\trectangle: t('Rectangle'),\n\tellipse: t('Ellipse'),\n\tarrow: t('Arrow'),\n\tsticker: t('Sticker'),\n\tredact: t('Redact'),\n}\n\n/**\n * Attach the pointer handlers for the drawing-style tools to the stage.\n * Returns a cleanup function removing the handlers again.\n *\n * @param tool the active tool\n * @param deps stage access and state callbacks\n */\nexport function attachPointerTools(tool: Tool, deps: PointerToolDeps): () => void {\n\tif (!['draw', 'rectangle', 'ellipse', 'arrow', 'text', 'sticker', 'redact'].includes(tool)) {\n\t\treturn () => {}\n\t}\n\n\tlet active: Annotation | null = null\n\tlet previewNode: Konva.Shape | null = null\n\tlet start = { x: 0, y: 0 }\n\tlet pendingText: { x: number, y: number } | null = null\n\n\tconst scenePointer = () => {\n\t\tconst pointer = deps.stage.getPointerPosition()\n\t\treturn pointer === null ? null : deps.toScene(pointer)\n\t}\n\n\t/**\n\t * Follow the active annotation with the live preview node.\n\t *\n\t * Point lists are pushed into the existing node: rebuilding it on\n\t * every pointermove made a long freehand stroke quadratic, since\n\t * each move re-created a shape carrying every point so far.\n\t */\n\tconst refreshPreview = () => {\n\t\tif (active === null) {\n\t\t\tpreviewNode?.destroy()\n\t\t\tpreviewNode = null\n\t\t\treturn\n\t\t}\n\t\tif (previewNode !== null && (active.type === 'draw' || active.type === 'arrow')) {\n\t\t\t(previewNode as Konva.Line).points(active.points)\n\t\t\treturn\n\t\t}\n\n\t\tpreviewNode?.destroy()\n\t\tpreviewNode = null\n\t\tconst source = deps.oriented() ?? undefined\n\t\t// A redaction preview needs the image to pixelate; without it the\n\t\t// commit still works, only the live preview is skipped\n\t\tif (active.type === 'redact' && source === undefined) {\n\t\t\treturn\n\t\t}\n\t\tpreviewNode = buildAnnotationNode(active, source)\n\t\t// The live preview joins the content group so it shares the\n\t\t// scene transform with the final node\n\t\tdeps.contentGroup()?.add(previewNode)\n\t}\n\n\t/**\n\t * Drop the annotation in progress without committing it.\n\t */\n\tconst discard = () => {\n\t\tactive = null\n\t\tpendingText = null\n\t\tpreviewNode?.destroy()\n\t\tpreviewNode = null\n\t}\n\n\tconst onPointerDown = () => {\n\t\tconst point = scenePointer()\n\t\tif (point === null || deps.panning()) {\n\t\t\treturn\n\t\t}\n\t\tconst options = deps.options()\n\t\tstart = point\n\n\t\tswitch (tool) {\n\t\t\tcase 'draw':\n\t\t\t\tactive = { id: newId(), type: 'draw', points: [point.x, point.y], color: options.color, strokeWidth: options.strokeWidth }\n\t\t\t\tbreak\n\t\t\tcase 'arrow':\n\t\t\t\tactive = { id: newId(), type: 'arrow', points: [point.x, point.y, point.x, point.y], color: options.color, strokeWidth: options.strokeWidth }\n\t\t\t\tbreak\n\t\t\tcase 'rectangle':\n\t\t\tcase 'ellipse':\n\t\t\t\tactive = { id: newId(), type: tool, rect: { x: point.x, y: point.y, width: 1, height: 1 }, rotation: 0, color: options.color, strokeWidth: options.strokeWidth }\n\t\t\t\tbreak\n\t\t\tcase 'redact':\n\t\t\t\tactive = { id: newId(), type: 'redact', rect: { x: point.x, y: point.y, width: 1, height: 1 }, style: options.redactStyle }\n\t\t\t\tbreak\n\t\t\tcase 'text':\n\t\t\t\t// Deferred to pointerup: opening the overlay mid-click would\n\t\t\t\t// blur (and close) it again when the click completes\n\t\t\t\tpendingText = point\n\t\t\t\treturn\n\t\t\tcase 'sticker': {\n\t\t\t\tconst state = deps.getState()\n\t\t\t\tconst sticker: TextAnnotation = {\n\t\t\t\t\tid: newId(),\n\t\t\t\t\ttype: 'sticker',\n\t\t\t\t\tx: point.x,\n\t\t\t\t\ty: point.y,\n\t\t\t\t\ttext: options.sticker,\n\t\t\t\t\tcolor: options.color,\n\t\t\t\t\tfontSize: options.fontSize * 2,\n\t\t\t\t\trotation: 0,\n\t\t\t\t}\n\t\t\t\tdeps.commit({ ...state, annotations: [...state.annotations, sticker] }, TOOL_LABELS.sticker)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\trefreshPreview()\n\t}\n\n\tconst onPointerMove = () => {\n\t\tif (active === null) {\n\t\t\treturn\n\t\t}\n\t\t// A second finger turned the gesture into a pinch: the stroke it\n\t\t// started belongs to nobody now\n\t\tif (deps.panning()) {\n\t\t\tdiscard()\n\t\t\treturn\n\t\t}\n\t\tconst point = scenePointer()\n\t\tif (point === null) {\n\t\t\treturn\n\t\t}\n\n\t\tswitch (active.type) {\n\t\t\tcase 'draw':\n\t\t\t\t// Grown in place: the array belongs to this gesture until\n\t\t\t\t// pointerup hands it to the committed state\n\t\t\t\tactive.points.push(point.x, point.y)\n\t\t\t\tbreak\n\t\t\tcase 'arrow':\n\t\t\t\tactive.points = [start.x, start.y, point.x, point.y]\n\t\t\t\tbreak\n\t\t\tcase 'rectangle':\n\t\t\tcase 'ellipse':\n\t\t\tcase 'redact':\n\t\t\t\tactive = {\n\t\t\t\t\t...active,\n\t\t\t\t\trect: {\n\t\t\t\t\t\tx: Math.min(start.x, point.x),\n\t\t\t\t\t\ty: Math.min(start.y, point.y),\n\t\t\t\t\t\twidth: Math.abs(point.x - start.x) || 1,\n\t\t\t\t\t\theight: Math.abs(point.y - start.y) || 1,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t}\n\t\trefreshPreview()\n\t}\n\n\tconst onPointerUp = () => {\n\t\tif (pendingText !== null) {\n\t\t\tdeps.startTextEdit(pendingText)\n\t\t\tpendingText = null\n\t\t\treturn\n\t\t}\n\t\tif (active === null) {\n\t\t\treturn\n\t\t}\n\t\tconst state = deps.getState()\n\t\tdeps.commit({ ...state, annotations: [...state.annotations, active] }, TOOL_LABELS[tool])\n\t\tdiscard()\n\t}\n\n\tdeps.stage.on('pointerdown.tool', onPointerDown)\n\tdeps.stage.on('pointermove.tool', onPointerMove)\n\tdeps.stage.on('pointerup.tool', onPointerUp)\n\t// Konva only hears about pointers over its own container, so a\n\t// release that lands anywhere else would leave the shape stranded\n\t// as a preview and lose it on the next press\n\twindow.addEventListener('pointerup', onPointerUp)\n\t// An interrupted gesture is not a finished one\n\twindow.addEventListener('pointercancel', discard)\n\n\treturn () => {\n\t\tdeps.stage.off('.tool')\n\t\twindow.removeEventListener('pointerup', onPointerUp)\n\t\twindow.removeEventListener('pointercancel', discard)\n\t\tpreviewNode?.destroy()\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<script setup lang=\"ts\">\nimport type { TransitionContext, TransitionKind, TransitionTarget } from '../editor/animate.ts'\nimport type { Tool } from '../editor/context.ts'\nimport type { CropOverlay } from '../editor/cropOverlay.ts'\nimport type { Scene, SceneOptions } from '../editor/render.ts'\nimport type { Selection } from '../editor/selection.ts'\nimport type { EditorState, Rect, Size } from '../editor/state.ts'\nimport type { ViewFit } from '../editor/view.ts'\nimport type { ExportOptions, ExportResult } from '../types/export.ts'\n\nimport Konva from 'konva'\nimport { computed, onBeforeUnmount, onMounted, ref, shallowRef, useTemplateRef, watch } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'\nimport EditorPanel from './EditorPanel.vue'\nimport EditorSidebar from './EditorSidebar.vue'\nimport EditorTopBar from './EditorTopBar.vue'\nimport SelectionToolbar from './SelectionToolbar.vue'\nimport TextOverlay from './TextOverlay.vue'\nimport { useAmbient } from '../composables/useAmbient.ts'\nimport { useAnnouncements } from '../composables/useAnnouncements.ts'\nimport { useEditorShortcuts } from '../composables/useEditorShortcuts.ts'\nimport { useExportImage } from '../composables/useExportImage.ts'\nimport { useTextEditing } from '../composables/useTextEditing.ts'\nimport { useWheelControls } from '../composables/useWheelControls.ts'\nimport { playTransition } from '../editor/animate.ts'\nimport { provideEditorCommands } from '../editor/commands.ts'\nimport { createEditorContext } from '../editor/context.ts'\nimport { attachCropOverlay } from '../editor/cropOverlay.ts'\nimport { orientImage } from '../editor/orient.ts'\nimport { createScene, toImageCoords, visibleRect } from '../editor/render.ts'\nimport { attachSelection } from '../editor/selection.ts'\nimport { clampRect, createInitialState, duplicateAnnotation, flipHorizontal, flipVertical, orientedSize, rotateCW } from '../editor/state.ts'\nimport { attachPointerTools } from '../editor/tools.ts'\nimport { clampPan, panBounds, VIEW_MARGIN } from '../editor/view.ts'\nimport { fitContain } from '../utils/geometry.ts'\nimport { loadImage } from '../utils/image.ts'\nimport { t } from '../utils/l10n.ts'\n\nconst props = defineProps<{\n\t/** Image to edit: Blob, File or URL */\n\tsrc: Blob | string\n\t/** Accessible label of the canvas area */\n\tlabel?: string\n\t/**\n\t * Format, quality and size bound for the save button. Defaults to\n\t * PNG at natural resolution, which is lossless but large: a host\n\t * saving over a photo will want its source format instead.\n\t */\n\texportOptions?: ExportOptions\n\t/**\n\t * State to open with, as emitted by the change event, for resuming\n\t * an edit that was not finished. Read when the source loads, so\n\t * changing it later has no effect until the source changes too.\n\t */\n\tinitialState?: EditorState\n}>()\n\nconst emit = defineEmits<{\n\tsave: [result: ExportResult]\n\tcancel: []\n\terror: [error: Error]\n\tchange: [state: EditorState]\n}>()\n\nconst labels = {\n\tcanvas: t('Image editor'),\n\tfailed: t('The image could not be loaded'),\n\tretry: t('Try again'),\n}\n\n/** Guards against an older load publishing over a newer one */\nlet loadAttempt = 0\n\nconst context = createEditorContext()\nconst container = useTemplateRef<HTMLDivElement>('container')\nconst loaded = ref(false)\nconst errored = ref(false)\nconst containerSize = shallowRef<Size>({ width: 0, height: 0 })\nconst orientedCanvas = shallowRef<HTMLCanvasElement | null>(null)\nconst sourceImage = shallowRef<HTMLImageElement | null>(null)\nconst { ambient, backdrop } = useAmbient(sourceImage)\nconst { panArmed } = useWheelControls(container, context)\nconst announcement = useAnnouncements(context)\n\n/** Stage-space bounds of the selected annotation, for the mini toolbar */\nconst selectionBox = shallowRef<{ x: number, y: number, width: number, height: number } | null>(null)\n\n// Konva objects are deliberately non-reactive: proxying them breaks\n// their internal caching and costs performance for no benefit.\nlet stage: Konva.Stage | null = null\nlet scene: Scene | null = null\nlet cropOverlay: CropOverlay | null = null\nlet selection: Selection | null = null\nlet detachTool: (() => void) | null = null\n// What the attached tool was built for. A view change is no reason to\n// rebuild it: tearing the crop overlay down on every render cost the\n// user the rectangle they were drawing as soon as they zoomed or the\n// container resized.\nlet attached: { tool: Tool, oriented: HTMLCanvasElement, crop: Rect | null } | null = null\nlet resizeObserver: ResizeObserver | null = null\nlet pendingTransition: { kind: TransitionKind, context: TransitionContext } | null = null\n// The view metrics of the last completed render: transition capture\n// must not read the lazy computed, it already reflects the new mode\nlet lastView: TransitionContext | null = null\n\nconst canvasCursor = computed(() => {\n\tif (context.panning.value) {\n\t\treturn 'grabbing'\n\t}\n\tif (panArmed.value) {\n\t\treturn 'grab'\n\t}\n\tconst tool = context.activeTool.value\n\tif (['draw', 'rectangle', 'ellipse', 'arrow', 'text', 'sticker', 'redact'].includes(tool)) {\n\t\treturn 'crosshair'\n\t}\n\treturn 'default'\n})\n\n/**\n * The fitted view, before the view zoom and pan apply. Published to the\n * context so the view setters clamp panning against the same metrics.\n */\nconst viewFit = computed<ViewFit | null>(() => {\n\tconst oriented = orientedCanvas.value\n\tif (oriented === null || containerSize.value.width === 0 || containerSize.value.height === 0) {\n\t\treturn null\n\t}\n\tconst showCropped = context.activeTool.value !== 'crop'\n\tconst visible = showCropped\n\t\t? visibleRect(context.state.value, { width: oriented.width, height: oriented.height })\n\t\t: { x: 0, y: 0, width: oriented.width, height: oriented.height }\n\tconst container = containerSize.value\n\t// Small stage margin so crop handles at the image edge stay visible\n\tconst fit = fitContain(\n\t\t{ width: visible.width, height: visible.height },\n\t\t{\n\t\t\twidth: Math.max(1, container.width - VIEW_MARGIN * 2),\n\t\t\theight: Math.max(1, container.height - VIEW_MARGIN * 2),\n\t\t},\n\t)\n\treturn { scale: fit.scale, visible, container, showCropped }\n})\n\nconst viewOptions = computed<SceneOptions | null>(() => {\n\tconst fit = viewFit.value\n\tif (fit === null) {\n\t\treturn null\n\t}\n\t// View zoom magnifies around the center; panning shifts the view but\n\t// content edges never pass the container edges\n\tconst scale = fit.scale * context.viewZoom.value\n\tconst pan = clampPan(context.viewPan.value, panBounds(fit.visible, scale, fit.container))\n\treturn {\n\t\tscale,\n\t\toffset: {\n\t\t\tx: (fit.container.width - fit.visible.width * scale) / 2 + pan.x,\n\t\t\ty: (fit.container.height - fit.visible.height * scale) / 2 + pan.y,\n\t\t},\n\t\tshowCropped: fit.showCropped,\n\t\tfastFilters: context.interacting.value,\n\t}\n})\n\nconst { textEdit, startTextEdit, confirmTextEdit } = useTextEditing({\n\tcontext,\n\tviewOptions: () => viewOptions.value,\n\toriented: () => orientedCanvas.value,\n})\n\nconst { exportImage, save: onSave } = useExportImage({\n\toriented: () => orientedCanvas.value,\n\tgetState: () => context.state.value,\n\tsource: () => props.src instanceof Blob ? props.src : null,\n\tsaveOptions: () => props.exportOptions ?? {},\n\tonSaved: (result) => emit('save', result),\n\tonError: (error) => emit('error', error),\n})\n\n/**\n * Snapshot the current view metrics, taken right before an animated\n * edit so the transition can start from the old view.\n */\nfunction captureView(): TransitionContext {\n\treturn lastView ?? { previousScale: 1, previousOffset: { x: 0, y: 0 }, previousOrigin: { x: 0, y: 0 } }\n}\n\n/**\n * Commit a state change and play a view transition on the rebuilt scene.\n *\n * @param kind which transition to play\n * @param next the state to commit\n * @param label what the user did, for the history list\n */\nfunction commitWithTransition(kind: TransitionKind, next: EditorState, label: string): void {\n\tpendingTransition = { kind, context: captureView() }\n\tcontext.commit(next, label)\n}\n\n/**\n * Rebuild the stage from the current state and reattach the active tool.\n */\nfunction renderView(): void {\n\tconst oriented = orientedCanvas.value\n\tconst options = viewOptions.value\n\tif (stage === null || oriented === null || options === null) {\n\t\treturn\n\t}\n\n\tstage.size(containerSize.value)\n\tscene ??= createScene(stage)\n\tscene.update(oriented, context.state.value, options)\n\n\tconst renderedOrigin = options.showCropped\n\t\t? visibleRect(context.state.value, { width: oriented.width, height: oriented.height })\n\t\t: { x: 0, y: 0 }\n\n\t// Before the transition: the overlays it carries have to exist, and\n\t// already sit where the new state puts them\n\tsyncTools(oriented, options)\n\n\tif (pendingTransition !== null) {\n\t\tconst visible = options.showCropped\n\t\t\t? visibleRect(context.state.value, { width: oriented.width, height: oriented.height })\n\t\t\t: { x: 0, y: 0, width: oriented.width, height: oriented.height }\n\t\tconst center = {\n\t\t\tx: visible.x + visible.width / 2,\n\t\t\ty: visible.y + visible.height / 2,\n\t\t}\n\t\tconst targets: TransitionTarget[] = [{\n\t\t\tnode: scene.contentGroup,\n\t\t\tpivot: center,\n\t\t\tunit: 1 / options.scale,\n\t\t}]\n\t\tif (cropOverlay !== null) {\n\t\t\t// The same point, in the stage space the overlay draws in\n\t\t\ttargets.push({\n\t\t\t\tnode: cropOverlay.layer,\n\t\t\t\tpivot: {\n\t\t\t\t\tx: options.offset.x + (center.x - renderedOrigin.x) * options.scale,\n\t\t\t\t\ty: options.offset.y + (center.y - renderedOrigin.y) * options.scale,\n\t\t\t\t},\n\t\t\t\tunit: 1,\n\t\t\t})\n\t\t}\n\t\tplayTransition(pendingTransition.kind, {\n\t\t\ttargets,\n\t\t\tscale: options.scale,\n\t\t\toffset: options.offset,\n\t\t\torigin: renderedOrigin,\n\t\t}, pendingTransition.context)\n\t\tpendingTransition = null\n\t}\n\n\tlastView = {\n\t\tpreviousScale: options.scale,\n\t\tpreviousOffset: options.offset,\n\t\tpreviousOrigin: { x: renderedOrigin.x, y: renderedOrigin.y },\n\t}\n}\n\n/**\n * Bring the attached tool in line with the rendered scene. Only a\n * different tool, a re-baked source canvas or a committed crop is a\n * reason to rebuild it; a pan, a zoom or a resize is not, and neither\n * is a commit that merely changed the annotations.\n *\n * @param oriented the orientation-baked source canvas\n * @param options the view transform just rendered\n */\nfunction syncTools(oriented: HTMLCanvasElement, options: SceneOptions): void {\n\tif (stage === null) {\n\t\treturn\n\t}\n\tconst tool = context.activeTool.value\n\tconst crop = context.state.value.crop\n\tconst fresh = attached !== null\n\t\t&& attached.tool === tool\n\t\t&& attached.oriented === oriented\n\t\t&& attached.crop === crop\n\n\tif (fresh) {\n\t\t// The scene reconciled, so the selection has to re-find its node\n\t\tselection?.sync()\n\t\tcropOverlay?.update({\n\t\t\toriented: { width: oriented.width, height: oriented.height },\n\t\t\tscale: options.scale,\n\t\t\toffset: options.offset,\n\t\t})\n\t\treturn\n\t}\n\n\tdetachTool?.()\n\tdetachTool = null\n\tselection?.detach()\n\tselection = null\n\tcropOverlay?.destroy()\n\tcropOverlay = null\n\tattached = { tool, oriented, crop }\n\n\tif (tool === 'select') {\n\t\tselection = attachSelection({\n\t\t\tstage,\n\t\t\tgetState: () => context.state.value,\n\t\t\tcommit: context.commit,\n\t\t\tselect: (id) => {\n\t\t\t\tcontext.selectedId.value = id\n\t\t\t},\n\t\t\tgetSelectedId: () => context.selectedId.value,\n\t\t\teditText: (annotation) => startTextEdit({ x: annotation.x, y: annotation.y }, annotation),\n\t\t\tonSelectionRect: (rect) => {\n\t\t\t\tselectionBox.value = rect\n\t\t\t},\n\t\t})\n\t} else if (tool === 'crop') {\n\t\tcropOverlay = attachCropOverlay({\n\t\t\tstage,\n\t\t\toriented: { width: oriented.width, height: oriented.height },\n\t\t\tscale: options.scale,\n\t\t\toffset: options.offset,\n\t\t\tinitial: crop,\n\t\t})\n\t\tapplyCropAspect()\n\t} else if (tool !== 'adjust') {\n\t\tdetachTool = attachPointerTools(tool, {\n\t\t\tstage,\n\t\t\tcontentGroup: () => scene?.contentGroup ?? null,\n\t\t\toriented: () => orientedCanvas.value,\n\t\t\tgetState: () => context.state.value,\n\t\t\tcommit: context.commit,\n\t\t\t// Read the live view: the tool outlives the transform it was\n\t\t\t// attached under\n\t\t\ttoScene: (pointer) => toImageCoords(\n\t\t\t\tpointer,\n\t\t\t\tcontext.state.value,\n\t\t\t\t{ width: oriented.width, height: oriented.height },\n\t\t\t\tviewOptions.value ?? options,\n\t\t\t),\n\t\t\tpanning: () => context.panning.value,\n\t\t\toptions: () => ({\n\t\t\t\tcolor: context.drawColor.value,\n\t\t\t\tstrokeWidth: context.strokeWidth.value,\n\t\t\t\tfontSize: context.fontSize.value,\n\t\t\t\tsticker: context.sticker.value,\n\t\t\t\tredactStyle: context.redactStyle.value,\n\t\t\t}),\n\t\t\tstartTextEdit: (position) => startTextEdit(position),\n\t\t})\n\t}\n}\n\n/**\n * Push the chosen aspect lock into the live crop overlay.\n */\nfunction applyCropAspect(): void {\n\tif (cropOverlay === null) {\n\t\treturn\n\t}\n\tconst aspect = context.cropAspect.value\n\tconst oriented = orientedCanvas.value\n\tif (aspect === 'original' && oriented !== null) {\n\t\tcropOverlay.setAspect(oriented.width / oriented.height)\n\t} else {\n\t\tcropOverlay.setAspect(typeof aspect === 'number' ? aspect : null)\n\t}\n}\n\n/**\n * Regenerate the orientation-baked canvas after rotation/flip changes.\n */\nfunction refreshOrientedCanvas(): void {\n\tif (sourceImage.value === null) {\n\t\treturn\n\t}\n\torientedCanvas.value = orientImage(sourceImage.value, context.state.value)\n}\n\n/**\n * A seeded state made safe for this image: a crop recorded against a\n * different one would otherwise leave the view outside the picture.\n *\n * @param seed the state the host handed over\n * @param image the decoded source\n */\nfunction seedState(seed: EditorState, image: HTMLImageElement): EditorState {\n\tif (seed.crop === null) {\n\t\treturn seed\n\t}\n\tconst oriented = orientedSize({ width: image.naturalWidth, height: image.naturalHeight }, seed.rotation)\n\treturn { ...seed, crop: clampRect(seed.crop, oriented) }\n}\n\n/**\n * Load the source image and reset the editing session.\n */\nasync function load(): Promise<void> {\n\t// Decoding is asynchronous, so a source switched twice in quick\n\t// succession can finish out of order. Only the newest attempt is\n\t// allowed to publish anything.\n\tconst attempt = ++loadAttempt\n\tloaded.value = false\n\terrored.value = false\n\ttry {\n\t\tconst image = await loadImage(props.src)\n\t\tif (attempt !== loadAttempt) {\n\t\t\treturn\n\t\t}\n\t\tsourceImage.value = image\n\t\tcontext.reset(props.initialState === undefined ? undefined : seedState(props.initialState, image))\n\t\t// Sensible text size relative to the image resolution\n\t\tconst minDimension = Math.min(image.naturalWidth, image.naturalHeight)\n\t\tcontext.fontSize.value = Math.min(128, Math.max(12, Math.round(minDimension / 15)))\n\t\tpendingTransition = { kind: 'load', context: captureView() }\n\t\trefreshOrientedCanvas()\n\t\tloaded.value = true\n\t} catch (error) {\n\t\tif (attempt !== loadAttempt) {\n\t\t\treturn\n\t\t}\n\t\terrored.value = true\n\t\temit('error', error instanceof Error ? error : new Error(String(error)))\n\t}\n}\n\n/**\n *\n */\nfunction currentOriented(): Size {\n\tconst oriented = orientedCanvas.value!\n\treturn { width: oriented.width, height: oriented.height }\n}\n\n/**\n * Rotate the image 90° clockwise.\n */\nfunction onRotateCW(): void {\n\tcommitWithTransition('rotate-cw', rotateCW(context.state.value, currentOriented()), t('Rotate right'))\n}\n\n/**\n * Rotate the image 90° counter-clockwise (three clockwise turns).\n */\nfunction onRotateCCW(): void {\n\tlet state = context.state.value\n\tlet oriented = currentOriented()\n\tfor (let i = 0; i < 3; i++) {\n\t\tstate = rotateCW(state, oriented)\n\t\toriented = { width: oriented.height, height: oriented.width }\n\t}\n\tcommitWithTransition('rotate-ccw', state, t('Rotate left'))\n}\n\n/**\n * Mirror the image horizontally.\n */\nfunction onFlipHorizontal(): void {\n\tcommitWithTransition('flip-h', flipHorizontal(context.state.value, currentOriented()), t('Flip horizontal'))\n}\n\n/**\n * Mirror the image vertically.\n */\nfunction onFlipVertical(): void {\n\tcommitWithTransition('flip-v', flipVertical(context.state.value, currentOriented()), t('Flip vertical'))\n}\n\n/**\n * Apply the crop overlay rect and zoom into the cropped view.\n */\nfunction onApplyCrop(): void {\n\tif (cropOverlay !== null) {\n\t\tconst crop = cropOverlay.getRect()\n\t\t// Capture before the mode switches so the zoom starts from the\n\t\t// full-image crop view\n\t\tpendingTransition = { kind: 'crop', context: captureView() }\n\t\tcontext.commit({ ...context.state.value, crop }, t('Crop'))\n\t\tcontext.setMode('annotate')\n\t}\n}\n\n/**\n * Duplicate the selected annotation and select the copy.\n */\nfunction onDuplicateSelection(): void {\n\tconst id = context.selectedId.value\n\tconst state = context.state.value\n\tconst annotation = state.annotations.find((entry) => entry.id === id)\n\tif (annotation === undefined) {\n\t\treturn\n\t}\n\tconst copy = duplicateAnnotation(annotation)\n\tcontext.commit({ ...state, annotations: [...state.annotations, copy] }, t('Duplicate'))\n\tcontext.selectedId.value = copy.id\n\trenderView()\n}\n\n/**\n * Revert every edit as one undoable step.\n */\nfunction onRevert(): void {\n\tcontext.commit(createInitialState(), t('Revert all changes'))\n}\n\n/**\n * Drop the crop and return to the full image.\n */\nfunction onResetCrop(): void {\n\tcontext.commit({ ...context.state.value, crop: null }, t('Reset crop'))\n}\n\n/**\n *\n */\nfunction onDeleteSelection(): void {\n\tconst id = context.selectedId.value\n\tif (id === null) {\n\t\treturn\n\t}\n\tconst state = context.state.value\n\tcontext.selectedId.value = null\n\tcontext.commit({\n\t\t...state,\n\t\tannotations: state.annotations.filter((annotation) => annotation.id !== id),\n\t}, t('Delete'))\n}\n\nuseEditorShortcuts({\n\tcontext,\n\tisTextEditing: () => textEdit.value !== null,\n\tonDelete: onDeleteSelection,\n\tonEscape: () => {\n\t\tif (context.selectedId.value !== null) {\n\t\t\tcontext.selectedId.value = null\n\t\t\trenderView()\n\t\t} else if (context.activeMode.value === 'crop') {\n\t\t\t// Leave crop without applying the scratch selection\n\t\t\tcontext.setMode('select')\n\t\t} else if (context.activeMode.value === 'annotate' && context.activeTool.value !== 'select') {\n\t\t\tcontext.activeTool.value = 'select'\n\t\t}\n\t},\n})\n// Published for the view setters: they clamp panning against the fit\nwatch(viewFit, (fit) => {\n\tcontext.viewFit.value = fit\n}, { immediate: true })\n\nprovideEditorCommands({\n\trotateCW: onRotateCW,\n\trotateCCW: onRotateCCW,\n\tflipHorizontal: onFlipHorizontal,\n\tflipVertical: onFlipVertical,\n\tapplyCrop: onApplyCrop,\n\tresetCrop: onResetCrop,\n\trevert: onRevert,\n})\n\nwatch(() => props.src, load)\n// Separate sources so the compare is per value: a getter returning a\n// fresh array would fire on every commit and re-bake the source canvas\nwatch(\n\t[\n\t\t() => context.state.value.rotation,\n\t\t() => context.state.value.flipX,\n\t\t() => context.state.value.flipY,\n\t\t() => context.state.value.fineRotation,\n\t\t() => context.state.value.zoom,\n\t],\n\trefreshOrientedCanvas,\n)\n// context.interacting belongs here: a slider commits the state object\n// it previewed, which a shallow ref treats as no change, so nothing\n// else would re-render the scene at full filter quality afterwards\nwatch(\n\t[context.state, context.activeTool, context.activeMode, context.viewZoom, context.viewPan, context.interacting, orientedCanvas, containerSize],\n\trenderView,\n)\nwatch(context.cropAspect, applyCropAspect)\n\n// The color control follows the selection and edits it in place.\n// Stickers keep their color field untouched: the emoji glyph never\n// shows it, and a write would only pollute the undo history.\nwatch(context.selectedId, (id) => {\n\tconst annotation = context.state.value.annotations.find((entry) => entry.id === id)\n\tif (annotation !== undefined && 'color' in annotation && annotation.type !== 'sticker') {\n\t\tcontext.drawColor.value = annotation.color\n\t}\n})\n// Only committed states are reported: a slider preview fires on every\n// pixel of the drag, and a consumer tracking changes wants the step\n// the user settled on, not the sixty on the way there. The payload is\n// a copy so a consumer cannot reach into the editor's own state.\nwatch([context.state, context.interacting], () => {\n\tif (!context.interacting.value) {\n\t\temit('change', structuredClone(context.state.value))\n\t}\n})\n\nonMounted(() => {\n\tstage = new Konva.Stage({ container: container.value!, width: 1, height: 1 })\n\tresizeObserver = new ResizeObserver(() => {\n\t\tconst { clientWidth, clientHeight } = container.value!\n\t\tcontainerSize.value = { width: clientWidth, height: clientHeight }\n\t})\n\tresizeObserver.observe(container.value!)\n\tload()\n})\n\nonBeforeUnmount(() => {\n\tresizeObserver?.disconnect()\n\tdetachTool?.()\n\tselection?.detach()\n\tcropOverlay?.destroy()\n\tscene?.destroy()\n\tscene = null\n\tstage?.destroy()\n\tstage = null\n})\n\ndefineExpose({\n\texportImage,\n\t/**\n\t * Start over, optionally from a given state.\n\t *\n\t * @param state state to reset to, defaulting to a pristine one\n\t */\n\treset: (state?: EditorState) => context.reset(state),\n})\n</script>\n\n<template>\n\t<div\n\t\tclass=\"image-editor\"\n\t\t:style=\"{\n\t\t\t'--editor-ambient': ambient,\n\t\t\t'--editor-backdrop': backdrop ? `url(${backdrop})` : 'none',\n\t\t}\">\n\t\t<div class=\"image-editor__shell\">\n\t\t\t<div class=\"image-editor__frame\">\n\t\t\t\t<div class=\"image-editor__viewport\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tref=\"container\"\n\t\t\t\t\t\tclass=\"image-editor__canvas\"\n\t\t\t\t\t\t:style=\"{ cursor: canvasCursor }\"\n\t\t\t\t\t\trole=\"img\"\n\t\t\t\t\t\t:aria-label=\"label ?? labels.canvas\" />\n\t\t\t\t\t<NcLoadingIcon\n\t\t\t\t\t\tv-if=\"!loaded && !errored\"\n\t\t\t\t\t\tclass=\"image-editor__loading\"\n\t\t\t\t\t\t:size=\"44\" />\n\t\t\t\t\t<div v-if=\"errored\" class=\"image-editor__error\" data-test=\"load-error\">\n\t\t\t\t\t\t<p>{{ labels.failed }}</p>\n\t\t\t\t\t\t<NcButton variant=\"secondary\" data-test=\"retry\" @click=\"load()\">\n\t\t\t\t\t\t\t{{ labels.retry }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t\t<TextOverlay\n\t\t\t\t\t\tv-if=\"textEdit !== null\"\n\t\t\t\t\t\t:x=\"textEdit.screenX\"\n\t\t\t\t\t\t:y=\"textEdit.screenY\"\n\t\t\t\t\t\t:font-size=\"textEdit.screenFontSize\"\n\t\t\t\t\t\t:color=\"textEdit.color\"\n\t\t\t\t\t\t:initial=\"textEdit.value\"\n\t\t\t\t\t\t@confirm=\"confirmTextEdit\"\n\t\t\t\t\t\t@cancel=\"textEdit = null\" />\n\t\t\t\t\t<SelectionToolbar\n\t\t\t\t\t\tv-if=\"selectionBox !== null\"\n\t\t\t\t\t\t:box=\"selectionBox\"\n\t\t\t\t\t\t@duplicate=\"onDuplicateSelection\"\n\t\t\t\t\t\t@delete=\"onDeleteSelection\" />\n\t\t\t\t</div>\n\n\t\t\t\t<EditorTopBar\n\t\t\t\t\tclass=\"image-editor__topbar\"\n\t\t\t\t\t:loaded=\"loaded\"\n\t\t\t\t\t@save=\"onSave\"\n\t\t\t\t\t@cancel=\"emit('cancel')\" />\n\n\t\t\t\t<EditorPanel\n\t\t\t\t\t:class=\"context.activeMode.value === 'filter'\n\t\t\t\t\t\t? 'image-editor__strip'\n\t\t\t\t\t\t: 'image-editor__controls'\"\n\t\t\t\t\t:loaded=\"loaded\"\n\t\t\t\t\t:oriented=\"orientedCanvas\" />\n\n\t\t\t\t<EditorSidebar class=\"image-editor__rail\" :loaded=\"loaded\" />\n\t\t\t\t<span class=\"hidden-visually\" role=\"status\" aria-live=\"polite\">{{ announcement }}</span>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n.image-editor {\n\t// Always-dark chrome floating over the image, every surface tinted\n\t// by the image itself: --editor-ambient carries its dominant color,\n\t// --editor-backdrop a tiny blurred copy used as the wallpaper\n\t--color-main-text: #f2f2f7;\n\t--color-main-background: #141416;\n\t--color-background-hover: rgba(255, 255, 255, 0.08);\n\t--color-background-dark: rgba(255, 255, 255, 0.14);\n\t--color-border: rgba(255, 255, 255, 0.09);\n\t--color-element-hover: rgba(255, 255, 255, 0.08);\n\t--editor-glass: rgba(20, 20, 26, 0.6);\n\t// Mirrors of the Nextcloud server constants. The component is also\n\t// embedded outside a server page, in the playground, the demo and\n\t// host apps that mount it standalone, and @nextcloud/vue sizes its\n\t// controls from --default-clickable-area with no fallback of its\n\t// own: without these the buttons collapse to their content and fall\n\t// under the minimum pointer target.\n\t--default-clickable-area: 44px;\n\t--default-grid-baseline: 4px;\n\tfont-size: 13px;\n\n\tposition: relative;\n\theight: 100%;\n\twidth: 100%;\n\toverflow: hidden;\n\tcolor: var(--color-main-text);\n\tbackground-color: var(--color-main-background);\n\t// Layout adapts to the editor's own size, not the viewport: the\n\t// component embeds in arbitrary app layouts. Note: rules for the\n\t// container itself cannot live in @container blocks, only\n\t// descendants can respond: hence the shell wrapper.\n\tcontainer: editor / size;\n\n\t&,\n\t& :deep(*),\n\t& :deep(*)::before,\n\t& :deep(*)::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t// Full-window implementation, author decision: the editor fills its\n\t// host without a floating card frame\n\t&__shell {\n\t\tposition: relative;\n\t\theight: 100%;\n\t\twidth: 100%;\n\t}\n\n\t// Blurred image wallpaper bleeding around the editor card\n\t&::before {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\tinset: -10%;\n\t\tbackground-image: var(--editor-backdrop);\n\t\tbackground-size: cover;\n\t\tbackground-position: center;\n\t\tfilter: blur(64px) saturate(1.3) brightness(0.55);\n\t\ttransform: scale(1.15);\n\t}\n\n\t&__frame {\n\t\tposition: relative;\n\t\theight: 100%;\n\t\twidth: 100%;\n\t\toverflow: hidden;\n\t\tbackground: rgba(14, 14, 18, 0.55);\n\t\tbackdrop-filter: blur(40px);\n\t}\n\n\t&__viewport {\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\t// The stage runs under the floating glass chrome; the fit margin\n\t\t// keeps interactive handles visible\n\t\tpadding: 56px 16px 16px;\n\t}\n\n\t@container editor (max-width: 600px) {\n\n\t\t&__viewport {\n\t\t\tpadding: 56px 8px 8px;\n\t\t}\n\n\t\t// Doubled class specificity so these beat the card's own sizing\n\t\t& .image-editor__controls {\n\t\t\tinset-inline: 8px;\n\t\t\ttransform: none;\n\t\t\tmin-width: 0;\n\t\t\tmax-width: none;\n\t\t\twidth: auto;\n\t\t}\n\n\t\t// The preset strip lies down above the bottom edge on phones\n\t\t& .image-editor__strip {\n\t\t\tflex-direction: row;\n\t\t\tinset-inline: 8px;\n\t\t\tinset-block-start: auto;\n\t\t\tinset-block-end: calc(var(--default-grid-baseline) * 4);\n\t\t\ttransform: none;\n\t\t\tmax-height: none;\n\t\t\toverflow-x: auto;\n\t\t\toverflow-y: hidden;\n\t\t}\n\n\t\t// Anchored under the top bar with its height capped so it can\n\t\t// never collide with the bottom control card, and given its own\n\t\t// glass backing since it floats over the image on phones.\n\t\t// Doubled class specificity so this beats the base rail rules\n\t\t// further down the sheet.\n\t\t& .image-editor__rail {\n\t\t\tinset-inline-start: var(--default-grid-baseline);\n\t\t\tinset-block-start: 64px;\n\t\t\ttransform: none;\n\t\t\tmax-height: calc(100% - 240px);\n\t\t\toverflow-y: auto;\n\t\t\tpadding: var(--default-grid-baseline);\n\t\t\tbackground: var(--editor-glass);\n\t\t\tbackdrop-filter: blur(24px) saturate(1.4);\n\t\t\tborder: 1px solid rgba(255, 255, 255, 0.09);\n\t\t\tborder-radius: var(--border-radius-large, 12px);\n\t\t}\n\t}\n\n\t&__canvas {\n\t\theight: 100%;\n\t\twidth: 100%;\n\t\t// Pinch and drag gestures belong to the editor, not the browser\n\t\ttouch-action: none;\n\t}\n\n\t&__topbar {\n\t\tposition: absolute;\n\t\tinset-block-start: 0;\n\t\tinset-inline: 0;\n\t\t// Legibility scrim over bright images\n\t\tbackground: linear-gradient(rgba(8, 8, 12, 0.5), transparent);\n\t}\n\n\t&__rail {\n\t\tposition: absolute;\n\t\tinset-inline-start: calc(var(--default-grid-baseline) * 4);\n\t\tinset-block-start: 50%;\n\t\ttransform: translateY(-50%);\n\t}\n\n\t&__controls {\n\t\tposition: absolute;\n\t\tinset-block-end: calc(var(--default-grid-baseline) * 5);\n\t\tinset-inline-start: 50%;\n\t\ttransform: translateX(-50%);\n\t}\n\n\t&__strip {\n\t\tposition: absolute;\n\t\tinset-inline-end: calc(var(--default-grid-baseline) * 4);\n\t\tinset-block-start: 50%;\n\t\ttransform: translateY(-50%);\n\t\tmax-height: calc(100% - 160px);\n\t}\n\n\t.hidden-visually {\n\t\tposition: absolute;\n\t\twidth: 1px;\n\t\theight: 1px;\n\t\toverflow: hidden;\n\t\tclip-path: inset(50%);\n\t}\n\n\t&__loading {\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\tmargin: auto;\n\t}\n\n\t// Failing silently leaves an empty frame with no way forward\n\t&__error {\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tgap: calc(var(--default-grid-baseline) * 3);\n\t\ttext-align: center;\n\t\tpadding: calc(var(--default-grid-baseline) * 4);\n\n\t\tp {\n\t\t\tmargin: 0;\n\t\t\topacity: 0.85;\n\t\t}\n\t}\n\n}\n</style>\n"],"names":["shallowRef","computed","_createElementBlock","_normalizeClass","_renderSlot","_sfc_main","_hoisted_3","_mergeProps","_createElementVNode","_openBlock","_hoisted_1","getGettextBuilder","watch","provide","inject","_hoisted_2","_Fragment","_renderList","_createVNode","_createBlock","_resolveDynamicComponent","_unref","NcButton","_normalizeStyle","_createTextVNode","_toDisplayString","luma","Konva","_hoisted_4","_hoisted_5","emojiSearch","emoji","NcEmojiPicker","showConfirmation","NcActions","NcActionButton","ref","useTemplateRef","onMounted","onBeforeUnmount","container","NcLoadingIcon"],"mappings":"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","x_google_ignoreList":[4,5,6,13,14,15,16,17,20,21,22,23,34,35,36,37,38,39,41,42,43,44,45,46,47,48,50,51]}
|