diff --git a/e2e/image-cropper.e2e.ts b/e2e/image-cropper.e2e.ts new file mode 100644 index 0000000000..6ca1ae14ef --- /dev/null +++ b/e2e/image-cropper.e2e.ts @@ -0,0 +1,360 @@ +import { test, expect } from "@playwright/test" +import { ImageCropperModel } from "./models/image-cropper.model" + +let I: ImageCropperModel + +test.describe("image-cropper / resizable", () => { + test.beforeEach(async ({ page }) => { + I = new ImageCropperModel(page) + await I.goto() + await I.waitForImageLoad() + }) + + test("should have no accessibility violation", async () => { + await I.checkAccessibility() + }) + + test("should display image and crop selection", async () => { + await I.seeImageVisible() + await I.seeSelectionVisible() + }) + + test("[pointer] should move crop selection by dragging", async () => { + const initialRect = await I.getSelectionRect() + + await I.dragSelection(50, 30) + + await I.seeSelectionPosition(initialRect.x + 50, initialRect.y + 30) + + await I.seeSelectionSize(initialRect.width, initialRect.height) + }) + + test("[pointer] should resize crop selection using corner handle", async () => { + const initialRect = await I.getSelectionRect() + + await I.dragHandle("bottom-right", 10, 15) + + await I.seeSelectionSize(initialRect.width + 10, initialRect.height + 15) + }) + + test("[pointer] should resize crop selection using side handle", async () => { + const initialRect = await I.getSelectionRect() + + await I.dragHandle("right", 20, 0) + + await I.seeSelectionSize(initialRect.width + 20, initialRect.height) + }) + + test("[pointer] should resize crop selection using top handle", async () => { + const initialRect = await I.getSelectionRect() + + await I.dragHandle("top", 0, -20) + + await I.seeSelectionSize(initialRect.width, initialRect.height + 20) + }) + + test("[zoom] should zoom in using wheel", async () => { + await I.zoomWithWheel(-100) + await I.wait(100) + + const transform = await I.getImageTransform() + const { scaleX, scaleY } = await I.getScaleFromMatrix(transform) + + expect(scaleX).toBe(1.1) + expect(scaleY).toBe(1.1) + }) + + test("[zoom] should zoom out using wheel", async () => { + await I.zoomWithWheel(-100) + await I.wait(100) + + await I.zoomWithWheel(100) + await I.wait(100) + + const transform = await I.getImageTransform() + const { scaleX, scaleY } = await I.getScaleFromMatrix(transform) + + expect(scaleX).toBe(1) + expect(scaleY).toBe(1) + }) + + test("[pan] should pan image when dragging overlay", async () => { + await I.zoomWithWheel(-100) + await I.wait(100) + + await I.panImage(50, 30) + await I.wait(100) + + const transform = await I.getImageTransform() + const { translateX, translateY } = await I.getTranslateFromMatrix(transform) + + expect(translateX).toBe(25) + expect(translateY).toBe(15) + }) + + test("[aspectRatio] should maintain aspect ratio when resizing with constraint", async () => { + await I.controls.num("aspectRatio", "1") + await I.wait(100) + + await I.dragHandle("bottom-right", 60, 60) + await I.wait(100) + + const newRect = await I.getSelectionRect() + + const aspectRatio = newRect.width / newRect.height + const expectedRatio = 1 + + expect(aspectRatio).toBe(expectedRatio) + }) + + test("[rotation] should rotate image", async () => { + await I.rotationSlider.fill("45") + + const transform = await I.getImageTransform() + const rotation = await I.getRotationFromMatrix(transform) + + expect(rotation).toBe(45) + }) + + test("[keyboard + pointer] should lock aspect ratio with shift key during resize", async () => { + const initialRect = await I.getSelectionRect() + const initialAspectRatio = initialRect.width / initialRect.height + + await I.dragHandle("bottom-right", -60, -100, { shift: true }) + await I.wait(100) + + const newRect = await I.getSelectionRect() + const newAspectRatio = newRect.width / newRect.height + + expect(newAspectRatio).toBeCloseTo(initialAspectRatio, 2) + }) + + test("[minSize] should respect minimum crop size", async () => { + await I.controls.num("minWidth", "80") + await I.controls.num("minHeight", "60") + await I.wait(100) + + await I.dragHandle("bottom-right", -500, -500) + await I.wait(100) + + const { width, height } = await I.getSelectionRect() + + expect(width).toBe(80) + expect(height).toBe(60) + }) + + test("[maxSize] should respect maximum crop size", async () => { + await I.controls.num("maxWidth", "200") + await I.controls.num("maxHeight", "150") + await I.wait(100) + + await I.dragHandle("bottom-right", 500, 500) + await I.wait(100) + + const selectionRect = await I.getSelectionRect() + const viewportRect = await I.getViewportRect() + + const expectedWidth = Math.min(200, viewportRect.width) + const expectedHeight = Math.min(150, viewportRect.height) + + expect(selectionRect.width).toBe(expectedWidth) + expect(selectionRect.height).toBe(expectedHeight) + }) + + test("[zoom] should allow programmatic zoom changes", async () => { + await I.zoomSlider.fill("2") + + const transform = await I.getImageTransform() + const { scaleX, scaleY } = await I.getScaleFromMatrix(transform) + + expect(scaleX).toBe(2) + expect(scaleY).toBe(2) + }) + + test("[keyboard] should resize corner handle diagonally with left arrow", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("top-left") + await I.pressKey("ArrowLeft") + + const newRect = await I.getSelectionRect() + + expect(newRect.x).toBe(initialRect.x - 1) + expect(newRect.y).toBe(initialRect.y - 1) + expect(newRect.width).toBe(initialRect.width + 1) + expect(newRect.height).toBe(initialRect.height + 1) + }) + + test("[keyboard] should resize corner handle diagonally with up arrow", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("top-left") + await I.pressKey("ArrowUp") + + const newRect = await I.getSelectionRect() + + expect(newRect.x).toBe(initialRect.x - 1) + expect(newRect.y).toBe(initialRect.y - 1) + expect(newRect.width).toBe(initialRect.width + 1) + expect(newRect.height).toBe(initialRect.height + 1) + }) + + test("[keyboard] should resize corner handle diagonally with right arrow", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("top-left") + await I.pressKey("ArrowRight") + + const newRect = await I.getSelectionRect() + + expect(newRect.x).toBe(initialRect.x + 1) + expect(newRect.y).toBe(initialRect.y + 1) + expect(newRect.width).toBe(initialRect.width - 1) + expect(newRect.height).toBe(initialRect.height - 1) + }) + + test("[keyboard] should resize corner handle diagonally with down arrow", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("top-left") + await I.pressKey("ArrowDown") + + const newRect = await I.getSelectionRect() + + expect(newRect.x).toBe(initialRect.x + 1) + expect(newRect.y).toBe(initialRect.y + 1) + expect(newRect.width).toBe(initialRect.width - 1) + expect(newRect.height).toBe(initialRect.height - 1) + }) + + test("[keyboard] should resize bottom-right corner handle correctly", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("bottom-right") + await I.pressKey("ArrowRight") + + const newRect = await I.getSelectionRect() + + expect(newRect.width).toBe(initialRect.width + 1) + expect(newRect.height).toBe(initialRect.height + 1) + expect(newRect.x).toBe(initialRect.x) + expect(newRect.y).toBe(initialRect.y) + }) + + test("[keyboard] should resize edge handle in single direction", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("right") + await I.pressKey("ArrowRight") + + const newRect = await I.getSelectionRect() + + expect(newRect.width).toBe(initialRect.width + 1) + expect(newRect.height).toBe(initialRect.height) + expect(newRect.x).toBe(initialRect.x) + expect(newRect.y).toBe(initialRect.y) + }) + + test("[keyboard] should use larger step with shift modifier", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("bottom-right") + await I.pressKeyWithModifiers("ArrowRight", { shift: true }) + + const newRect = await I.getSelectionRect() + + expect(newRect.width - initialRect.width).toBe(10) + expect(newRect.height - initialRect.height).toBe(10) + }) + + test("[keyboard] should use largest step with ctrl modifier", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("bottom-right") + + await I.pressKeyWithModifiers("ArrowLeft", { ctrl: true }) + + const newRect = await I.getSelectionRect() + + // Notice that newRect and initialRect are swapped since default crop area size is large + expect(initialRect.width - newRect.width).toBe(50) + expect(initialRect.height - newRect.height).toBe(50) + }) + + test("[keyboard] should use largest step with meta modifier", async () => { + const initialRect = await I.getSelectionRect() + + await I.focusHandle("bottom-right") + + await I.pressKeyWithModifiers("ArrowLeft", { meta: true }) + + const newRect = await I.getSelectionRect() + + // Notice that newRect and initialRect are swapped since default crop area size is large + expect(initialRect.width - newRect.width).toBe(50) + expect(initialRect.height - newRect.height).toBe(50) + }) + + test("[keyboard] should respect minimum size constraints", async () => { + await I.controls.num("minWidth", "100") + await I.controls.num("minHeight", "80") + + await I.focusHandle("bottom-right") + + for (let i = 0; i < 10; i++) { + await I.pressKeyWithModifiers("ArrowLeft", { ctrl: true }) + } + + const { width, height } = await I.getSelectionRect() + + expect(width).toBe(100) + expect(height).toBe(80) + }) + + test("[keyboard] should respect maximum size constraints", async () => { + await I.controls.num("maxWidth", "250") + await I.controls.num("maxHeight", "200") + + await I.focusHandle("bottom-right") + + for (let i = 0; i < 10; i++) { + await I.pressKeyWithModifiers("ArrowRight", { ctrl: true }) + } + + const { width, height } = await I.getSelectionRect() + + expect(width).toBe(250) + expect(height).toBe(200) + }) + + test("[keyboard] should not move selection outside viewport bounds", async () => { + await I.focusHandle("top-left") + + for (let i = 0; i < 10; i++) { + await I.pressKeyWithModifiers("ArrowLeft", { ctrl: true }) + } + + const selectionRect = await I.getSelectionRect() + const viewportRect = await I.getViewportRect() + + expect(viewportRect.x - selectionRect.x).toBe(0) + expect(viewportRect.y - selectionRect.y).toBe(0) + }) +}) + +test.describe("image-cropper / fixedCropArea", () => { + test.beforeEach(async ({ page }) => { + I = new ImageCropperModel(page) + await I.goto("/image-cropper-fixed") + await I.waitForImageLoad() + }) + + test("should prevent crop area from moving when fixed", async () => { + const initialRect = await I.getSelectionRect() + + await I.dragSelection(50, 30) + await I.wait(100) + + await I.seeSelectionPosition(initialRect.x, initialRect.y) + }) +}) diff --git a/e2e/models/image-cropper.model.ts b/e2e/models/image-cropper.model.ts new file mode 100644 index 0000000000..aaa268608d --- /dev/null +++ b/e2e/models/image-cropper.model.ts @@ -0,0 +1,225 @@ +import { expect, type Page } from "@playwright/test" +import { a11y, rect } from "../_utils" +import { Model } from "./model" + +export class ImageCropperModel extends Model { + constructor(public page: Page) { + super(page) + } + + checkAccessibility() { + return a11y(this.page) + } + + goto(url = "/image-cropper") { + return this.page.goto(url) + } + + get viewport() { + return this.page.locator("[data-scope='image-cropper'][data-part='viewport']") + } + + get image() { + return this.page.locator("[data-scope='image-cropper'][data-part='image']") + } + + get selection() { + return this.page.locator("[data-scope='image-cropper'][data-part='selection']") + } + + get overlay() { + return this.page.locator("[data-scope='image-cropper'][data-part='overlay']") + } + + get zoomSlider() { + return this.page.locator("input[type='range'][data-testid='zoom-slider']") + } + + get rotationSlider() { + return this.page.locator("input[type='range'][data-testid='rotation-slider']") + } + + getHandle(position: string) { + return this.page.locator(`[data-scope='image-cropper'][data-part='handle'][data-position='${position}']`) + } + + async getSelectionRect() { + const bbox = await rect(this.selection) + return bbox + } + + async getViewportRect() { + return rect(this.viewport) + } + + async getImageTransform() { + return this.image.evaluate((el) => { + const style = window.getComputedStyle(el) + return style.transform + }) + } + + async getRotationFromMatrix(transform: string) { + if (!transform || transform === "none") return 0 + + const match = transform.match(/^matrix\(([^)]+)\)$/) + if (!match) return 0 + + const values = match[1].split(",").map(parseFloat) + const [a, b] = values + + let angle = Math.atan2(b, a) * (180 / Math.PI) + if (angle < 0) angle += 360 + return angle + } + + async getScaleFromMatrix(transform: string) { + if (!transform || transform === "none") { + return { scaleX: 1, scaleY: 1 } + } + + const match = transform.match(/^matrix\(([^)]+)\)$/) + if (!match) return { scaleX: 1, scaleY: 1 } + + const values = match[1].split(",").map(parseFloat) + const [a, b, c, d] = values + + const scaleX = Math.sqrt(a * a + b * b) + const scaleY = Math.sqrt(c * c + d * d) + + return { scaleX, scaleY } + } + + async getTranslateFromMatrix(transform: string) { + if (!transform || transform === "none") { + return { translateX: 0, translateY: 0 } + } + + const match = transform.match(/^matrix\(([^)]+)\)$/) + if (!match) return { translateX: 0, translateY: 0 } + + const values = match[1].split(",").map(parseFloat) + const [, , , , e, f] = values + + return { translateX: e, translateY: f } + } + + async dragSelection(deltaX: number, deltaY: number) { + const selectionBox = await rect(this.selection) + const startX = selectionBox.midX + const startY = selectionBox.midY + + await this.page.mouse.move(startX, startY) + await this.page.mouse.down() + await this.page.mouse.move(startX + deltaX, startY + deltaY) + await this.page.mouse.up() + } + + async dragHandle(position: string, deltaX: number, deltaY: number, options?: { shift?: boolean }) { + const handle = this.getHandle(position) + const handleBox = await rect(handle) + + await this.page.mouse.move(handleBox.midX, handleBox.midY) + + if (options?.shift) { + await this.page.keyboard.down("Shift") + } + + await this.page.mouse.down() + await this.page.mouse.move(handleBox.midX + deltaX, handleBox.midY + deltaY, { steps: 10 }) + await this.page.mouse.up() + + if (options?.shift) { + await this.page.keyboard.up("Shift") + } + } + + async panImage(deltaX: number, deltaY: number) { + // Click on overlay (outside selection) to trigger pan + const viewportBox = await rect(this.viewport) + const selectionBox = await rect(this.selection) + + // Click in top-left corner of viewport, outside selection + const startX = viewportBox.x + 10 + const startY = viewportBox.y + 10 + + // Make sure we're not clicking on the selection + const isOutsideSelection = startX < selectionBox.x || startY < selectionBox.y + + if (!isOutsideSelection) { + // If selection is in top-left, use bottom-right instead + const altX = viewportBox.maxX - 10 + const altY = viewportBox.maxY - 10 + + await this.page.mouse.move(altX, altY) + await this.page.mouse.down() + await this.page.mouse.move(altX + deltaX, altY + deltaY) + await this.page.mouse.up() + } else { + await this.page.mouse.move(startX, startY) + await this.page.mouse.down() + await this.page.mouse.move(startX + deltaX, startY + deltaY) + await this.page.mouse.up() + } + } + + async zoomWithWheel(deltaY: number, point?: { x: number; y: number }) { + const viewportBox = await rect(this.viewport) + const x = point?.x ?? viewportBox.midX + const y = point?.y ?? viewportBox.midY + + await this.page.mouse.move(x, y) + await this.page.mouse.wheel(0, deltaY) + } + + async seeSelectionPosition(expectedX: number, expectedY: number) { + const bbox = await this.getSelectionRect() + expect(bbox.x).toBe(expectedX) + expect(bbox.y).toBe(expectedY) + } + + async seeSelectionSize(expectedWidth: number, expectedHeight: number) { + const bbox = await this.getSelectionRect() + expect(bbox.width).toBe(expectedWidth) + expect(bbox.height).toBe(expectedHeight) + } + + async seeSelectionVisible() { + await expect(this.selection).toBeVisible() + } + + async seeImageVisible() { + await expect(this.image).toBeVisible() + } + + async waitForImageLoad() { + await this.image.evaluate((img: HTMLImageElement) => { + if (img.complete) return + return new Promise((resolve) => { + img.onload = () => resolve(true) + }) + }) + } + + async focusHandle(position: string) { + const handle = this.getHandle(position) + await handle.focus() + } + + async pressKeyWithModifiers(key: string, options?: { shift?: boolean; ctrl?: boolean; meta?: boolean }) { + const modifiers: string[] = [] + if (options?.shift) modifiers.push("Shift") + if (options?.ctrl) modifiers.push("Control") + if (options?.meta) modifiers.push("Meta") + + for (const mod of modifiers) { + await this.page.keyboard.down(mod) + } + + await this.page.keyboard.press(key) + + for (const mod of modifiers.reverse()) { + await this.page.keyboard.up(mod) + } + } +} diff --git a/examples/next-ts/package.json b/examples/next-ts/package.json index 95b69a498f..e9498dc4ec 100644 --- a/examples/next-ts/package.json +++ b/examples/next-ts/package.json @@ -48,6 +48,7 @@ "@zag-js/hotkeys": "workspace:*", "@zag-js/hover-card": "workspace:*", "@zag-js/i18n-utils": "workspace:*", + "@zag-js/image-cropper": "workspace:*", "@zag-js/interact-outside": "workspace:*", "@zag-js/json-tree-utils": "workspace:*", "@zag-js/listbox": "workspace:*", diff --git a/examples/next-ts/pages/image-cropper-fixed.tsx b/examples/next-ts/pages/image-cropper-fixed.tsx new file mode 100644 index 0000000000..69c28ca6aa --- /dev/null +++ b/examples/next-ts/pages/image-cropper-fixed.tsx @@ -0,0 +1,68 @@ +import * as imageCropper from "@zag-js/image-cropper" +import { useMachine, normalizeProps } from "@zag-js/react" +import { imageCropperControls } from "@zag-js/shared" +import { useId, useState } from "react" +import { StateVisualizer } from "../components/state-visualizer" +import { Toolbar } from "../components/toolbar" +import { useControls } from "../hooks/use-controls" + +export default function Page() { + const controls = useControls(imageCropperControls) + const [zoom, setZoom] = useState(1) + const [rotation, setRotation] = useState(0) + + const service = useMachine(imageCropper.machine, { + id: useId(), + zoom, + onZoomChange(details) { + setZoom(details.zoom) + }, + rotation, + onRotationChange(details) { + setRotation(details.rotation) + }, + fixedCropArea: true, + ...controls.context, + }) + + const api = imageCropper.connect(service, normalizeProps) + + return ( + <> +
+
+
+ +
+
+
+ + +
+ + + + + + ) +} diff --git a/examples/next-ts/pages/image-cropper.tsx b/examples/next-ts/pages/image-cropper.tsx new file mode 100644 index 0000000000..00a01faf99 --- /dev/null +++ b/examples/next-ts/pages/image-cropper.tsx @@ -0,0 +1,76 @@ +import * as imageCropper from "@zag-js/image-cropper" +import { useMachine, normalizeProps } from "@zag-js/react" +import { imageCropperControls } from "@zag-js/shared" +import { useId, useState } from "react" +import { StateVisualizer } from "../components/state-visualizer" +import { Toolbar } from "../components/toolbar" +import { handlePositions } from "@zag-js/shared" +import { useControls } from "../hooks/use-controls" + +export default function Page() { + const controls = useControls(imageCropperControls) + const [zoom, setZoom] = useState(1) + const [rotation, setRotation] = useState(0) + + const service = useMachine(imageCropper.machine, { + id: useId(), + zoom, + onZoomChange(details) { + setZoom(details.zoom) + }, + rotation, + onRotationChange(details) { + setRotation(details.rotation) + }, + ...controls.context, + }) + + const api = imageCropper.connect(service, normalizeProps) + + return ( + <> +
+
+
+ +
+ {handlePositions.map((position) => ( +
+
+
+ ))} +
+
+
+ + +
+ + + + + + ) +} diff --git a/examples/nuxt-ts/app/pages/image-cropper-fixed.vue b/examples/nuxt-ts/app/pages/image-cropper-fixed.vue new file mode 100644 index 0000000000..9adb8620ae --- /dev/null +++ b/examples/nuxt-ts/app/pages/image-cropper-fixed.vue @@ -0,0 +1,69 @@ + + + diff --git a/examples/nuxt-ts/app/pages/image-cropper.vue b/examples/nuxt-ts/app/pages/image-cropper.vue new file mode 100644 index 0000000000..75954b7d94 --- /dev/null +++ b/examples/nuxt-ts/app/pages/image-cropper.vue @@ -0,0 +1,74 @@ + + + diff --git a/examples/nuxt-ts/package.json b/examples/nuxt-ts/package.json index ed0635121a..25193a81dd 100644 --- a/examples/nuxt-ts/package.json +++ b/examples/nuxt-ts/package.json @@ -44,6 +44,7 @@ "@zag-js/hotkeys": "workspace:*", "@zag-js/hover-card": "workspace:*", "@zag-js/i18n-utils": "workspace:*", + "@zag-js/image-cropper": "workspace:*", "@zag-js/interact-outside": "workspace:*", "@zag-js/json-tree-utils": "workspace:*", "@zag-js/listbox": "workspace:*", @@ -63,8 +64,8 @@ "@zag-js/rating-group": "workspace:*", "@zag-js/rect-utils": "workspace:*", "@zag-js/remove-scroll": "workspace:*", - "@zag-js/scroll-snap": "workspace:*", "@zag-js/scroll-area": "workspace:*", + "@zag-js/scroll-snap": "workspace:*", "@zag-js/select": "workspace:*", "@zag-js/shared": "workspace:*", "@zag-js/signature-pad": "workspace:*", diff --git a/examples/preact-ts/package.json b/examples/preact-ts/package.json index be138ebfe3..c13bf2a018 100644 --- a/examples/preact-ts/package.json +++ b/examples/preact-ts/package.json @@ -43,6 +43,7 @@ "@zag-js/hotkeys": "workspace:*", "@zag-js/hover-card": "workspace:*", "@zag-js/i18n-utils": "workspace:*", + "@zag-js/image-cropper": "workspace:*", "@zag-js/interact-outside": "workspace:*", "@zag-js/json-tree-utils": "workspace:*", "@zag-js/listbox": "workspace:*", @@ -63,8 +64,8 @@ "@zag-js/rating-group": "workspace:*", "@zag-js/rect-utils": "workspace:*", "@zag-js/remove-scroll": "workspace:*", - "@zag-js/scroll-snap": "workspace:*", "@zag-js/scroll-area": "workspace:*", + "@zag-js/scroll-snap": "workspace:*", "@zag-js/select": "workspace:*", "@zag-js/shared": "workspace:*", "@zag-js/signature-pad": "workspace:*", diff --git a/examples/solid-ts/package.json b/examples/solid-ts/package.json index bf5c6bc044..1cad37e083 100644 --- a/examples/solid-ts/package.json +++ b/examples/solid-ts/package.json @@ -47,6 +47,7 @@ "@zag-js/hotkeys": "workspace:*", "@zag-js/hover-card": "workspace:*", "@zag-js/i18n-utils": "workspace:*", + "@zag-js/image-cropper": "workspace:*", "@zag-js/interact-outside": "workspace:*", "@zag-js/json-tree-utils": "workspace:*", "@zag-js/listbox": "workspace:*", @@ -66,8 +67,8 @@ "@zag-js/rating-group": "workspace:*", "@zag-js/rect-utils": "workspace:*", "@zag-js/remove-scroll": "workspace:*", - "@zag-js/scroll-snap": "workspace:*", "@zag-js/scroll-area": "workspace:*", + "@zag-js/scroll-snap": "workspace:*", "@zag-js/select": "workspace:*", "@zag-js/shared": "workspace:*", "@zag-js/signature-pad": "workspace:*", diff --git a/examples/solid-ts/src/routes/image-cropper-fixed.tsx b/examples/solid-ts/src/routes/image-cropper-fixed.tsx new file mode 100644 index 0000000000..53d73f8787 --- /dev/null +++ b/examples/solid-ts/src/routes/image-cropper-fixed.tsx @@ -0,0 +1,70 @@ +import * as imageCropper from "@zag-js/image-cropper" +import { normalizeProps, useMachine } from "@zag-js/solid" +import { imageCropperControls } from "@zag-js/shared" +import { createMemo, createSignal, createUniqueId } from "solid-js" +import { StateVisualizer } from "~/components/state-visualizer" +import { Toolbar } from "~/components/toolbar" +import { useControls } from "~/hooks/use-controls" + +export default function Page() { + const controls = useControls(imageCropperControls) + const [zoom, setZoom] = createSignal(1) + const [rotation, setRotation] = createSignal(0) + + const service = useMachine( + imageCropper.machine, + controls.mergeProps(() => ({ + id: createUniqueId(), + zoom: zoom(), + onZoomChange(details) { + setZoom(details.zoom) + }, + rotation: rotation(), + onRotationChange(details) { + setRotation(details.rotation) + }, + fixedCropArea: true, + })), + ) + + const api = createMemo(() => imageCropper.connect(service, normalizeProps)) + + return ( + <> +
+
+
+ +
+
+
+ + +
+ + + + + + ) +} diff --git a/examples/solid-ts/src/routes/image-cropper.tsx b/examples/solid-ts/src/routes/image-cropper.tsx new file mode 100644 index 0000000000..fa6f3cd1c4 --- /dev/null +++ b/examples/solid-ts/src/routes/image-cropper.tsx @@ -0,0 +1,79 @@ +import * as imageCropper from "@zag-js/image-cropper" +import { normalizeProps, useMachine } from "@zag-js/solid" +import { imageCropperControls, handlePositions } from "@zag-js/shared" +import { For, createMemo, createSignal, createUniqueId } from "solid-js" +import { StateVisualizer } from "~/components/state-visualizer" +import { Toolbar } from "~/components/toolbar" +import { useControls } from "~/hooks/use-controls" + +export default function Page() { + const controls = useControls(imageCropperControls) + const [zoom, setZoom] = createSignal(1) + const [rotation, setRotation] = createSignal(0) + + const service = useMachine( + imageCropper.machine, + controls.mergeProps(() => ({ + id: createUniqueId(), + zoom: zoom(), + onZoomChange(details) { + setZoom(details.zoom) + }, + rotation: rotation(), + onRotationChange(details) { + setRotation(details.rotation) + }, + })), + ) + + const api = createMemo(() => imageCropper.connect(service, normalizeProps)) + + return ( + <> +
+
+
+ +
+ + {(position) => ( +
+
+
+ )} + +
+
+
+ + +
+ + + + + + ) +} diff --git a/examples/svelte-ts/package-map.json b/examples/svelte-ts/package-map.json index 9200507591..851e8c88af 100644 --- a/examples/svelte-ts/package-map.json +++ b/examples/svelte-ts/package-map.json @@ -30,8 +30,10 @@ "@zag-js/focus-trap": "../../packages/utilities/focus-trap/src", "@zag-js/focus-visible": "../../packages/utilities/focus-visible/src", "@zag-js/highlight-word": "../../packages/utilities/highlight-word/src", + "@zag-js/hotkeys": "../../packages/utilities/hotkeys/src", "@zag-js/hover-card": "../../packages/machines/hover-card/src", "@zag-js/i18n-utils": "../../packages/utilities/i18n-utils/src", + "@zag-js/image-cropper": "../../packages/machines/image-cropper/src", "@zag-js/interact-outside": "../../packages/utilities/interact-outside/src", "@zag-js/json-tree-utils": "../../packages/utilities/json-tree-utils/src", "@zag-js/listbox": "../../packages/machines/listbox/src", @@ -51,8 +53,8 @@ "@zag-js/rating-group": "../../packages/machines/rating-group/src", "@zag-js/rect-utils": "../../packages/utilities/rect/src", "@zag-js/remove-scroll": "../../packages/utilities/remove-scroll/src", - "@zag-js/scroll-snap": "../../packages/utilities/scroll-snap/src", "@zag-js/scroll-area": "../../packages/machines/scroll-area/src", + "@zag-js/scroll-snap": "../../packages/utilities/scroll-snap/src", "@zag-js/select": "../../packages/machines/select/src", "@zag-js/shared": "../../shared/src", "@zag-js/signature-pad": "../../packages/machines/signature-pad/src", diff --git a/examples/svelte-ts/package.json b/examples/svelte-ts/package.json index 6aec5773b7..6eb90b3419 100644 --- a/examples/svelte-ts/package.json +++ b/examples/svelte-ts/package.json @@ -48,6 +48,7 @@ "@zag-js/hotkeys": "workspace:*", "@zag-js/hover-card": "workspace:*", "@zag-js/i18n-utils": "workspace:*", + "@zag-js/image-cropper": "workspace:*", "@zag-js/interact-outside": "workspace:*", "@zag-js/json-tree-utils": "workspace:*", "@zag-js/listbox": "workspace:*", @@ -67,8 +68,8 @@ "@zag-js/rating-group": "workspace:*", "@zag-js/rect-utils": "workspace:*", "@zag-js/remove-scroll": "workspace:*", - "@zag-js/scroll-snap": "workspace:*", "@zag-js/scroll-area": "workspace:*", + "@zag-js/scroll-snap": "workspace:*", "@zag-js/select": "workspace:*", "@zag-js/shared": "workspace:*", "@zag-js/signature-pad": "workspace:*", diff --git a/examples/svelte-ts/src/routes/image-cropper-fixed/+page.svelte b/examples/svelte-ts/src/routes/image-cropper-fixed/+page.svelte new file mode 100644 index 0000000000..6907dac810 --- /dev/null +++ b/examples/svelte-ts/src/routes/image-cropper-fixed/+page.svelte @@ -0,0 +1,71 @@ + + +
+
+
+ Cropper +
+
+
+ + +
+ + + + diff --git a/examples/svelte-ts/src/routes/image-cropper/+page.svelte b/examples/svelte-ts/src/routes/image-cropper/+page.svelte new file mode 100644 index 0000000000..8af3f482df --- /dev/null +++ b/examples/svelte-ts/src/routes/image-cropper/+page.svelte @@ -0,0 +1,78 @@ + + +
+
+
+ Cropper +
+ {#each handlePositions as position} +
+
+
+ {/each} +
+
+
+ + +
+ + + + diff --git a/examples/vanilla-ts/package.json b/examples/vanilla-ts/package.json index 8357892f81..f8dd52adfe 100644 --- a/examples/vanilla-ts/package.json +++ b/examples/vanilla-ts/package.json @@ -48,6 +48,7 @@ "@zag-js/hotkeys": "workspace:*", "@zag-js/hover-card": "workspace:*", "@zag-js/i18n-utils": "workspace:*", + "@zag-js/image-cropper": "workspace:*", "@zag-js/interact-outside": "workspace:*", "@zag-js/json-tree-utils": "workspace:*", "@zag-js/listbox": "workspace:*", @@ -67,8 +68,8 @@ "@zag-js/rating-group": "workspace:*", "@zag-js/rect-utils": "workspace:*", "@zag-js/remove-scroll": "workspace:*", - "@zag-js/scroll-snap": "workspace:*", "@zag-js/scroll-area": "workspace:*", + "@zag-js/scroll-snap": "workspace:*", "@zag-js/select": "workspace:*", "@zag-js/shared": "workspace:*", "@zag-js/signature-pad": "workspace:*", diff --git a/packages/machines/image-cropper/README.md b/packages/machines/image-cropper/README.md new file mode 100644 index 0000000000..4555d98ae8 --- /dev/null +++ b/packages/machines/image-cropper/README.md @@ -0,0 +1,19 @@ +# @zag-js/image-cropper + +Core logic for the image-cropper widget implemented as a state machine + +## Installation + +```sh +yarn add @zag-js/image-cropper +# or +npm i @zag-js/image-cropper +``` + +## Contribution + +Yes please! See the [contributing guidelines](https://github.com/chakra-ui/zag/blob/main/CONTRIBUTING.md) for details. + +## License + +This project is licensed under the terms of the [MIT license](https://github.com/chakra-ui/zag/blob/main/LICENSE). diff --git a/packages/machines/image-cropper/package.json b/packages/machines/image-cropper/package.json new file mode 100644 index 0000000000..3c4011a2e1 --- /dev/null +++ b/packages/machines/image-cropper/package.json @@ -0,0 +1,48 @@ +{ + "name": "@zag-js/image-cropper", + "version": "0.0.0", + "description": "Core logic for the image-cropper widget implemented as a state machine", + "keywords": [ + "js", + "machine", + "xstate", + "statechart", + "component", + "chakra-ui", + "image-cropper" + ], + "author": "Segun Adebayo ", + "homepage": "https://github.com/chakra-ui/zag#readme", + "license": "MIT", + "main": "src/index.ts", + "repository": "https://github.com/chakra-ui/zag/tree/main/packages/image-cropper", + "sideEffects": false, + "files": [ + "dist", + "src" + ], + "scripts": { + "build": "tsup", + "lint": "eslint src", + "typecheck": "tsc --noEmit", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "publishConfig": { + "access": "public" + }, + "bugs": { + "url": "https://github.com/chakra-ui/zag/issues" + }, + "dependencies": { + "@zag-js/anatomy": "workspace:*", + "@zag-js/core": "workspace:*", + "@zag-js/dom-query": "workspace:*", + "@zag-js/types": "workspace:*", + "@zag-js/utils": "workspace:*" + }, + "devDependencies": { + "clean-package": "2.2.0" + }, + "clean-package": "../../../clean-package.config.json" +} diff --git a/packages/machines/image-cropper/src/image-cropper.anatomy.ts b/packages/machines/image-cropper/src/image-cropper.anatomy.ts new file mode 100644 index 0000000000..60d9914b20 --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.anatomy.ts @@ -0,0 +1,5 @@ +import { createAnatomy } from "@zag-js/anatomy" + +export const anatomy = createAnatomy("image-cropper").parts("root", "viewport", "image", "selection", "handle") + +export const parts = anatomy.build() diff --git a/packages/machines/image-cropper/src/image-cropper.connect.ts b/packages/machines/image-cropper/src/image-cropper.connect.ts new file mode 100644 index 0000000000..da1fe130ff --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.connect.ts @@ -0,0 +1,229 @@ +import type { EventKeyMap, NormalizeProps, PropTypes } from "@zag-js/types" +import { parts } from "./image-cropper.anatomy" +import * as dom from "./image-cropper.dom" +import type { ImageCropperApi, ImageCropperService } from "./image-cropper.types" +import { getEventPoint, contains, getEventKey } from "@zag-js/dom-query" +import { toPx } from "@zag-js/utils" + +export function connect( + service: ImageCropperService, + normalize: NormalizeProps, +): ImageCropperApi { + const { scope, send, context, prop } = service + + const shouldIgnoreTouchPointer = (event: { pointerType?: string; isPrimary?: boolean }) => { + if (event.pointerType !== "touch") return false + const isSecondaryTouch = event.isPrimary === false + const pinchActive = context.get("pinchDistance") != null + return isSecondaryTouch || pinchActive + } + + return { + setZoom(zoom) { + send({ type: "SET_ZOOM", zoom }) + }, + + setRotation(rotation) { + send({ type: "SET_ROTATION", rotation }) + }, + + getRootProps() { + return normalize.element({ + ...parts.root.attrs, + id: dom.getRootId(scope), + }) + }, + + getViewportProps() { + const fixedCropArea = prop("fixedCropArea") + + return normalize.element({ + ...parts.viewport.attrs, + id: dom.getViewportId(scope), + onPointerDown(event) { + if (event.pointerType === "mouse" && event.button !== 0) return + + if (shouldIgnoreTouchPointer(event)) return + + const target = event.target as HTMLElement | null + const rootEl = dom.getRootEl(scope) + if (!target || !rootEl || !contains(rootEl, target)) return + + const selectionEl = dom.getSelectionEl(scope) + + if (!fixedCropArea && contains(selectionEl, target)) return + + const handleEl = target.closest('[data-scope="image-cropper"][data-part="handle"]') as HTMLElement | null + if (handleEl && contains(rootEl, handleEl)) return + + const point = getEventPoint(event) + send({ type: "PAN_POINTER_DOWN", point }) + }, + onWheel(event) { + const viewportEl = event.currentTarget + if (!viewportEl) return + const rect = viewportEl.getBoundingClientRect() + const point = { + x: event.clientX - rect.left, + y: event.clientY - rect.top, + } + send({ type: "ZOOM", trigger: "wheel", delta: event.deltaY, point }) + }, + onTouchStart(event) { + if (event.touches.length >= 2) { + const touches = Array.from(event.touches).map((touch) => ({ + x: touch.clientX, + y: touch.clientY, + })) + + send({ type: "PINCH_START", touches }) + } + }, + onTouchMove(event) { + if (event.touches.length >= 2) { + event.preventDefault() + + const touches = Array.from(event.touches).map((touch) => ({ + x: touch.clientX, + y: touch.clientY, + })) + + send({ type: "PINCH_MOVE", touches }) + } + }, + + onTouchEnd(event) { + if (event.touches.length < 2) { + send({ type: "PINCH_END" }) + } + }, + }) + }, + + getImageProps() { + const zoom = context.get("zoom") + const offset = context.get("offset") + const rotation = context.get("rotation") + + const translate = `translate(${toPx(offset.x)}, ${toPx(offset.y)})` + const rotate = `rotate(${rotation}deg)` + const scale = `scale(${zoom})` + + return normalize.element({ + ...parts.image.attrs, + id: dom.getImageId(scope), + draggable: false, + "aria-hidden": true, + onLoad(event) { + const imageEl = event.currentTarget as HTMLImageElement + if (!imageEl?.complete) return + const { naturalWidth: width, naturalHeight: height } = imageEl + send({ type: "SET_NATURAL_SIZE", src: "element", size: { width, height } }) + }, + style: { + transform: `${translate} ${rotate} ${scale}`, + }, + }) + }, + + getSelectionProps() { + const crop = context.get("crop") + + return normalize.element({ + ...parts.selection.attrs, + id: dom.getSelectionId(scope), + tabIndex: 0, + role: "slider", + "aria-label": "Crop selection area", + style: { + "--width": toPx(crop.width), + "--height": toPx(crop.height), + "--x": toPx(crop.x), + "--y": toPx(crop.y), + top: "var(--y)", + left: "var(--x)", + width: "var(--width)", + height: "var(--height)", + }, + onPointerDown(event) { + if (shouldIgnoreTouchPointer(event)) return + const point = getEventPoint(event) + send({ type: "POINTER_DOWN", point }) + }, + onKeyDown(event) { + if (event.defaultPrevented) return + const src = "selection" + const { shiftKey, ctrlKey, metaKey } = event + const keyMap: EventKeyMap = { + ArrowUp() { + send({ type: "NUDGE_MOVE_CROP", key: "ArrowUp", src, shiftKey, ctrlKey, metaKey }) + }, + ArrowDown() { + send({ type: "NUDGE_MOVE_CROP", key: "ArrowDown", src, shiftKey, ctrlKey, metaKey }) + }, + ArrowLeft() { + send({ type: "NUDGE_MOVE_CROP", key: "ArrowLeft", src, shiftKey, ctrlKey, metaKey }) + }, + ArrowRight() { + send({ type: "NUDGE_MOVE_CROP", key: "ArrowRight", src, shiftKey, ctrlKey, metaKey }) + }, + } + + const key = getEventKey(event, { dir: prop("dir") }) + const exec = keyMap[key] + + if (exec) { + exec(event) + event.preventDefault() + } + }, + }) + }, + + getHandleProps(props) { + const handlePosition = props.position + + return normalize.element({ + ...parts.handle.attrs, + id: dom.getHandleId(scope, handlePosition), + "data-position": handlePosition, + tabIndex: 0, + role: "slider", + "aria-label": `Resize handle for ${handlePosition} corner`, + onPointerDown(event) { + if (shouldIgnoreTouchPointer(event)) return + const point = getEventPoint(event) + + send({ type: "POINTER_DOWN", point, handlePosition }) + }, + onKeyDown(event) { + if (event.defaultPrevented) return + const src = "handle" + const { shiftKey, ctrlKey, metaKey } = event + const keyMap: EventKeyMap = { + ArrowUp() { + send({ type: "NUDGE_RESIZE_CROP", handlePosition, key: "ArrowUp", src, shiftKey, ctrlKey, metaKey }) + }, + ArrowDown() { + send({ type: "NUDGE_RESIZE_CROP", handlePosition, key: "ArrowDown", src, shiftKey, ctrlKey, metaKey }) + }, + ArrowLeft() { + send({ type: "NUDGE_RESIZE_CROP", handlePosition, key: "ArrowLeft", src, shiftKey, ctrlKey, metaKey }) + }, + ArrowRight() { + send({ type: "NUDGE_RESIZE_CROP", handlePosition, key: "ArrowRight", src, shiftKey, ctrlKey, metaKey }) + }, + } + + const key = getEventKey(event, { dir: prop("dir") }) + const exec = keyMap[key] + + if (exec) { + exec(event) + event.preventDefault() + } + }, + }) + }, + } +} diff --git a/packages/machines/image-cropper/src/image-cropper.dom.ts b/packages/machines/image-cropper/src/image-cropper.dom.ts new file mode 100644 index 0000000000..ae6364a862 --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.dom.ts @@ -0,0 +1,14 @@ +import type { Scope } from "@zag-js/core" + +export const getRootId = (ctx: Scope) => ctx.ids?.root ?? `image-cropper:${ctx.id}` +export const getViewportId = (ctx: Scope) => ctx.ids?.viewport ?? `image-cropper:${ctx.id}:viewport` +export const getImageId = (ctx: Scope) => ctx.ids?.image ?? `image-cropper:${ctx.id}:image` +export const getSelectionId = (ctx: Scope) => ctx.ids?.selection ?? `image-cropper:${ctx.id}:selection` +export const getHandleId = (ctx: Scope, position: string) => + ctx.ids?.handle?.(position) ?? `image-cropper:${ctx.id}:handle:${position}` + +export const getRootEl = (ctx: Scope) => ctx.getById(getRootId(ctx)) +export const getViewportEl = (ctx: Scope) => ctx.getById(getViewportId(ctx)) +export const getImageEl = (ctx: Scope) => ctx.getById(getImageId(ctx)) +export const getSelectionEl = (ctx: Scope) => ctx.getById(getSelectionId(ctx)) +export const getHandleEl = (ctx: Scope, position: string) => ctx.getById(getHandleId(ctx, position)) diff --git a/packages/machines/image-cropper/src/image-cropper.machine.ts b/packages/machines/image-cropper/src/image-cropper.machine.ts new file mode 100644 index 0000000000..800ad40a1b --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.machine.ts @@ -0,0 +1,712 @@ +import { createMachine } from "@zag-js/core" +import * as dom from "./image-cropper.dom" +import type { HandlePosition, ImageCropperSchema } from "./image-cropper.types" +import type { Point, Rect, Size } from "@zag-js/types" +import { addDomEvent, getEventPoint, getEventTarget } from "@zag-js/dom-query" +import { + clampOffset, + computeKeyboardCrop, + computeMoveCrop, + computeResizeCrop, + getKeyboardMoveDelta, +} from "./image-cropper.utils" +import { clampValue } from "@zag-js/utils" + +export const machine = createMachine({ + props({ props }) { + return { + minWidth: 40, + minHeight: 40, + maxWidth: Number.POSITIVE_INFINITY, + maxHeight: Number.POSITIVE_INFINITY, + defaultZoom: 1, + zoomStep: 0.1, + zoomSensitivity: 2, + minZoom: 1, + maxZoom: 5, + defaultRotation: 0, + fixedCropArea: false, + nudgeStep: 1, + nudgeStepShift: 10, + nudgeStepCtrl: 50, + ...props, + } + }, + + context({ bindable, prop }) { + return { + naturalSize: bindable(() => ({ + defaultValue: { width: 0, height: 0 }, + })), + crop: bindable(() => ({ + defaultValue: { x: 0, y: 0, width: 0, height: 0 }, + })), + pointerStart: bindable(() => ({ + defaultValue: null, + })), + cropStart: bindable(() => ({ + defaultValue: null, + })), + handlePosition: bindable(() => ({ + defaultValue: null, + })), + shiftLockRatio: bindable(() => ({ + defaultValue: null, + })), + pinchDistance: bindable(() => ({ + defaultValue: null, + })), + pinchMidpoint: bindable(() => ({ + defaultValue: null, + })), + zoom: bindable(() => ({ + defaultValue: prop("defaultZoom"), + value: prop("zoom"), + onChange(zoom) { + prop("onZoomChange")?.({ zoom }) + }, + })), + rotation: bindable(() => ({ + defaultValue: prop("defaultRotation"), + value: prop("rotation"), + onChange(rotation) { + prop("onRotationChange")?.({ rotation }) + }, + })), + offset: bindable(() => ({ + defaultValue: { x: 0, y: 0 }, + })), + offsetStart: bindable(() => ({ + defaultValue: null, + })), + viewportRect: bindable<{ + width: number + height: number + top: number + left: number + right: number + bottom: number + }>(() => ({ + defaultValue: { width: 0, height: 0, top: 0, left: 0, right: 0, bottom: 0 }, + })), + } + }, + + initialState() { + return "idle" + }, + + on: { + PINCH_START: { + actions: ["setPinchDistance"], + }, + PINCH_MOVE: { + actions: ["handlePinchMove"], + }, + PINCH_END: { + actions: ["clearPinchDistance"], + }, + SET_ZOOM: { + actions: ["updateZoom"], + }, + SET_ROTATION: { + actions: ["setRotation"], + }, + }, + + states: { + idle: { + entry: ["checkImageStatus"], + on: { + SET_NATURAL_SIZE: { + actions: ["setNaturalSize"], + }, + SET_DEFAULT_CROP: { + actions: ["setDefaultCrop"], + }, + POINTER_DOWN: { + guard: "canDragSelection", + target: "dragging", + actions: ["setPointerStart", "setCropStart", "setHandlePosition"], + }, + PAN_POINTER_DOWN: { + guard: "canPan", + target: "panning", + actions: ["setPointerStart", "setOffsetStart"], + }, + ZOOM: { + guard: "hasViewportRect", + actions: ["updateZoom"], + }, + NUDGE_RESIZE_CROP: { + guard: "hasViewportRect", + actions: ["nudgeResizeCrop"], + }, + NUDGE_MOVE_CROP: { + guard: "hasViewportRect", + actions: ["nudgeMoveCrop"], + }, + }, + }, + + dragging: { + effects: ["trackPointerMove"], + on: { + POINTER_MOVE: { + actions: ["updateCrop"], + }, + POINTER_UP: { + target: "idle", + actions: [ + "clearPointerStart", + "clearCropStart", + "clearHandlePosition", + "clearOffsetStart", + "clearShiftRatio", + ], + }, + }, + }, + + panning: { + effects: ["trackPointerMove"], + on: { + POINTER_MOVE: { + actions: ["updatePanOffset"], + }, + POINTER_UP: { + target: "idle", + actions: ["clearPointerStart", "clearOffsetStart"], + }, + }, + }, + }, + + implementations: { + guards: { + hasViewportRect({ context }) { + const viewportRect = context.get("viewportRect") + return viewportRect.width > 0 && viewportRect.height > 0 + }, + canPan({ context }) { + const naturalSize = context.get("naturalSize") + if (naturalSize.width <= 0 || naturalSize.height <= 0) return false + const viewportRect = context.get("viewportRect") + return viewportRect.width > 0 && viewportRect.height > 0 + }, + canDragSelection({ context, prop }) { + const viewportRect = context.get("viewportRect") + const hasViewportRect = viewportRect.width > 0 && viewportRect.height > 0 + const isNotFixed = !prop("fixedCropArea") + return hasViewportRect && isNotFixed + }, + }, + + actions: { + checkImageStatus({ send, scope, context }) { + const naturalSize = context.get("naturalSize") + const imageEl = dom.getImageEl(scope) + if (!imageEl?.complete) return + + const { naturalWidth: width, naturalHeight: height } = imageEl + + if (width !== 0 && height !== 0 && naturalSize.width === 0 && naturalSize.height === 0) { + send({ type: "SET_NATURAL_SIZE", src: "ssr", size: { width, height } }) + } + }, + + setNaturalSize({ event, context, send }) { + context.set("naturalSize", event.size) + send({ type: "SET_DEFAULT_CROP", src: "init" }) + }, + + setDefaultCrop({ context, prop, scope }) { + const viewportEl = dom.getViewportEl(scope) + if (!viewportEl) return + const viewportRect = viewportEl.getBoundingClientRect() + if (viewportRect.height <= 0 || viewportRect.width <= 0) return + + const aspectRatio = prop("aspectRatio") + const minSize = { width: prop("minWidth"), height: prop("minHeight") } + const maxSize = { width: prop("maxWidth"), height: prop("maxHeight") } + + const clampSize = (rect: Rect) => { + const result = computeResizeCrop({ + cropStart: rect, + handlePosition: "bottom-right", + delta: { x: 0, y: 0 }, + viewportRect, + minSize, + maxSize, + aspectRatio, + }) + + return { width: result.width, height: result.height } + } + + const initialCrop = prop("initialCrop") + if (initialCrop) { + const constrainedSize = clampSize({ + x: 0, + y: 0, + width: initialCrop.width, + height: initialCrop.height, + }) + + const width = constrainedSize.width + const height = constrainedSize.height + const maxX = Math.max(0, viewportRect.width - width) + const maxY = Math.max(0, viewportRect.height - height) + const x = clampValue(initialCrop.x, 0, maxX) + const y = clampValue(initialCrop.y, 0, maxY) + + context.set("crop", { x, y, width, height }) + return + } + + const fixedCropArea = prop("fixedCropArea") + + const targetWidth = viewportRect.width * 0.8 + const targetHeight = viewportRect.height * 0.8 + + let width: number + let height: number + + if (typeof aspectRatio === "number" && aspectRatio > 0) { + if (fixedCropArea) { + height = viewportRect.height + width = height * aspectRatio + + // If calculated width exceeds viewport, scale down proportionally + if (width > viewportRect.width) { + width = viewportRect.width + height = width / aspectRatio + } + } else { + const targetAspect = targetWidth / targetHeight + + if (aspectRatio > targetAspect) { + width = targetWidth + height = width / aspectRatio + } else { + height = targetHeight + width = height * aspectRatio + } + } + } else { + if (fixedCropArea) { + const size = Math.min(viewportRect.width, viewportRect.height) + width = size + height = size + } else { + width = targetWidth + height = targetHeight + } + } + + const constrainedSize = clampSize({ + x: 0, + y: 0, + width, + height, + }) + + width = constrainedSize.width + height = constrainedSize.height + + const x = Math.max(0, (viewportRect.width - width) / 2) + const y = Math.max(0, (viewportRect.height - height) / 2) + + context.set("crop", { x, y, width, height }) + context.set("viewportRect", viewportRect) + }, + + setPointerStart({ event, context }) { + const point = event.point + if (!point) return + + context.set("pointerStart", point) + }, + + setOffsetStart({ context }) { + const offset = context.get("offset") + context.set("offsetStart", { x: offset.x, y: offset.y }) + }, + + setCropStart({ context }) { + const crop = context.get("crop") + context.set("cropStart", crop) + }, + + updateCrop({ context, event, prop }) { + const minWidth = prop("minWidth") + const minHeight = prop("minHeight") + const maxWidth = prop("maxWidth") + const maxHeight = prop("maxHeight") + const handlePosition = context.get("handlePosition") + const pointerStart = context.get("pointerStart") + const cropStart = context.get("cropStart") + const viewportRect = context.get("viewportRect") + let aspectRatio = prop("aspectRatio") + + const currentPoint = event.point + + if (!pointerStart || !cropStart) return + + const delta = { x: currentPoint.x - pointerStart.x, y: currentPoint.y - pointerStart.y } + + let nextCrop + if (handlePosition) { + if (typeof aspectRatio === "undefined") { + if (event.shiftKey) { + const currentCrop = context.get("crop") + const w = currentCrop.width + const h = currentCrop.height + if (w > 0 && h > 0) { + const ratio = w / h + if (ratio > 0) context.set("shiftLockRatio", ratio) + } + } + + if (event.shiftKey) { + const lockRatio = context.get("shiftLockRatio") + if (lockRatio !== null && lockRatio > 0) aspectRatio = lockRatio + } else { + context.set("shiftLockRatio", null) + } + } + nextCrop = computeResizeCrop({ + cropStart, + handlePosition, + delta, + viewportRect: viewportRect, + minSize: { width: minWidth, height: minHeight }, + maxSize: { width: maxWidth, height: maxHeight }, + aspectRatio, + }) + } else { + nextCrop = computeMoveCrop(cropStart, delta, viewportRect) + } + + context.set("crop", nextCrop) + }, + + updatePanOffset({ context, event, prop }) { + const point = event.point + const pointerStart = context.get("pointerStart") + const offsetStart = context.get("offsetStart") + + if (!point || !pointerStart || !offsetStart) return + + const zoom = context.get("zoom") + const rotation = context.get("rotation") + const viewportRect = context.get("viewportRect") + + const deltaX = point.x - pointerStart.x + const deltaY = point.y - pointerStart.y + + const nextOffset = clampOffset({ + zoom, + rotation, + viewportRect, + offset: { + x: offsetStart.x + deltaX, + y: offsetStart.y + deltaY, + }, + fixedCropArea: prop("fixedCropArea"), + crop: context.get("crop"), + naturalSize: context.get("naturalSize"), + }) + + context.set("offset", nextOffset) + }, + + setHandlePosition({ event, context }) { + const position = event.handlePosition + if (!position) return + context.set("handlePosition", position) + }, + + setRotation({ context, event }) { + const rotation = event.rotation + const nextRotation = clampValue(rotation, 0, 360) + context.set("rotation", nextRotation) + }, + + clearPointerStart({ context }) { + context.set("pointerStart", null) + }, + + clearCropStart({ context }) { + context.set("cropStart", null) + }, + + clearHandlePosition({ context }) { + context.set("handlePosition", null) + }, + + clearOffsetStart({ context }) { + context.set("offsetStart", null) + }, + + clearShiftRatio({ context }) { + context.set("shiftLockRatio", null) + }, + + updateZoom({ context, event, prop }) { + let { delta, point, zoom: targetZoom, scale, panDelta } = event + + // If no point is specified, zoom based on the center of the crop area + if (!point) { + const crop = context.get("crop") + point = { x: crop.x + crop.width / 2, y: crop.y + crop.height / 2 } + } + + const step = Math.abs(prop("zoomStep")) + const sensitivity = Math.max(0, prop("zoomSensitivity")) + const [minZoom, maxZoom] = [prop("minZoom"), prop("maxZoom")] + const currentZoom = context.get("zoom") + const viewportRect = context.get("viewportRect") + + let nextZoom + + if (typeof targetZoom === "number") { + nextZoom = clampValue(targetZoom, minZoom, maxZoom) + } else if (event.trigger === "touch" && typeof scale === "number") { + const minScale = 0.5 + const maxScale = 2 + const clampedScale = clampValue(scale, minScale, maxScale) + const smoothing = sensitivity > 0 ? Math.pow(clampedScale, sensitivity) : clampedScale + nextZoom = clampValue(currentZoom * smoothing, minZoom, maxZoom) + } else if (typeof delta === "number") { + const direction = Math.sign(delta) < 0 ? 1 : -1 + nextZoom = clampValue(currentZoom + step * direction, minZoom, maxZoom) + } else { + return + } + + // Only pan if there's a pan delta from pinch movement + if (nextZoom === currentZoom && panDelta) { + const currentOffset = context.get("offset") + const rotation = context.get("rotation") + + const nextOffset = clampOffset({ + zoom: currentZoom, + rotation, + viewportRect: viewportRect, + offset: { + x: currentOffset.x + panDelta.x, + y: currentOffset.y + panDelta.y, + }, + fixedCropArea: prop("fixedCropArea"), + crop: context.get("crop"), + naturalSize: context.get("naturalSize"), + }) + + context.set("offset", nextOffset) + return + } + + if (nextZoom === currentZoom) return + + const { width: vpW, height: vpH } = viewportRect + const centerX = vpW / 2 + const centerY = vpH / 2 + + const currentOffset = context.get("offset") + + const ratio = nextZoom / currentZoom + let nextOffset = { + x: (1 - ratio) * (point.x - centerX) + ratio * currentOffset.x, + y: (1 - ratio) * (point.y - centerY) + ratio * currentOffset.y, + } + + // Apply pan delta from pinch movement if provided + if (panDelta) { + nextOffset.x += panDelta.x + nextOffset.y += panDelta.y + + const rotation = context.get("rotation") + nextOffset = clampOffset({ + zoom: nextZoom, + rotation, + viewportRect: viewportRect, + offset: nextOffset, + fixedCropArea: prop("fixedCropArea"), + crop: context.get("crop"), + naturalSize: context.get("naturalSize"), + }) + } else if (nextZoom < currentZoom) { + if (prop("fixedCropArea")) { + const rotation = context.get("rotation") + nextOffset = clampOffset({ + zoom: nextZoom, + rotation, + viewportRect: viewportRect, + offset: nextOffset, + fixedCropArea: true, + crop: context.get("crop"), + naturalSize: context.get("naturalSize"), + }) + } else { + const imgSize = context.get("naturalSize") + const scaledW = imgSize.width * nextZoom + const scaledH = imgSize.height * nextZoom + + if (scaledW <= vpW) { + nextOffset.x = 0 + } else { + const minX = vpW - centerX - scaledW / 2 + const maxX = scaledW / 2 - centerX + nextOffset.x = Math.max(minX, Math.min(maxX, nextOffset.x)) + } + + if (scaledH <= vpH) { + nextOffset.y = 0 + } else { + const minY = vpH - centerY - scaledH / 2 + const maxY = scaledH / 2 - centerY + nextOffset.y = Math.max(minY, Math.min(maxY, nextOffset.y)) + } + } + } + + context.set("zoom", nextZoom) + context.set("offset", nextOffset) + }, + + setPinchDistance({ context, event, send }) { + const touches = Array.isArray(event.touches) ? event.touches : [] + if (touches.length < 2) return + if (context.get("pointerStart") !== null) { + send({ type: "POINTER_UP", src: "pinch" }) + } + const [first, second] = touches + const dx = first.x - second.x + const dy = first.y - second.y + const distance = Math.hypot(dx, dy) + + const viewportRect = context.get("viewportRect") + const midpoint = { + x: (first.x + second.x) / 2 - viewportRect.left, + y: (first.y + second.y) / 2 - viewportRect.top, + } + + context.set("pinchDistance", distance) + context.set("pinchMidpoint", midpoint) + }, + + handlePinchMove({ context, event, send }) { + const touches = Array.isArray(event.touches) ? event.touches : [] + if (touches.length < 2) return + + const [first, second] = touches + const dx = first.x - second.x + const dy = first.y - second.y + const distance = Math.hypot(dx, dy) + + const lastDistance = context.get("pinchDistance") + const lastMidpoint = context.get("pinchMidpoint") + const viewportRect = context.get("viewportRect") + + const midpoint = { + x: (first.x + second.x) / 2 - viewportRect.left, + y: (first.y + second.y) / 2 - viewportRect.top, + } + + if (lastDistance != null && lastDistance > 0 && lastMidpoint != null) { + const delta = lastDistance - distance + const scale = distance / lastDistance + const distanceChange = Math.abs(delta) + + // Improve smoothing by ignoring very small changes + const hasSignificantZoom = distanceChange > 1 + + const panDelta = { + x: midpoint.x - lastMidpoint.x, + y: midpoint.y - lastMidpoint.y, + } + + send({ + type: "ZOOM", + trigger: "touch", + delta, + scale: hasSignificantZoom ? scale : 1, + point: midpoint, + panDelta, + }) + } + + context.set("pinchDistance", distance) + context.set("pinchMidpoint", midpoint) + }, + + clearPinchDistance({ context }) { + context.set("pinchDistance", null) + context.set("pinchMidpoint", null) + }, + + nudgeResizeCrop({ context, event, prop }) { + const { key, handlePosition, shiftKey, ctrlKey, metaKey } = event + const crop = context.get("crop") + const viewportRect = context.get("viewportRect") + + // Determine step size based on modifier keys + let step = prop("nudgeStep") + if (ctrlKey || metaKey) { + step = prop("nudgeStepCtrl") + } else if (shiftKey) { + step = prop("nudgeStepShift") + } + + const minSize = { width: prop("minWidth"), height: prop("minHeight") } + const maxSize = { width: prop("maxWidth"), height: prop("maxHeight") } + + const nextCrop = computeKeyboardCrop(key, handlePosition, step, crop, viewportRect, minSize, maxSize) + + context.set("crop", nextCrop) + }, + + nudgeMoveCrop({ context, event, prop }) { + const { key, shiftKey, ctrlKey, metaKey } = event + const crop = context.get("crop") + const viewportRect = context.get("viewportRect") + + let step = prop("nudgeStep") + if (ctrlKey || metaKey) { + step = prop("nudgeStepCtrl") + } else if (shiftKey) { + step = prop("nudgeStepShift") + } + + const delta = getKeyboardMoveDelta(key, step) + const nextCrop = computeMoveCrop(crop, delta, viewportRect) + + context.set("crop", nextCrop) + }, + }, + + effects: { + trackPointerMove({ scope, send }) { + function onPointerMove(event: PointerEvent) { + const point = getEventPoint(event) + const target = getEventTarget(event) + send({ type: "POINTER_MOVE", point, target, shiftKey: event.shiftKey }) + } + + function onPointerUp() { + send({ type: "POINTER_UP" }) + } + + const cleanups = [ + addDomEvent(scope.getDoc(), "pointermove", onPointerMove), + addDomEvent(scope.getDoc(), "pointerup", onPointerUp), + ] + + return () => { + cleanups.forEach((cleanup) => cleanup()) + } + }, + }, + }, +}) diff --git a/packages/machines/image-cropper/src/image-cropper.props.ts b/packages/machines/image-cropper/src/image-cropper.props.ts new file mode 100644 index 0000000000..48e27be6f2 --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.props.ts @@ -0,0 +1,32 @@ +import { createProps } from "@zag-js/types" +import { createSplitProps } from "@zag-js/utils" +import type { ImageCropperProps } from "./image-cropper.types" + +export const props = createProps()([ + "id", + "ids", + "dir", + "getRootNode", + "initialCrop", + "minWidth", + "minHeight", + "maxWidth", + "maxHeight", + "aspectRatio", + "zoom", + "rotation", + "defaultZoom", + "defaultRotation", + "zoomStep", + "zoomSensitivity", + "minZoom", + "maxZoom", + "onZoomChange", + "onRotationChange", + "fixedCropArea", + "nudgeStep", + "nudgeStepShift", + "nudgeStepCtrl", +]) + +export const splitProps = createSplitProps>(props) diff --git a/packages/machines/image-cropper/src/image-cropper.types.ts b/packages/machines/image-cropper/src/image-cropper.types.ts new file mode 100644 index 0000000000..c913214c5d --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.types.ts @@ -0,0 +1,199 @@ +import type { EventObject, Service, Machine } from "@zag-js/core" +import type { CommonProperties, DirectionProperty, Point, PropTypes, Rect, RequiredBy, Size } from "@zag-js/types" + +export type HandlePosition = + | "top-left" + | "top" + | "top-right" + | "right" + | "bottom-right" + | "bottom" + | "bottom-left" + | "left" + +export interface ZoomChangeDetails { + zoom: number +} + +export interface RotationChangeDetails { + rotation: number +} + +export type ElementIds = Partial<{ + root: string + viewport: string + selection: string + handle: (position: string) => string +}> + +export interface ImageCropperProps extends DirectionProperty, CommonProperties { + /** + * The ids of the image cropper elements + */ + ids?: ElementIds + /** + * The initial rectangle of the crop area. + * If not provided, a smart default will be computed based on viewport size and aspect ratio. + */ + initialCrop?: Rect + /** + * The minimum width of the crop area + * @default 40 + */ + minWidth?: number + /** + * The minimum height of the crop area + * @default 40 + */ + minHeight?: number + /** + * The maximum width of the crop area + * @default Infinity + */ + maxWidth?: number + /** + * The maximum height of the crop area + * @default Infinity + */ + maxHeight?: number + /** + * The aspect ratio to maintain for the crop area (width / height). + * For example, an aspect ratio of 16 / 9 will maintain a width to height ratio of 16:9. + * If not provided, the crop area can be freely resized. + */ + aspectRatio?: number + /** + * The controlled zoom level of the image. + */ + zoom?: number + /** + * The controlled rotation of the image in degrees (0 - 360). + */ + rotation?: number + /** + * The initial zoom factor to apply to the image. + * @default 1 + */ + defaultZoom?: number + /** + * The initial rotation to apply to the image in degrees. + * @default 0 + */ + defaultRotation?: number + /** + * The amount of zoom applied per wheel step. + * @default 0.1 + */ + zoomStep?: number + /** + * Controls how responsive pinch-to-zoom is. + * @default 2 + */ + zoomSensitivity?: number + /** + * The minimum zoom factor allowed. + * @default 1 + */ + minZoom?: number + /** + * The maximum zoom factor allowed. + * @default 5 + */ + maxZoom?: number + /** + * The base nudge step for keyboard arrow keys (in pixels). + * @default 1 + */ + nudgeStep?: number + /** + * The nudge step when Shift key is held (in pixels). + * @default 10 + */ + nudgeStepShift?: number + /** + * The nudge step when Ctrl/Cmd key is held (in pixels). + * @default 50 + */ + nudgeStepCtrl?: number + /** + * Callback fired when the zoom level changes. + */ + onZoomChange?: ((details: ZoomChangeDetails) => void) | undefined + /** + * Callback fired when the rotation changes. + */ + onRotationChange?: ((details: RotationChangeDetails) => void) | undefined + /** + * Whether the crop area is fixed in size and position. + * @default false + */ + fixedCropArea?: boolean +} + +type PropsWithDefault = + | "minWidth" + | "minHeight" + | "defaultZoom" + | "defaultRotation" + | "zoomStep" + | "zoomSensitivity" + | "minZoom" + | "maxZoom" + | "maxWidth" + | "maxHeight" + | "fixedCropArea" + | "nudgeStep" + | "nudgeStepShift" + | "nudgeStepCtrl" + +export interface ImageCropperSchema { + state: "idle" | "dragging" | "panning" + props: RequiredBy + context: { + naturalSize: Size + crop: Rect + pointerStart: Point | null + cropStart: Rect | null + handlePosition: HandlePosition | null + shiftLockRatio: number | null + pinchDistance: number | null + pinchMidpoint: Point | null + zoom: number + rotation: number + offset: Point + offsetStart: Point | null + viewportRect: { width: number; height: number; top: number; left: number; right: number; bottom: number } + } + event: EventObject + action: string + guard: string + effect: string +} + +export type ImageCropperService = Service + +export type ImageCropperMachine = Machine + +export interface HandleProps { + /** + * The position of the handle + */ + position: HandlePosition +} + +export interface ImageCropperApi { + /** + * Function to set the zoom level of the image. + */ + setZoom: (zoom: number) => void + /** + * Function to set the rotation of the image. + */ + setRotation: (rotation: number) => void + + getRootProps: () => T["element"] + getViewportProps: () => T["element"] + getImageProps: () => T["element"] + getSelectionProps: () => T["element"] + getHandleProps: (props: HandleProps) => T["element"] +} diff --git a/packages/machines/image-cropper/src/image-cropper.utils.ts b/packages/machines/image-cropper/src/image-cropper.utils.ts new file mode 100644 index 0000000000..fe8cb07b9b --- /dev/null +++ b/packages/machines/image-cropper/src/image-cropper.utils.ts @@ -0,0 +1,552 @@ +import type { Point, Rect, Size } from "@zag-js/types" +import { clampValue } from "@zag-js/utils" +import type { HandlePosition } from "./image-cropper.types" + +interface ResizeOptions { + cropStart: Rect + handlePosition: HandlePosition + delta: { x: number; y: number } + viewportRect: Size + minSize: Size + maxSize?: Size + aspectRatio?: number | undefined +} + +export function computeResizeCrop(options: ResizeOptions): Rect { + const { cropStart, handlePosition, delta, viewportRect, minSize, maxSize, aspectRatio } = options + let { x, y, width, height } = cropStart + let left = x + let top = y + let right = x + width + let bottom = y + height + + const hasAspect = typeof aspectRatio === "number" && aspectRatio > 0 + + let minWidth = Math.min(minSize.width, viewportRect.width) + let minHeight = Math.min(minSize.height, viewportRect.height) + + let maxWidth = maxSize?.width ?? viewportRect.width + if (!Number.isFinite(maxWidth)) maxWidth = viewportRect.width + maxWidth = Math.min(maxWidth, viewportRect.width) + + let maxHeight = maxSize?.height ?? viewportRect.height + if (!Number.isFinite(maxHeight)) maxHeight = viewportRect.height + maxHeight = Math.min(maxHeight, viewportRect.height) + + maxWidth = Math.max(minWidth, maxWidth) + maxHeight = Math.max(minHeight, maxHeight) + + if (hasAspect) { + const mw = Math.max(minWidth, minHeight * aspectRatio) + const mh = mw / aspectRatio + minWidth = Math.min(mw, viewportRect.width) + minHeight = Math.min(mh, viewportRect.height) + + let constrainedMaxWidth = Math.min(maxWidth, maxHeight * aspectRatio, viewportRect.width) + let constrainedMaxHeight = constrainedMaxWidth / aspectRatio + + if (constrainedMaxHeight > maxHeight || constrainedMaxHeight > viewportRect.height) { + constrainedMaxHeight = Math.min(maxHeight, viewportRect.height) + constrainedMaxWidth = constrainedMaxHeight * aspectRatio + } + + maxWidth = Math.max(minWidth, Math.min(constrainedMaxWidth, viewportRect.width)) + maxHeight = Math.max(minHeight, Math.min(constrainedMaxHeight, viewportRect.height)) + } else { + maxWidth = Math.max(minWidth, Math.min(maxWidth, viewportRect.width)) + maxHeight = Math.max(minHeight, Math.min(maxHeight, viewportRect.height)) + } + + const hasLeft = handlePosition.includes("left") + const hasRight = handlePosition.includes("right") + const hasTop = handlePosition.includes("top") + const hasBottom = handlePosition.includes("bottom") + + if (hasLeft) { + const minLeft = Math.max(0, right - maxWidth) + const maxLeft = right - minWidth + left = clampValue(left + delta.x, minLeft, maxLeft) + } + + if (hasRight) { + const minRight = left + minWidth + const maxRight = Math.min(viewportRect.width, left + maxWidth) + right = clampValue(right + delta.x, minRight, maxRight) + } + + if (hasTop) { + const minTop = Math.max(0, bottom - maxHeight) + const maxTop = bottom - minHeight + top = clampValue(top + delta.y, minTop, maxTop) + } + + if (hasBottom) { + const minBottom = top + minHeight + const maxBottom = Math.min(viewportRect.height, top + maxHeight) + bottom = clampValue(bottom + delta.y, minBottom, maxBottom) + } + + if (hasAspect) { + const clampAspectSize = (widthValue: number, heightValue: number) => { + const clampByWidth = (value: number) => { + let w = clampValue(value, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + let h = w / aspectRatio + + if (h < minHeight) { + h = minHeight + w = clampValue(h * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + h = w / aspectRatio + } + + if (h > maxHeight) { + h = Math.min(maxHeight, viewportRect.height) + w = clampValue(h * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + h = w / aspectRatio + } + + if (h > viewportRect.height) { + h = viewportRect.height + w = clampValue(h * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + h = w / aspectRatio + if (h < minHeight) { + h = minHeight + w = clampValue(h * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + h = w / aspectRatio + } + } + + return { width: w, height: h } + } + + const clampByHeight = (value: number) => { + let h = clampValue(value, minHeight, maxHeight) + h = Math.min(h, viewportRect.height) + let w = h * aspectRatio + w = clampValue(w, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + let adjustedH = w / aspectRatio + + if (adjustedH < minHeight) { + adjustedH = minHeight + w = clampValue(adjustedH * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + adjustedH = w / aspectRatio + } + + if (adjustedH > maxHeight) { + adjustedH = Math.min(maxHeight, viewportRect.height) + w = clampValue(adjustedH * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + adjustedH = w / aspectRatio + } + + if (w > viewportRect.width) { + w = viewportRect.width + adjustedH = w / aspectRatio + if (adjustedH > maxHeight) { + adjustedH = Math.min(maxHeight, viewportRect.height) + w = clampValue(adjustedH * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + adjustedH = w / aspectRatio + } + if (adjustedH < minHeight) { + adjustedH = minHeight + w = clampValue(adjustedH * aspectRatio, minWidth, maxWidth) + w = Math.min(w, viewportRect.width) + adjustedH = w / aspectRatio + } + } + + return { width: w, height: adjustedH } + } + + const byWidth = clampByWidth(widthValue) + const byHeight = clampByHeight(heightValue) + + const deltaWidth = Math.abs(byWidth.width - widthValue) + Math.abs(byWidth.height - heightValue) + const deltaHeight = Math.abs(byHeight.width - widthValue) + Math.abs(byHeight.height - heightValue) + + return deltaHeight < deltaWidth ? byHeight : byWidth + } + + let newWidth = right - left + let newHeight = bottom - top + + if ((hasLeft || hasRight) && (hasTop || hasBottom)) { + let tempW = newWidth + let tempH = tempW / aspectRatio + + if (tempH > newHeight || top + tempH > viewportRect.height || left + tempW > viewportRect.width) { + tempH = newHeight + tempW = tempH * aspectRatio + } + + const constrained = clampAspectSize(tempW, tempH) + tempW = constrained.width + tempH = constrained.height + + if (hasRight && hasBottom) { + right = left + tempW + bottom = top + tempH + } else if (hasRight && hasTop) { + right = left + tempW + top = bottom - tempH + } else if (hasLeft && hasBottom) { + left = right - tempW + bottom = top + tempH + } else if (hasLeft && hasTop) { + left = right - tempW + top = bottom - tempH + } + } else if ((hasLeft || hasRight) && !(hasTop || hasBottom)) { + const centerY = (top + bottom) / 2 + let nextWidth = newWidth + let nextHeight = nextWidth / aspectRatio + + const constrained = clampAspectSize(nextWidth, nextHeight) + nextWidth = constrained.width + nextHeight = constrained.height + + const halfH = nextHeight / 2 + top = centerY - halfH + bottom = centerY + halfH + + if (top < 0) { + top = 0 + bottom = nextHeight + } + + if (bottom > viewportRect.height) { + bottom = viewportRect.height + top = bottom - nextHeight + } + + if (hasRight) { + right = left + nextWidth + } else { + left = right - nextWidth + } + } else if ((hasTop || hasBottom) && !(hasLeft || hasRight)) { + const centerX = (left + right) / 2 + let nextHeight = newHeight + const constrained = clampAspectSize(newWidth, nextHeight) + const nextWidth = constrained.width + nextHeight = constrained.height + + const halfW = nextWidth / 2 + left = centerX - halfW + right = centerX + halfW + + if (left < 0) { + left = 0 + right = nextWidth + } + + if (right > viewportRect.width) { + right = viewportRect.width + left = right - nextWidth + } + + if (hasBottom) { + bottom = top + nextHeight + } else { + top = bottom - nextHeight + } + } + } + + const maxLeft = Math.max(0, viewportRect.width - minWidth) + const maxTop = Math.max(0, viewportRect.height - minHeight) + left = clampValue(left, 0, maxLeft) + top = clampValue(top, 0, maxTop) + + if (hasAspect) { + const maxRight = Math.min(viewportRect.width, left + maxWidth) + const maxBottom = Math.min(viewportRect.height, top + maxHeight) + right = clampValue(right, left + minWidth, maxRight) + bottom = clampValue(bottom, top + minHeight, maxBottom) + } else { + const maxRight = Math.min(viewportRect.width, left + maxWidth) + const maxBottom = Math.min(viewportRect.height, top + maxHeight) + right = clampValue(right, left + minWidth, maxRight) + bottom = clampValue(bottom, top + minHeight, maxBottom) + } + + return { + x: left, + y: top, + width: right - left, + height: bottom - top, + } +} + +export function computeMoveCrop( + cropStart: Rect, + delta: { x: number; y: number }, + viewportRect: { width: number; height: number }, +): Rect { + return { + x: clampValue(cropStart.x + delta.x, 0, viewportRect.width - cropStart.width), + y: clampValue(cropStart.y + delta.y, 0, viewportRect.height - cropStart.height), + width: cropStart.width, + height: cropStart.height, + } +} + +interface ClampOffsetParams { + zoom: number + rotation: number + viewportRect: { width: number; height: number } + offset: Point + fixedCropArea?: boolean + crop?: Rect + naturalSize?: Size +} + +export function clampOffset(params: ClampOffsetParams): Point { + const { zoom, rotation, viewportRect, offset, fixedCropArea, crop, naturalSize } = params + + if (fixedCropArea && crop && naturalSize) { + const theta = ((rotation % 360) * Math.PI) / 180 + const c = Math.abs(Math.cos(theta)) + const s = Math.abs(Math.sin(theta)) + + const imgW = naturalSize.width * zoom + const imgH = naturalSize.height * zoom + + const aabbW = imgW * c + imgH * s + const aabbH = imgW * s + imgH * c + + const centerX = viewportRect.width / 2 + const centerY = viewportRect.height / 2 + + const cropLeft = crop.x + const cropRight = crop.x + crop.width + const cropTop = crop.y + const cropBottom = crop.y + crop.height + + const minX = cropRight - centerX - aabbW / 2 + const maxX = cropLeft - centerX + aabbW / 2 + const minY = cropBottom - centerY - aabbH / 2 + const maxY = cropTop - centerY + aabbH / 2 + + return { + x: clampValue(offset.x, minX, maxX), + y: clampValue(offset.y, minY, maxY), + } + } + + const theta = ((rotation % 360) * Math.PI) / 180 + const c = Math.abs(Math.cos(theta)) + const s = Math.abs(Math.sin(theta)) + + const contentW = viewportRect.width * zoom + const contentH = viewportRect.height * zoom + + const aabbW = contentW * c + contentH * s + const aabbH = contentW * s + contentH * c + + const extraWidth = Math.max(0, aabbW - viewportRect.width) + const extraHeight = Math.max(0, aabbH - viewportRect.height) + + const minX = -extraWidth / 2 + const maxX = extraWidth / 2 + const minY = -extraHeight / 2 + const maxY = extraHeight / 2 + + return { + x: clampValue(offset.x, minX, maxX), + y: clampValue(offset.y, minY, maxY), + } +} + +export function computeKeyboardCrop( + key: string, + handlePosition: HandlePosition, + step: number, + crop: Rect, + viewportRect: Size, + minSize: Size, + maxSize: Size, +): Rect { + const nextCrop = { ...crop } + + const hasLeft = handlePosition.includes("left") + const hasRight = handlePosition.includes("right") + const hasTop = handlePosition.includes("top") + const hasBottom = handlePosition.includes("bottom") + + const minWidth = Math.min(minSize.width, viewportRect.width) + const minHeight = Math.min(minSize.height, viewportRect.height) + let maxWidth = Math.min(maxSize.width, viewportRect.width) + let maxHeight = Math.min(maxSize.height, viewportRect.height) + + maxWidth = Math.max(minWidth, maxWidth) + maxHeight = Math.max(minHeight, maxHeight) + + const isCorner = (hasLeft || hasRight) && (hasTop || hasBottom) + + if (key === "ArrowLeft") { + if (hasLeft) { + const newX = Math.max(0, nextCrop.x - step) + const newWidth = crop.width + (crop.x - newX) + if (newWidth <= maxWidth) { + nextCrop.x = newX + nextCrop.width = newWidth + } else { + nextCrop.x = crop.x + crop.width - maxWidth + nextCrop.width = maxWidth + } + + if (isCorner && hasTop) { + const newY = Math.max(0, nextCrop.y - step) + const newHeight = crop.height + (crop.y - newY) + if (newHeight <= maxHeight) { + nextCrop.y = newY + nextCrop.height = newHeight + } else { + nextCrop.y = crop.y + crop.height - maxHeight + nextCrop.height = maxHeight + } + } else if (isCorner && hasBottom) { + const newHeight = nextCrop.height + step + nextCrop.height = Math.min(viewportRect.height - nextCrop.y, Math.min(maxHeight, newHeight)) + } + } else if (hasRight) { + nextCrop.width = Math.max(minWidth, nextCrop.width - step) + + if (isCorner && hasTop) { + const newY = Math.min(crop.y + step, crop.y + crop.height - minHeight) + nextCrop.y = newY + nextCrop.height = crop.height - (newY - crop.y) + } else if (isCorner && hasBottom) { + nextCrop.height = Math.max(minHeight, nextCrop.height - step) + } + } + } else if (key === "ArrowRight") { + if (hasLeft) { + const newX = Math.min(crop.x + step, crop.x + crop.width - minWidth) + nextCrop.x = newX + nextCrop.width = crop.width - (newX - crop.x) + + if (isCorner && hasTop) { + const newY = Math.min(crop.y + step, crop.y + crop.height - minHeight) + nextCrop.y = newY + nextCrop.height = crop.height - (newY - crop.y) + } else if (isCorner && hasBottom) { + nextCrop.height = Math.max(minHeight, nextCrop.height - step) + } + } else if (hasRight) { + const newWidth = nextCrop.width + step + nextCrop.width = Math.min(viewportRect.width - nextCrop.x, Math.min(maxWidth, newWidth)) + + if (isCorner && hasTop) { + const newY = Math.max(0, nextCrop.y - step) + const newHeight = crop.height + (crop.y - newY) + if (newHeight <= maxHeight) { + nextCrop.y = newY + nextCrop.height = newHeight + } else { + nextCrop.y = crop.y + crop.height - maxHeight + nextCrop.height = maxHeight + } + } else if (isCorner && hasBottom) { + const newHeight = nextCrop.height + step + nextCrop.height = Math.min(viewportRect.height - nextCrop.y, Math.min(maxHeight, newHeight)) + } + } + } + + if (key === "ArrowUp") { + if (hasTop) { + const newY = Math.max(0, nextCrop.y - step) + const newHeight = crop.height + (crop.y - newY) + if (newHeight <= maxHeight) { + nextCrop.y = newY + nextCrop.height = newHeight + } else { + nextCrop.y = crop.y + crop.height - maxHeight + nextCrop.height = maxHeight + } + + if (isCorner && hasLeft) { + const newX = Math.max(0, nextCrop.x - step) + const newWidth = crop.width + (crop.x - newX) + if (newWidth <= maxWidth) { + nextCrop.x = newX + nextCrop.width = newWidth + } else { + nextCrop.x = crop.x + crop.width - maxWidth + nextCrop.width = maxWidth + } + } else if (isCorner && hasRight) { + const newWidth = nextCrop.width + step + nextCrop.width = Math.min(viewportRect.width - nextCrop.x, Math.min(maxWidth, newWidth)) + } + } else if (hasBottom) { + nextCrop.height = Math.max(minHeight, nextCrop.height - step) + + if (isCorner && hasLeft) { + const newX = Math.min(crop.x + step, crop.x + crop.width - minWidth) + nextCrop.x = newX + nextCrop.width = crop.width - (newX - crop.x) + } else if (isCorner && hasRight) { + nextCrop.width = Math.max(minWidth, nextCrop.width - step) + } + } + } else if (key === "ArrowDown") { + if (hasTop) { + const newY = Math.min(crop.y + step, crop.y + crop.height - minHeight) + nextCrop.y = newY + nextCrop.height = crop.height - (newY - crop.y) + + if (isCorner && hasLeft) { + const newX = Math.min(crop.x + step, crop.x + crop.width - minWidth) + nextCrop.x = newX + nextCrop.width = crop.width - (newX - crop.x) + } else if (isCorner && hasRight) { + nextCrop.width = Math.max(minWidth, nextCrop.width - step) + } + } else if (hasBottom) { + const newHeight = nextCrop.height + step + nextCrop.height = Math.min(viewportRect.height - nextCrop.y, Math.min(maxHeight, newHeight)) + + if (isCorner && hasLeft) { + const newX = Math.max(0, nextCrop.x - step) + const newWidth = crop.width + (crop.x - newX) + if (newWidth <= maxWidth) { + nextCrop.x = newX + nextCrop.width = newWidth + } else { + nextCrop.x = crop.x + crop.width - maxWidth + nextCrop.width = maxWidth + } + } else if (isCorner && hasRight) { + const newWidth = nextCrop.width + step + nextCrop.width = Math.min(viewportRect.width - nextCrop.x, Math.min(maxWidth, newWidth)) + } + } + } + + return nextCrop +} + +export function getKeyboardMoveDelta(key: string, step: number): { x: number; y: number } { + switch (key) { + case "ArrowLeft": + return { x: -step, y: 0 } + case "ArrowRight": + return { x: step, y: 0 } + case "ArrowUp": + return { x: 0, y: -step } + case "ArrowDown": + return { x: 0, y: step } + default: + return { x: 0, y: 0 } + } +} diff --git a/packages/machines/image-cropper/src/index.ts b/packages/machines/image-cropper/src/index.ts new file mode 100644 index 0000000000..39647d00a8 --- /dev/null +++ b/packages/machines/image-cropper/src/index.ts @@ -0,0 +1,15 @@ +export { anatomy } from "./image-cropper.anatomy" +export { connect } from "./image-cropper.connect" +export { machine } from "./image-cropper.machine" +export * from "./image-cropper.props" +export type { + ImageCropperApi as Api, + ImageCropperProps as Props, + ImageCropperMachine as Machine, + ImageCropperService as Service, + ElementIds, + HandleProps, + HandlePosition, + RotationChangeDetails, + ZoomChangeDetails, +} from "./image-cropper.types" diff --git a/packages/machines/image-cropper/tsconfig.json b/packages/machines/image-cropper/tsconfig.json new file mode 100644 index 0000000000..8e781cd154 --- /dev/null +++ b/packages/machines/image-cropper/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "include": ["src"], + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/.tsbuildinfo" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58b5341c31..c6f819e07f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -112,7 +112,7 @@ importers: version: 27.0.0 tsup: specifier: 8.5.0 - version: 8.5.0(@microsoft/api-extractor@7.53.0(@types/node@24.7.0))(@swc/core@1.13.5(@swc/helpers@0.5.17))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.0(@microsoft/api-extractor@7.52.13(@types/node@24.7.0))(@swc/core@1.13.5(@swc/helpers@0.5.17))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) tsx: specifier: 4.20.6 version: 4.20.6 @@ -127,7 +127,7 @@ importers: version: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vite-plugin-dts: specifier: 4.5.4 - version: 4.5.4(@types/node@24.7.0)(rollup@4.52.4)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 4.5.4(@types/node@24.7.0)(rollup@4.52.0)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: specifier: 3.2.4 version: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.0)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) @@ -245,6 +245,9 @@ importers: '@zag-js/i18n-utils': specifier: workspace:* version: link:../../packages/utilities/i18n-utils + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../../packages/machines/image-cropper '@zag-js/interact-outside': specifier: workspace:* version: link:../../packages/utilities/interact-outside @@ -385,10 +388,10 @@ importers: version: 8.1.0 next: specifier: 15.5.4 - version: 15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) next-cloudinary: specifier: 6.16.0 - version: 6.16.0(next@15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + version: 6.16.0(next@15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) react: specifier: 19.2.0 version: 19.2.0 @@ -406,7 +409,7 @@ importers: version: 3.1.0 virtua: specifier: ^0.44.2 - version: 0.44.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(solid-js@1.9.9)(svelte@5.39.9)(vue@3.5.22(typescript@5.9.3)) + version: 0.44.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(solid-js@1.9.9)(svelte@5.39.9)(vue@3.5.22(typescript@5.9.3)) devDependencies: '@next/eslint-plugin-next': specifier: 15.5.4 @@ -419,10 +422,10 @@ importers: version: 24.7.0 '@types/react': specifier: ^19 - version: 19.2.0 + version: 19.1.13 '@types/react-dom': specifier: ^19 - version: 19.2.0(@types/react@19.2.0) + version: 19.1.9(@types/react@19.1.13) eslint-plugin-react: specifier: 7.37.5 version: 7.37.5(eslint@9.37.0(jiti@2.6.1)) @@ -540,6 +543,9 @@ importers: '@zag-js/i18n-utils': specifier: workspace:* version: link:../../packages/utilities/i18n-utils + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../../packages/machines/image-cropper '@zag-js/interact-outside': specifier: workspace:* version: link:../../packages/utilities/interact-outside @@ -696,7 +702,7 @@ importers: version: 24.7.0 nuxt: specifier: 4.1.3 - version: 4.1.3(@parcel/watcher@2.5.1)(@types/node@24.7.0)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.8.1)(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.4)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(yaml@2.8.1) + version: 4.1.3(@parcel/watcher@2.5.1)(@types/node@24.7.0)(@vue/compiler-sfc@3.5.22)(db0@0.3.2)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.7.0)(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.0)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(yaml@2.8.1) examples/preact-ts: dependencies: @@ -805,6 +811,9 @@ importers: '@zag-js/i18n-utils': specifier: workspace:* version: link:../../packages/utilities/i18n-utils + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../../packages/machines/image-cropper '@zag-js/interact-outside': specifier: workspace:* version: link:../../packages/utilities/interact-outside @@ -976,7 +985,7 @@ importers: version: 0.15.3(solid-js@1.9.9) '@solidjs/start': specifier: 1.2.0 - version: 1.2.0(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 1.2.0(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@zag-js/accordion': specifier: workspace:* version: link:../../packages/machines/accordion @@ -1079,6 +1088,9 @@ importers: '@zag-js/i18n-utils': specifier: workspace:* version: link:../../packages/utilities/i18n-utils + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../../packages/machines/image-cropper '@zag-js/interact-outside': specifier: workspace:* version: link:../../packages/utilities/interact-outside @@ -1219,7 +1231,7 @@ importers: version: 1.9.9 vinxi: specifier: 0.5.8 - version: 0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) examples/svelte-ts: dependencies: @@ -1328,6 +1340,9 @@ importers: '@zag-js/i18n-utils': specifier: workspace:* version: link:../../packages/utilities/i18n-utils + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../../packages/machines/image-cropper '@zag-js/interact-outside': specifier: workspace:* version: link:../../packages/utilities/interact-outside @@ -1466,10 +1481,10 @@ importers: devDependencies: '@sveltejs/adapter-auto': specifier: 6.1.1 - version: 6.1.1(@sveltejs/kit@2.44.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 6.1.1(@sveltejs/kit@2.44.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/kit': specifier: 2.44.0 - version: 2.44.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 2.44.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@sveltejs/vite-plugin-svelte': specifier: 6.2.1 version: 6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) @@ -1605,6 +1620,9 @@ importers: '@zag-js/i18n-utils': specifier: workspace:* version: link:../../packages/utilities/i18n-utils + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../../packages/machines/image-cropper '@zag-js/interact-outside': specifier: workspace:* version: link:../../packages/utilities/interact-outside @@ -1765,7 +1783,7 @@ importers: devDependencies: '@types/react': specifier: ^19 - version: 19.2.0 + version: 19.1.13 clean-package: specifier: 2.2.0 version: 2.2.0 @@ -1837,16 +1855,16 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.0 - version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.0(@types/react@19.2.0))(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/jsdom': specifier: ^27.0.0 version: 27.0.0 '@types/react': specifier: ^19 - version: 19.2.0 + version: 19.1.13 '@types/react-dom': specifier: ^19 - version: 19.2.0(@types/react@19.2.0) + version: 19.1.9(@types/react@19.1.13) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) @@ -2408,6 +2426,28 @@ importers: specifier: 2.2.0 version: 2.2.0 + packages/machines/image-cropper: + dependencies: + '@zag-js/anatomy': + specifier: workspace:* + version: link:../../anatomy + '@zag-js/core': + specifier: workspace:* + version: link:../../core + '@zag-js/dom-query': + specifier: workspace:* + version: link:../../utilities/dom-query + '@zag-js/types': + specifier: workspace:* + version: link:../../types + '@zag-js/utils': + specifier: workspace:* + version: link:../../utilities/core + devDependencies: + clean-package: + specifier: 2.2.0 + version: 2.2.0 + packages/machines/listbox: dependencies: '@zag-js/anatomy': @@ -3368,6 +3408,9 @@ importers: shared: dependencies: + '@zag-js/image-cropper': + specifier: workspace:* + version: link:../packages/machines/image-cropper '@zag-js/tour': specifier: workspace:* version: link:../packages/machines/tour @@ -3562,7 +3605,7 @@ importers: version: 8.1.0 next: specifier: 15.5.4 - version: 15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: 19.2.0 version: 19.2.0 @@ -3581,10 +3624,10 @@ importers: version: 24.7.0 '@types/react': specifier: ^19 - version: 19.2.0 + version: 19.1.13 '@types/react-dom': specifier: ^19 - version: 19.2.0(@types/react@19.2.0) + version: 19.1.9(@types/react@19.1.13) eslint: specifier: 9.37.0 version: 9.37.0(jiti@2.6.1) @@ -3758,10 +3801,10 @@ importers: version: 8.1.0 next: specifier: 15.5.4 - version: 15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) next-seo: specifier: 6.8.0 - version: 6.8.0(next@15.5.4(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 6.8.0(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -3798,16 +3841,16 @@ importers: version: 1.4.1(jsdom@27.0.0(postcss@8.4.49))(typescript@5.9.3) '@types/react': specifier: ^19 - version: 19.2.0 + version: 19.1.13 all-contributors-cli: specifier: 6.26.1 version: 6.26.1 eslint: specifier: ^9 - version: 9.36.0(jiti@2.6.1) + version: 9.35.0(jiti@2.6.1) eslint-config-next: specifier: 15.5.4 - version: 15.5.4(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) + version: 15.5.4(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) prettier: specifier: 3.6.2 version: 3.6.2 @@ -3838,11 +3881,11 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@asamuzakjp/css-color@4.0.5': - resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==} + '@asamuzakjp/css-color@4.0.4': + resolution: {integrity: sha512-cKjSKvWGmAziQWbCouOsFwb14mp1betm8Y7Fn+yglDMUUu3r9DCbJ9iJbeFDenLMqFbIMC0pQP8K+B8LAxX3OQ==} - '@asamuzakjp/dom-selector@6.6.1': - resolution: {integrity: sha512-8QT9pokVe1fUt1C8IrJketaeFOdRfTOS96DL3EBjE8CRZm3eHnwMlQe2NPoOSEYPwJ5Q25uYoX1+m9044l3ysQ==} + '@asamuzakjp/dom-selector@6.5.5': + resolution: {integrity: sha512-kI2MX9pmImjxWT8nxDZY+MuN6r1jJGe7WxizEbsAEPB/zxfW5wYLIiPG1v3UKgEOOP8EsDkp0ZL99oRFAdPM8g==} '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} @@ -4441,6 +4484,10 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@9.35.0': + resolution: {integrity: sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@9.36.0': resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4696,11 +4743,11 @@ packages: '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} - '@microsoft/api-extractor-model@7.31.0': - resolution: {integrity: sha512-DqbB4G33bYTsS8hxdmyjpLXjQTjf/05Jsk82d4ldb5UaYi5kt7imJDcSJh5K+bgJXLBn63MAPAJTUNVXsniFCQ==} + '@microsoft/api-extractor-model@7.30.7': + resolution: {integrity: sha512-TBbmSI2/BHpfR9YhQA7nH0nqVmGgJ0xH0Ex4D99/qBDAUpnhA2oikGmdXanbw9AWWY/ExBYIpkmY8dBHdla3YQ==} - '@microsoft/api-extractor@7.53.0': - resolution: {integrity: sha512-gbeBZm5ni4VIo7oUIq0u2UpIJsayBzxxsqE6dk1G/lrjef4OuuCJh09BakPH348JhD0ZIa3M+c0wGphLkYohTA==} + '@microsoft/api-extractor@7.52.13': + resolution: {integrity: sha512-K6/bBt8zZfn9yc06gNvA+/NlBGJC/iJlObpdufXHEJtqcD4Dln4ITCLZpwP3DNZ5NyBFeTkKdv596go3V72qlA==} hasBin: true '@microsoft/tsdoc-config@0.17.1': @@ -4788,8 +4835,8 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@nuxt/cli@3.29.0': - resolution: {integrity: sha512-qqToeBZPGCkMYJvHR/8j/qzmZwnLs2EVTV5eBalA5CfX8+NTdR1uqrhtHcZXO3vySoODFjzCCVIK5a6chtyeQQ==} + '@nuxt/cli@3.29.2': + resolution: {integrity: sha512-emUswscW990anBIQLxb1tPviB6S12nssEK73fHm+79D1Ndqa3lc7M/APqp6zShNKXvf7e8Q0UWX4SceImuApJA==} engines: {node: ^16.10.0 || >=18.0.0} hasBin: true @@ -4842,23 +4889,26 @@ packages: resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} - '@octokit/core@7.0.5': - resolution: {integrity: sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==} + '@octokit/core@7.0.4': + resolution: {integrity: sha512-jOT8V1Ba5BdC79sKrRWDdMT5l1R+XNHTPR6CPWzUP2EcfAcvIHZWF0eAbmRcpOOP5gVIwnqNg0C4nvh6Abc3OA==} engines: {node: '>= 20'} - '@octokit/endpoint@11.0.1': - resolution: {integrity: sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==} + '@octokit/endpoint@11.0.0': + resolution: {integrity: sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==} engines: {node: '>= 20'} - '@octokit/graphql@9.0.2': - resolution: {integrity: sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==} + '@octokit/graphql@9.0.1': + resolution: {integrity: sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg==} engines: {node: '>= 20'} + '@octokit/openapi-types@25.1.0': + resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==} + '@octokit/openapi-types@26.0.0': resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} - '@octokit/plugin-paginate-rest@13.2.0': - resolution: {integrity: sha512-YuAlyjR8o5QoRSOvMHxSJzPtogkNMgeMv2mpccrvdUGeC3MKyfi/hS+KiFwyH/iRKIKyx+eIMsDjbt3p9r2GYA==} + '@octokit/plugin-paginate-rest@13.1.1': + resolution: {integrity: sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -4875,21 +4925,28 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/request-error@7.0.1': - resolution: {integrity: sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==} + '@octokit/request-error@7.0.0': + resolution: {integrity: sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==} engines: {node: '>= 20'} - '@octokit/request@10.0.5': - resolution: {integrity: sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==} + '@octokit/request@10.0.3': + resolution: {integrity: sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==} engines: {node: '>= 20'} '@octokit/rest@22.0.0': resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} engines: {node: '>= 20'} + '@octokit/types@14.1.0': + resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} + '@octokit/types@15.0.0': resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + '@oxc-minify/binding-android-arm64@0.94.0': resolution: {integrity: sha512-7VEBFFFAi4cYqlW/ziVs5XmNM/0IqAp7duBuTM/zus/EOc3Q2zhS9ApJo0zIwbRUZMlIm1RHe8Hths//xE7K1A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5369,8 +5426,8 @@ packages: '@prefresh/babel-plugin@0.5.2': resolution: {integrity: sha512-AOl4HG6dAxWkJ5ndPHBgBa49oo/9bOiJuRDKHLSTyH+Fd9x00shTXpdiTj1W41l6oQIwUOAgJeHMn4QwIDpHkA==} - '@prefresh/core@1.5.8': - resolution: {integrity: sha512-T7HMpakS1iPVCFZvfDLMGyrWAcO3toUN9/RkJUqqoRr/vNhQrZgHjidfhq3awDzAQtw1emDWH8dsOeu0DWqtgA==} + '@prefresh/core@1.5.7': + resolution: {integrity: sha512-AsyeitiPwG7UkT0mqgKzIDuydmYSKtBlzXEb5ymzskvxewcmVGRjQkcHDy6PCNBT7soAyHpQ0mPgXX4IeyOlUg==} peerDependencies: preact: ^10.0.0 || ^11.0.0-0 @@ -5389,9 +5446,6 @@ packages: '@rolldown/pluginutils@1.0.0-beta.38': resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} - '@rolldown/pluginutils@1.0.0-beta.41': - resolution: {integrity: sha512-ycMEPrS3StOIeb87BT3/+bu+blEtyvwQ4zmo2IcJQy0Rd1DAAhKksA0iUZ3MYSpJtjlPhg0Eo6mvVS6ggPhRbw==} - '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} engines: {node: '>=14.0.0'} @@ -5428,8 +5482,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@16.0.2': - resolution: {integrity: sha512-tCtHJ2BlhSoK4cCs25NMXfV7EALKr0jyasmqVCq3y9cBrKdmJhtsy1iTz36Xhk/O+pDJbzawxF4K6ZblqCnITQ==} + '@rollup/plugin-node-resolve@16.0.1': + resolution: {integrity: sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -5468,151 +5522,143 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.52.4': - resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} + '@rollup/rollup-android-arm-eabi@4.52.0': + resolution: {integrity: sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.4': - resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==} + '@rollup/rollup-android-arm64@4.52.0': + resolution: {integrity: sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.4': - resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==} + '@rollup/rollup-darwin-arm64@4.52.0': + resolution: {integrity: sha512-YCdWlY/8ltN6H78HnMsRHYlPiKvqKagBP1r+D7SSylxX+HnsgXGCmLiV3Y4nSyY9hW8qr8U9LDUx/Lo7M6MfmQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.4': - resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==} + '@rollup/rollup-darwin-x64@4.52.0': + resolution: {integrity: sha512-z4nw6y1j+OOSGzuVbSWdIp1IUks9qNw4dc7z7lWuWDKojY38VMWBlEN7F9jk5UXOkUcp97vA1N213DF+Lz8BRg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.4': - resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==} + '@rollup/rollup-freebsd-arm64@4.52.0': + resolution: {integrity: sha512-Q/dv9Yvyr5rKlK8WQJZVrp5g2SOYeZUs9u/t2f9cQ2E0gJjYB/BWoedXfUT0EcDJefi2zzVfhcOj8drWCzTviw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.4': - resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==} + '@rollup/rollup-freebsd-x64@4.52.0': + resolution: {integrity: sha512-kdBsLs4Uile/fbjZVvCRcKB4q64R+1mUq0Yd7oU1CMm1Av336ajIFqNFovByipciuUQjBCPMxwJhCgfG2re3rg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': - resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.52.0': + resolution: {integrity: sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.4': - resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} + '@rollup/rollup-linux-arm-musleabihf@4.52.0': + resolution: {integrity: sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.4': - resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} + '@rollup/rollup-linux-arm64-gnu@4.52.0': + resolution: {integrity: sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.4': - resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} + '@rollup/rollup-linux-arm64-musl@4.52.0': + resolution: {integrity: sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.4': - resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} + '@rollup/rollup-linux-loong64-gnu@4.52.0': + resolution: {integrity: sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.4': - resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} + '@rollup/rollup-linux-ppc64-gnu@4.52.0': + resolution: {integrity: sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.4': - resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} + '@rollup/rollup-linux-riscv64-gnu@4.52.0': + resolution: {integrity: sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.4': - resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} + '@rollup/rollup-linux-riscv64-musl@4.52.0': + resolution: {integrity: sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.4': - resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} + '@rollup/rollup-linux-s390x-gnu@4.52.0': + resolution: {integrity: sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.4': - resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} + '@rollup/rollup-linux-x64-gnu@4.52.0': + resolution: {integrity: sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.4': - resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} + '@rollup/rollup-linux-x64-musl@4.52.0': + resolution: {integrity: sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.4': - resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} + '@rollup/rollup-openharmony-arm64@4.52.0': + resolution: {integrity: sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.4': - resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==} + '@rollup/rollup-win32-arm64-msvc@4.52.0': + resolution: {integrity: sha512-YQugafP/rH0eOOHGjmNgDURrpYHrIX0yuojOI8bwCyXwxC9ZdTd3vYkmddPX0oHONLXu9Rb1dDmT0VNpjkzGGw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.4': - resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==} + '@rollup/rollup-win32-ia32-msvc@4.52.0': + resolution: {integrity: sha512-zYdUYhi3Qe2fndujBqL5FjAFzvNeLxtIqfzNEVKD1I7C37/chv1VxhscWSQHTNfjPCrBFQMnynwA3kpZpZ8w4A==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.4': - resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==} + '@rollup/rollup-win32-x64-gnu@4.52.0': + resolution: {integrity: sha512-fGk03kQylNaCOQ96HDMeT7E2n91EqvCDd3RwvT5k+xNdFCeMGnj5b5hEgTGrQuyidqSsD3zJDQ21QIaxXqTBJw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.4': - resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==} + '@rollup/rollup-win32-x64-msvc@4.52.0': + resolution: {integrity: sha512-6iKDCVSIUQ8jPMoIV0OytRKniaYyy5EbY/RRydmLW8ZR3cEBhxbWl5ro0rkUNe0ef6sScvhbY79HrjRm8i3vDQ==} cpu: [x64] os: [win32] '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@rushstack/eslint-patch@1.13.0': - resolution: {integrity: sha512-2ih5qGw5SZJ+2fLZxP6Lr6Na2NTIgPRL/7Kmyuw0uIyBQnuhQ8fi8fzUTd38eIQmqp+GYLC00cI6WgtqHxBwmw==} - - '@rushstack/node-core-library@5.16.0': - resolution: {integrity: sha512-bO2LN3olkALZawMqPtBgRGtSzd9l306imZYE0kCiCHNvMEvCB40GqbNFZBds0RcQxx/Am2oohPSJA15UP/MrSA==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@rushstack/eslint-patch@1.12.0': + resolution: {integrity: sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==} - '@rushstack/problem-matcher@0.1.1': - resolution: {integrity: sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==} + '@rushstack/node-core-library@5.14.0': + resolution: {integrity: sha512-eRong84/rwQUlATGFW3TMTYVyqL1vfW9Lf10PH+mVGfIb9HzU3h5AASNIw+axnBLjnD0n3rT5uQBwu9fvzATrg==} peerDependencies: '@types/node': '*' peerDependenciesMeta: '@types/node': optional: true - '@rushstack/rig-package@0.6.0': - resolution: {integrity: sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==} + '@rushstack/rig-package@0.5.3': + resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==} - '@rushstack/terminal@0.19.0': - resolution: {integrity: sha512-Q0eHHuK3V4yLJ8mMuwal+YKhp1TcT0tW9Pr3xJDXyNGlpishp5M9qRTsLsk1d8GcIF15APV9vcKkFDtTvzFGHQ==} + '@rushstack/terminal@0.16.0': + resolution: {integrity: sha512-WEvNuKkoR1PXorr9SxO0dqFdSp1BA+xzDrIm/Bwlc5YHg2FFg6oS+uCTYjerOhFuqCW+A3vKBm6EmKWSHfgx/A==} peerDependencies: '@types/node': '*' peerDependenciesMeta: '@types/node': optional: true - '@rushstack/ts-command-line@5.1.0': - resolution: {integrity: sha512-ncUEFDUU/RMwCmQpwy8fcA3CenEV0ZsNg8m1IJYGVUVzC5WdfeeoDEWhMjNqjq9DYcE4VXTXwQwyAeGo3ugSLg==} + '@rushstack/ts-command-line@5.0.3': + resolution: {integrity: sha512-bgPhQEqLVv/2hwKLYv/XvsTWNZ9B/+X1zJ7WgQE9rO5oiLzrOZvkIW4pk13yOQBhHyjcND5qMOa6p83t+Z66iQ==} '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -5689,8 +5735,8 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@sveltejs/acorn-typescript@1.0.6': - resolution: {integrity: sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==} + '@sveltejs/acorn-typescript@1.0.5': + resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} peerDependencies: acorn: ^8.9.0 @@ -5895,8 +5941,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/router-utils@1.132.31': - resolution: {integrity: sha512-uf8mQ3wV58K8TL5XXBoWhkYxmCV7LLWbbf6AvcxdhnCnBNmXBGlY+T8RdsRnXyI2Iyp2HfHaVZ+8H3CEQedXfw==} + '@tanstack/router-utils@1.131.2': + resolution: {integrity: sha512-sr3x0d2sx9YIJoVth0QnfEcAcl+39sQYaNQxThtHmRpyeFYNyM2TTH+Ud3TNEnI3bbzmLYEUD+7YqB987GzhDA==} engines: {node: '>=12'} '@tanstack/server-functions-plugin@1.121.21': @@ -6053,13 +6099,13 @@ packages: '@types/ps-tree@1.1.6': resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} - '@types/react-dom@19.2.0': - resolution: {integrity: sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg==} + '@types/react-dom@19.1.9': + resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==} peerDependencies: - '@types/react': ^19.2.0 + '@types/react': ^19.0.0 - '@types/react@19.2.0': - resolution: {integrity: sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA==} + '@types/react@19.1.13': + resolution: {integrity: sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -6306,8 +6352,8 @@ packages: cpu: [x64] os: [win32] - '@vercel/nft@0.30.2': - resolution: {integrity: sha512-pquXF3XZFg/T3TBor08rUhIGgOhdSilbn7WQLVP/aVSSO+25Rs4H/m3nxNDQ2x3znX7Z3yYjryN8xaLwypcwQg==} + '@vercel/nft@0.30.1': + resolution: {integrity: sha512-2mgJZv4AYBFkD/nJ4QmiX5Ymxi+AisPLPcS/KPXVqniyQNqKXX+wjieAbDXQP3HcogfEbpHoRMs49Cd4pfkk8g==} engines: {node: '>=18'} hasBin: true @@ -6411,12 +6457,18 @@ packages: '@vue/compiler-core@3.4.19': resolution: {integrity: sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==} + '@vue/compiler-core@3.5.21': + resolution: {integrity: sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==} + '@vue/compiler-core@3.5.22': resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==} '@vue/compiler-dom@3.4.19': resolution: {integrity: sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==} + '@vue/compiler-dom@3.5.21': + resolution: {integrity: sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==} + '@vue/compiler-dom@3.5.22': resolution: {integrity: sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==} @@ -6457,8 +6509,8 @@ packages: typescript: optional: true - '@vue/language-core@3.1.0': - resolution: {integrity: sha512-a7ns+X9vTbdmk7QLrvnZs8s4E1wwtxG/sELzr6F2j4pU+r/OoAv6jJGSz+5tVTU6e4+3rjepGhSP8jDmBBcb3w==} + '@vue/language-core@3.0.7': + resolution: {integrity: sha512-0sqqyqJ0Gn33JH3TdIsZLCZZ8Gr4kwlg8iYOnOrDDkJKSjFurlQY/bEFQx5zs7SX2C/bjMkmPYq/NiyY1fTOkw==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -6482,6 +6534,9 @@ packages: '@vue/shared@3.4.19': resolution: {integrity: sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==} + '@vue/shared@3.5.21': + resolution: {integrity: sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==} + '@vue/shared@3.5.22': resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==} @@ -6556,8 +6611,8 @@ packages: alien-signals@0.4.14: resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} - alien-signals@3.0.0: - resolution: {integrity: sha512-JHoRJf18Y6HN4/KZALr3iU+0vW9LKG+8FMThQlbn4+gv8utsLIkwpomjElGPccGeNwh0FI2HN6BLnyFLo6OyLQ==} + alien-signals@2.0.7: + resolution: {integrity: sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==} all-contributors-cli@6.26.1: resolution: {integrity: sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==} @@ -6575,8 +6630,8 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - ansi-escapes@7.1.1: - resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} + ansi-escapes@7.1.0: + resolution: {integrity: sha512-YdhtCd19sKRKfAAUsrcC1wzm4JuzJoiX4pOJqIoW2qmKj5WzG/dL8uUJ0361zaXtHqK7gEhOwtAtz7t3Yq3X5g==} engines: {node: '>=18'} ansi-red@0.1.1: @@ -6611,8 +6666,8 @@ packages: resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==} engines: {node: '>=0.10.0'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + ansis@4.1.0: + resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} engines: {node: '>=14'} any-promise@1.3.0: @@ -6752,8 +6807,8 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - b4a@1.7.3: - resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + b4a@1.7.1: + resolution: {integrity: sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==} peerDependencies: react-native-b4a: '*' peerDependenciesMeta: @@ -6794,8 +6849,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.12: - resolution: {integrity: sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==} + baseline-browser-mapping@2.8.6: + resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} hasBin: true before-after-hook@4.0.0: @@ -6811,8 +6866,8 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - birpc@2.6.1: - resolution: {integrity: sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==} + birpc@2.5.0: + resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -6839,8 +6894,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - browserslist@4.26.3: - resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + browserslist@4.26.2: + resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -6913,8 +6968,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001748: - resolution: {integrity: sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==} + caniuse-lite@1.0.30001743: + resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -7313,8 +7368,8 @@ packages: dax-sh@0.43.2: resolution: {integrity: sha512-uULa1sSIHgXKGCqJ/pA0zsnzbHlVnuq7g8O2fkHokWFNwEGIhh5lAJlxZa1POG5En5ba7AU4KcBAvGQWMMf8rg==} - db0@0.3.4: - resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} + db0@0.3.2: + resolution: {integrity: sha512-xzWNQ6jk/+NtdfLyXEipbX55dmDSeteLFt/ayF+wZUU5bzKgmrDOxmInUTbyVRp46YwnJdkDA1KhB7WIXFofJw==} peerDependencies: '@electric-sql/pglite': '*' '@libsql/client': '*' @@ -7450,8 +7505,8 @@ packages: engines: {node: '>=0.10'} hasBin: true - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + detect-libc@2.1.0: + resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==} engines: {node: '>=8'} devalue@5.3.2: @@ -7541,8 +7596,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.230: - resolution: {integrity: sha512-A6A6Fd3+gMdaed9wX83CvHYJb4UuapPD5X5SLq72VZJzxHSY0/LUweGXRWmQlh2ln7KV7iw7jnwXK7dlPoOnHQ==} + electron-to-chromium@1.5.222: + resolution: {integrity: sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==} emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -7801,8 +7856,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.36.0: - resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==} + eslint@9.35.0: + resolution: {integrity: sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -7897,9 +7952,6 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - events-universal@1.0.1: - resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} - events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -7967,8 +8019,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-npm-meta@0.4.7: - resolution: {integrity: sha512-aZU3i3eRcSb2NCq8i6N6IlyiTyF6vqAqzBGl2NBF6ngNx/GIqfYbkLDIKZ4z4P0o/RmtsFnVqHwdrSm13o4tnQ==} + fast-npm-meta@0.4.6: + resolution: {integrity: sha512-zbBBOAOlzxfrU4WSnbCHk/nR6Vf32lSEPxDEvNOR08Z5DSZ/A6qJu0rqrHVcexBTd1hc2gim998xnqF/R1PuEw==} fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -8148,10 +8200,6 @@ packages: resolution: {integrity: sha512-zGrN/ZIa95IjRmxDan9a9r9FI6XPmoaNwwojqHLM62wQE1oD6mSoylPzB8hBqXhd8acP5y23rx3AIQaxiEk5BQ==} hasBin: true - generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -8520,8 +8568,8 @@ packages: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} - ioredis@5.8.1: - resolution: {integrity: sha512-Qho8TgIamqEPdgiMadJwzRMW3TudIg6vpg4YONokGDudy4eqRIJtDbVX72pfLBcWxvbn3qm/40TyGUObdW4tLQ==} + ioredis@5.7.0: + resolution: {integrity: sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==} engines: {node: '>=12.22.0'} iron-webcrypto@1.2.1: @@ -8615,8 +8663,8 @@ packages: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -8840,6 +8888,10 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -9177,8 +9229,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.2: - resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + lru-cache@11.2.1: + resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -9539,8 +9591,8 @@ packages: nanotar@0.2.0: resolution: {integrity: sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==} - napi-postinstall@0.3.4: - resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + napi-postinstall@0.3.3: + resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true @@ -9649,8 +9701,8 @@ packages: resolution: {integrity: sha512-tn+OxutdqhvoByKJ7p84FZBSUDfUB76bcvj0ugLBvgE9V52LFcnz8cauCDKi6otnctvFCqa9XkrU35pBY5Baig==} engines: {node: '>=18'} - node-releases@2.0.23: - resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + node-releases@2.0.21: + resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} nopt@8.1.0: resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} @@ -9871,8 +9923,8 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} - package-manager-detector@1.4.0: - resolution: {integrity: sha512-rRZ+pR1Usc+ND9M2NkmCvE/LYJS+8ORVV9X0KuNSY/gFsp7RBHJM/ADh9LYq4Vvfq6QkKrW6/weuh8SMEtN5gw==} + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -9921,6 +9973,9 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -10650,6 +10705,19 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rollup-plugin-visualizer@6.0.3: + resolution: {integrity: sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + rollup-plugin-visualizer@6.0.4: resolution: {integrity: sha512-q8Q7J/6YofkmaGW1sH/fPRAz37x/+pd7VBuaUU7lwvOS/YikuiiEU9jeb9PH8XHiq50XFrUsBbOxeAMYQ7KZkg==} engines: {node: '>=18'} @@ -10663,8 +10731,8 @@ packages: rollup: optional: true - rollup@4.52.4: - resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==} + rollup@4.52.0: + resolution: {integrity: sha512-+IuescNkTJQgX7AkIDtITipZdIGcWF0pnVvZTWStiazUmcGA2ag8dfg0urest2XlXUi9kuhfQ+qmdc5Stc3z7g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -10948,8 +11016,8 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - srvx@0.8.9: - resolution: {integrity: sha512-wYc3VLZHRzwYrWJhkEqkhLb31TI0SOkfYZDkUhXdp3NoCnNS0FqajiQszZZjfow/VYEuc6Q5sZh9nM6kPy2NBQ==} + srvx@0.8.15: + resolution: {integrity: sha512-poPs1GuctQLpiJ/1Pb8e+5b5lju9hQU7wxJ6NkYVUw7ZZExeRoYwyiaOekal+rDZc99MO/J2y9+SGFpHBKRSpQ==} engines: {node: '>=20.16.0'} hasBin: true @@ -10987,8 +11055,8 @@ packages: stream-combiner@0.0.4: resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} - streamx@2.23.0: - resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + streamx@2.22.1: + resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} @@ -11081,6 +11149,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} @@ -11149,8 +11220,8 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 typescript: '>=5.0.0' - svelte2tsx@0.7.44: - resolution: {integrity: sha512-opuH+bCboss0/ncxnfAO+qt0IAprxc8OqwuC7otafWeO5CHjJ6UAAwvQmu/+xjpCSarX8pQKydXQuoJmbCDcTg==} + svelte2tsx@0.7.43: + resolution: {integrity: sha512-TtxMuk520th4ZEvUQrhbDAyyQ1I+kc5dZCA4ChOLlbVXZfqenrY45iTH27DpLyx/u4STEz8O3hkGm5goTS8JhQ==} peerDependencies: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 @@ -11185,8 +11256,8 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar@7.5.1: - resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + tar@7.4.4: + resolution: {integrity: sha512-O1z7ajPkjTgEgmTGz0v9X4eqeEXTDREPTO77pVC1Nbs86feBU1Zhdg+edzavPmYW1olxkwsqA2v4uOw6E8LeDg==} engines: {node: '>=18'} term-size@2.2.1: @@ -11258,11 +11329,11 @@ packages: title-case@4.3.2: resolution: {integrity: sha512-I/nkcBo73mO42Idfv08jhInV61IMb61OdIFxk+B4Gu1oBjWBPOLmhZdsli+oJCVaD+86pYQA93cJfFt224ZFAA==} - tldts-core@7.0.16: - resolution: {integrity: sha512-XHhPmHxphLi+LGbH0G/O7dmUH9V65OY20R7vH8gETHsp5AZCjBk9l8sqmRKLaGOxnETU7XNSDUPtewAy/K6jbA==} + tldts-core@7.0.15: + resolution: {integrity: sha512-YBkp2VfS9VTRMPNL2PA6PMESmxV1JEVoAr5iBlZnB5JG3KUrWzNCB3yNNkRa2FZkqClaBgfNYCp8PgpYmpjkZw==} - tldts@7.0.16: - resolution: {integrity: sha512-5bdPHSwbKTeHmXrgecID4Ljff8rQjv7g8zKQPkCozRo2HWWni+p310FSn5ImI+9kWw9kK4lzOB5q/a6iv0IJsw==} + tldts@7.0.15: + resolution: {integrity: sha512-heYRCiGLhtI+U/D0V8YM3QRwPfsLJiP+HX+YwiHZTnWzjIKC+ZCxQRYlzvOoTEc6KIP62B1VeAN63diGCng2hg==} hasBin: true tmp@0.0.33: @@ -11490,6 +11561,10 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unimport@5.3.0: + resolution: {integrity: sha512-cty7t1DESgm0OPfCy9oyn5u9B5t0tMW6tH6bXTjAGIO3SkJsbg/DXYHjrPrUKqultqbAAoltAfYsuu/FEDocjg==} + engines: {node: '>=18.12.0'} + unimport@5.4.1: resolution: {integrity: sha512-wMZ2JKUCleCK2zfRHeWcbrUHKXOC3SVBYkyn/wTGzh0THX6sT4hSjuKXxKANN4/WMbT6ZPM4JzcDcnhD2x9Bpg==} engines: {node: '>=18.12.0'} @@ -11682,8 +11757,8 @@ packages: resolution: {integrity: sha512-1pGA+cU1G9feBQ1sd5FMftPuLUT8NSX880AvELhNWqoqWhe2jeSOQxjDPxlA3f1AC+Bbknl4UPKHyVXmfLZQjw==} hasBin: true - virtua@0.44.2: - resolution: {integrity: sha512-YCzmduVzt3/V0i/fZpbOmucsyHAN8CNMqmHlRQt+q9Wd1dtNrgAJpSWi3jVywu7A6t5qf+q+5kOSMMC6iwpWcw==} + virtua@0.44.3: + resolution: {integrity: sha512-KAuFPMOTW/zhnnu+3jMhAzpPnxwrE00jTwnlLJzgv5DeeQ0quEgXtUW6Wf+/z1erlItmfersBjazjC1Q6roZvA==} peerDependencies: react: '>=16.14.0' react-dom: '>=16.14.0' @@ -11773,6 +11848,16 @@ packages: '@nuxt/kit': optional: true + vite-plugin-solid@2.11.8: + resolution: {integrity: sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg==} + peerDependencies: + '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* + solid-js: ^1.7.2 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + '@testing-library/jest-dom': + optional: true + vite-plugin-solid@2.11.9: resolution: {integrity: sha512-bTA6p+bspXZsuulSd2y6aTzegF8xGaJYcq1Uyh/mv+W4DQtzCgL9nN6n2fsTaxp/dMk+ZHHKgGndlNeooqHLKw==} peerDependencies: @@ -11783,8 +11868,8 @@ packages: '@testing-library/jest-dom': optional: true - vite-plugin-vue-tracer@1.0.1: - resolution: {integrity: sha512-L5/vAhT6oYbH4RSQYGLN9VfHexWe7SGzca1pJ7oPkL6KtxWA1jbGeb3Ri1JptKzqtd42HinOq4uEYqzhVWrzig==} + vite-plugin-vue-tracer@1.0.0: + resolution: {integrity: sha512-a+UB9IwGx5uwS4uG/a9kM6fCMnxONDkOTbgCUbhFpiGhqfxrrC1+9BibV7sWwUnwj1Dg6MnRxG0trLgUZslDXA==} peerDependencies: vite: ^6.0.0 || ^7.0.0 vue: ^3.5.0 @@ -12194,21 +12279,20 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@asamuzakjp/css-color@4.0.5': + '@asamuzakjp/css-color@4.0.4': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.2 + lru-cache: 11.2.1 - '@asamuzakjp/dom-selector@6.6.1': + '@asamuzakjp/dom-selector@6.5.5': dependencies: '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.1.0 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.2 '@asamuzakjp/nwsapi@2.3.9': {} @@ -12275,7 +12359,7 @@ snapshots: dependencies: '@babel/compat-data': 7.28.4 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.3 + browserslist: 4.26.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -12903,9 +12987,9 @@ snapshots: '@esbuild/win32-x64@0.25.10': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0(jiti@2.6.1))': dependencies: - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0(jiti@2.6.1))': @@ -12951,6 +13035,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/js@9.35.0': {} + '@eslint/js@9.36.0': {} '@eslint/js@9.37.0': {} @@ -13168,12 +13254,12 @@ snapshots: '@mapbox/node-pre-gyp@2.0.0': dependencies: consola: 3.4.2 - detect-libc: 2.1.2 + detect-libc: 2.1.0 https-proxy-agent: 7.0.6 node-fetch: 2.7.0 nopt: 8.1.0 semver: 7.7.2 - tar: 7.5.1 + tar: 7.4.4 transitivePeerDependencies: - encoding - supports-color @@ -13210,23 +13296,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@microsoft/api-extractor-model@7.31.0(@types/node@24.7.0)': + '@microsoft/api-extractor-model@7.30.7(@types/node@24.7.0)': dependencies: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.16.0(@types/node@24.7.0) + '@rushstack/node-core-library': 5.14.0(@types/node@24.7.0) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.53.0(@types/node@24.7.0)': + '@microsoft/api-extractor@7.52.13(@types/node@24.7.0)': dependencies: - '@microsoft/api-extractor-model': 7.31.0(@types/node@24.7.0) + '@microsoft/api-extractor-model': 7.30.7(@types/node@24.7.0) '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.16.0(@types/node@24.7.0) - '@rushstack/rig-package': 0.6.0 - '@rushstack/terminal': 0.19.0(@types/node@24.7.0) - '@rushstack/ts-command-line': 5.1.0(@types/node@24.7.0) + '@rushstack/node-core-library': 5.14.0(@types/node@24.7.0) + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.16.0(@types/node@24.7.0) + '@rushstack/ts-command-line': 5.0.3(@types/node@24.7.0) lodash: 4.17.21 minimatch: 10.0.3 resolve: 1.22.10 @@ -13307,7 +13393,7 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@nuxt/cli@3.29.0(magicast@0.3.5)': + '@nuxt/cli@3.29.2(magicast@0.3.5)': dependencies: c12: 3.3.0(magicast@0.3.5) citty: 0.1.6 @@ -13330,7 +13416,7 @@ snapshots: pkg-types: 2.3.0 scule: 1.3.0 semver: 7.7.2 - srvx: 0.8.9 + srvx: 0.8.15 std-env: 3.9.0 tinyexec: 1.0.1 ufo: 1.6.1 @@ -13367,12 +13453,12 @@ snapshots: '@nuxt/kit': 3.19.2(magicast@0.3.5) '@vue/devtools-core': 7.7.7(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) '@vue/devtools-kit': 7.7.7 - birpc: 2.6.1 + birpc: 2.5.0 consola: 3.4.2 destr: 2.0.5 error-stack-parser-es: 1.0.5 execa: 8.0.1 - fast-npm-meta: 0.4.7 + fast-npm-meta: 0.4.6 get-port-please: 3.2.0 hookable: 5.5.3 image-meta: 0.2.1 @@ -13392,7 +13478,7 @@ snapshots: tinyglobby: 0.2.15 vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vite-plugin-inspect: 11.3.3(@nuxt/kit@3.19.2(magicast@0.3.5))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - vite-plugin-vue-tracer: 1.0.1(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) + vite-plugin-vue-tracer: 1.0.0(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) which: 5.0.0 ws: 8.18.3 transitivePeerDependencies: @@ -13410,7 +13496,7 @@ snapshots: errx: 0.1.0 exsolve: 1.0.7 ignore: 7.0.5 - jiti: 2.6.1 + jiti: 2.5.1 klona: 2.0.6 knitwork: 1.2.0 mlly: 1.8.0 @@ -13424,7 +13510,7 @@ snapshots: tinyglobby: 0.2.15 ufo: 1.6.1 unctx: 2.4.1 - unimport: 5.4.1 + unimport: 5.3.0 untyped: 2.0.0 transitivePeerDependencies: - magicast @@ -13476,17 +13562,17 @@ snapshots: git-url-parse: 16.1.0 is-docker: 3.0.0 ofetch: 1.4.1 - package-manager-detector: 1.4.0 + package-manager-detector: 1.3.0 pathe: 2.0.3 rc9: 2.1.2 std-env: 3.9.0 transitivePeerDependencies: - magicast - '@nuxt/vite-builder@4.1.3(@types/node@24.7.0)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.4)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)': + '@nuxt/vite-builder@4.1.3(@types/node@24.7.0)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.0)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)': dependencies: '@nuxt/kit': 4.1.3(magicast@0.3.5) - '@rollup/plugin-replace': 6.0.2(rollup@4.52.4) + '@rollup/plugin-replace': 6.0.2(rollup@4.52.0) '@vitejs/plugin-vue': 6.0.1(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) '@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) autoprefixer: 10.4.21(postcss@8.5.6) @@ -13506,7 +13592,7 @@ snapshots: pathe: 2.0.3 pkg-types: 2.3.0 postcss: 8.5.6 - rollup-plugin-visualizer: 6.0.4(rollup@4.52.4) + rollup-plugin-visualizer: 6.0.4(rollup@4.52.0) std-env: 3.9.0 ufo: 1.6.1 unenv: 2.0.0-rc.21 @@ -13542,66 +13628,75 @@ snapshots: '@octokit/auth-token@6.0.0': {} - '@octokit/core@7.0.5': + '@octokit/core@7.0.4': dependencies: '@octokit/auth-token': 6.0.0 - '@octokit/graphql': 9.0.2 - '@octokit/request': 10.0.5 - '@octokit/request-error': 7.0.1 + '@octokit/graphql': 9.0.1 + '@octokit/request': 10.0.3 + '@octokit/request-error': 7.0.0 '@octokit/types': 15.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 - '@octokit/endpoint@11.0.1': + '@octokit/endpoint@11.0.0': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 14.1.0 universal-user-agent: 7.0.3 - '@octokit/graphql@9.0.2': + '@octokit/graphql@9.0.1': dependencies: - '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/request': 10.0.3 + '@octokit/types': 14.1.0 universal-user-agent: 7.0.3 + '@octokit/openapi-types@25.1.0': {} + '@octokit/openapi-types@26.0.0': {} - '@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)': + '@octokit/plugin-paginate-rest@13.1.1(@octokit/core@7.0.4)': dependencies: - '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/core': 7.0.4 + '@octokit/types': 14.1.0 - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)': + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.4)': dependencies: - '@octokit/core': 7.0.5 + '@octokit/core': 7.0.4 - '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.5)': + '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.4)': dependencies: - '@octokit/core': 7.0.5 + '@octokit/core': 7.0.4 '@octokit/types': 15.0.0 - '@octokit/request-error@7.0.1': + '@octokit/request-error@7.0.0': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 14.1.0 - '@octokit/request@10.0.5': + '@octokit/request@10.0.3': dependencies: - '@octokit/endpoint': 11.0.1 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/endpoint': 11.0.0 + '@octokit/request-error': 7.0.0 + '@octokit/types': 14.1.0 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 '@octokit/rest@22.0.0': dependencies: - '@octokit/core': 7.0.5 - '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) - '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) + '@octokit/core': 7.0.4 + '@octokit/plugin-paginate-rest': 13.1.1(@octokit/core@7.0.4) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.4) + '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.4) + + '@octokit/types@14.1.0': + dependencies: + '@octokit/openapi-types': 25.1.0 '@octokit/types@15.0.0': dependencies: '@octokit/openapi-types': 26.0.0 + '@opentelemetry/api@1.9.0': + optional: true + '@oxc-minify/binding-android-arm64@0.94.0': optional: true @@ -14067,7 +14162,7 @@ snapshots: '@prefresh/babel-plugin@0.5.2': {} - '@prefresh/core@1.5.8(preact@10.27.2)': + '@prefresh/core@1.5.7(preact@10.27.2)': dependencies: preact: 10.27.2 @@ -14077,7 +14172,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@prefresh/babel-plugin': 0.5.2 - '@prefresh/core': 1.5.8(preact@10.27.2) + '@prefresh/core': 1.5.7(preact@10.27.2) '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 preact: 10.27.2 @@ -14089,15 +14184,13 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.38': {} - '@rolldown/pluginutils@1.0.0-beta.41': {} - - '@rollup/plugin-alias@5.1.1(rollup@4.52.4)': + '@rollup/plugin-alias@5.1.1(rollup@4.52.0)': optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/plugin-commonjs@28.0.6(rollup@4.52.4)': + '@rollup/plugin-commonjs@28.0.6(rollup@4.52.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) @@ -14105,131 +14198,131 @@ snapshots: magic-string: 0.30.19 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/plugin-inject@5.0.5(rollup@4.52.4)': + '@rollup/plugin-inject@5.0.5(rollup@4.52.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) estree-walker: 2.0.2 magic-string: 0.30.19 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/plugin-json@6.1.0(rollup@4.52.4)': + '@rollup/plugin-json@6.1.0(rollup@4.52.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/plugin-node-resolve@16.0.2(rollup@4.52.4)': + '@rollup/plugin-node-resolve@16.0.1(rollup@4.52.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.10 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/plugin-replace@6.0.2(rollup@4.52.4)': + '@rollup/plugin-replace@6.0.2(rollup@4.52.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) magic-string: 0.30.19 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/plugin-terser@0.4.4(rollup@4.52.4)': + '@rollup/plugin-terser@0.4.4(rollup@4.52.0)': dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 terser: 5.44.0 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/pluginutils@5.3.0(rollup@4.52.4)': + '@rollup/pluginutils@5.3.0(rollup@4.52.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - '@rollup/rollup-android-arm-eabi@4.52.4': + '@rollup/rollup-android-arm-eabi@4.52.0': optional: true - '@rollup/rollup-android-arm64@4.52.4': + '@rollup/rollup-android-arm64@4.52.0': optional: true - '@rollup/rollup-darwin-arm64@4.52.4': + '@rollup/rollup-darwin-arm64@4.52.0': optional: true - '@rollup/rollup-darwin-x64@4.52.4': + '@rollup/rollup-darwin-x64@4.52.0': optional: true - '@rollup/rollup-freebsd-arm64@4.52.4': + '@rollup/rollup-freebsd-arm64@4.52.0': optional: true - '@rollup/rollup-freebsd-x64@4.52.4': + '@rollup/rollup-freebsd-x64@4.52.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': + '@rollup/rollup-linux-arm-gnueabihf@4.52.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.4': + '@rollup/rollup-linux-arm-musleabihf@4.52.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.4': + '@rollup/rollup-linux-arm64-gnu@4.52.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.4': + '@rollup/rollup-linux-arm64-musl@4.52.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.4': + '@rollup/rollup-linux-loong64-gnu@4.52.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.4': + '@rollup/rollup-linux-ppc64-gnu@4.52.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.4': + '@rollup/rollup-linux-riscv64-gnu@4.52.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.4': + '@rollup/rollup-linux-riscv64-musl@4.52.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.4': + '@rollup/rollup-linux-s390x-gnu@4.52.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.4': + '@rollup/rollup-linux-x64-gnu@4.52.0': optional: true - '@rollup/rollup-linux-x64-musl@4.52.4': + '@rollup/rollup-linux-x64-musl@4.52.0': optional: true - '@rollup/rollup-openharmony-arm64@4.52.4': + '@rollup/rollup-openharmony-arm64@4.52.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.4': + '@rollup/rollup-win32-arm64-msvc@4.52.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.4': + '@rollup/rollup-win32-ia32-msvc@4.52.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.4': + '@rollup/rollup-win32-x64-gnu@4.52.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.4': + '@rollup/rollup-win32-x64-msvc@4.52.0': optional: true '@rtsao/scc@1.1.0': {} - '@rushstack/eslint-patch@1.13.0': {} + '@rushstack/eslint-patch@1.12.0': {} - '@rushstack/node-core-library@5.16.0(@types/node@24.7.0)': + '@rushstack/node-core-library@5.14.0(@types/node@24.7.0)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -14242,26 +14335,21 @@ snapshots: optionalDependencies: '@types/node': 24.7.0 - '@rushstack/problem-matcher@0.1.1(@types/node@24.7.0)': - optionalDependencies: - '@types/node': 24.7.0 - - '@rushstack/rig-package@0.6.0': + '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.10 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.19.0(@types/node@24.7.0)': + '@rushstack/terminal@0.16.0(@types/node@24.7.0)': dependencies: - '@rushstack/node-core-library': 5.16.0(@types/node@24.7.0) - '@rushstack/problem-matcher': 0.1.1(@types/node@24.7.0) + '@rushstack/node-core-library': 5.14.0(@types/node@24.7.0) supports-color: 8.1.1 optionalDependencies: '@types/node': 24.7.0 - '@rushstack/ts-command-line@5.1.0(@types/node@24.7.0)': + '@rushstack/ts-command-line@5.0.3(@types/node@24.7.0)': dependencies: - '@rushstack/terminal': 0.19.0(@types/node@24.7.0) + '@rushstack/terminal': 0.16.0(@types/node@24.7.0) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -14323,11 +14411,11 @@ snapshots: dependencies: solid-js: 1.9.9 - '@solidjs/start@1.2.0(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@solidjs/start@1.2.0(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@tanstack/server-functions-plugin': 1.121.21(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vinxi/plugin-directives': 0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vinxi/server-components': 0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vinxi/plugin-directives': 0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vinxi/server-components': 0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) cookie-es: 2.0.0 defu: 6.1.4 error-stack-parser: 2.1.4 @@ -14339,8 +14427,8 @@ snapshots: source-map-js: 1.2.1 terracotta: 1.0.6(solid-js@1.9.9) tinyglobby: 0.2.15 - vinxi: 0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - vite-plugin-solid: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + vinxi: 0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite-plugin-solid: 2.11.8(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) transitivePeerDependencies: - '@testing-library/jest-dom' - solid-js @@ -14360,18 +14448,18 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@sveltejs/acorn-typescript@1.0.6(acorn@8.15.0)': + '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)': dependencies: acorn: 8.15.0 - '@sveltejs/adapter-auto@6.1.1(@sveltejs/kit@2.44.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@sveltejs/adapter-auto@6.1.1(@sveltejs/kit@2.44.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: - '@sveltejs/kit': 2.44.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/kit': 2.44.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@sveltejs/kit@2.44.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/kit@2.44.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.0.0 - '@sveltejs/acorn-typescript': 1.0.6(acorn@8.15.0) + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.15.0 @@ -14386,6 +14474,8 @@ snapshots: sirv: 3.0.2 svelte: 5.39.9 vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + optionalDependencies: + '@opentelemetry/api': 1.9.0 '@sveltejs/package@2.5.4(svelte@5.39.9)(typescript@5.9.3)': dependencies: @@ -14394,7 +14484,7 @@ snapshots: sade: 1.8.1 semver: 7.7.2 svelte: 5.39.9 - svelte2tsx: 0.7.44(svelte@5.39.9)(typescript@5.9.3) + svelte2tsx: 0.7.43(svelte@5.39.9)(typescript@5.9.3) transitivePeerDependencies: - typescript @@ -14556,7 +14646,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/traverse': 7.28.4 '@babel/types': 7.28.4 - '@tanstack/router-utils': 1.132.31 + '@tanstack/router-utils': 1.131.2 babel-dead-code-elimination: 1.0.10 tiny-invariant: 1.3.3 vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) @@ -14569,16 +14659,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@tanstack/router-utils@1.132.31': + '@tanstack/router-utils@1.131.2': dependencies: '@babel/core': 7.28.4 '@babel/generator': 7.28.3 '@babel/parser': 7.28.4 '@babel/preset-typescript': 7.27.1(@babel/core@7.28.4) - ansis: 4.2.0 + ansis: 4.1.0 diff: 8.0.2 - fast-glob: 3.3.3 - pathe: 2.0.3 transitivePeerDependencies: - supports-color @@ -14620,15 +14708,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.0(@types/react@19.2.0))(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 '@testing-library/dom': 10.4.1 react: 19.2.0 react-dom: 19.2.0(react@19.2.0) optionalDependencies: - '@types/react': 19.2.0 - '@types/react-dom': 19.2.0(@types/react@19.2.0) + '@types/react': 19.1.13 + '@types/react-dom': 19.1.9(@types/react@19.1.13) '@ts-morph/common@0.27.0': dependencies: @@ -14771,11 +14859,11 @@ snapshots: '@types/ps-tree@1.1.6': {} - '@types/react-dom@19.2.0(@types/react@19.2.0)': + '@types/react-dom@19.1.9(@types/react@19.1.13)': dependencies: - '@types/react': 19.2.0 + '@types/react': 19.1.13 - '@types/react@19.2.0': + '@types/react@19.1.13': dependencies: csstype: 3.1.3 @@ -14799,15 +14887,15 @@ snapshots: '@types/which@3.0.4': {} - '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.45.0 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -14850,14 +14938,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.45.0 debug: 4.4.3 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -14922,13 +15010,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.45.0 '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -14994,13 +15082,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -15104,10 +15192,10 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/nft@0.30.2(rollup@4.52.4)': + '@vercel/nft@0.30.1(rollup@4.52.0)': dependencies: '@mapbox/node-pre-gyp': 2.0.0 - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) async-sema: 3.1.1 @@ -15143,7 +15231,7 @@ snapshots: untun: 0.1.3 uqr: 0.1.2 - '@vinxi/plugin-directives@0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vinxi/plugin-directives@0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@babel/parser': 7.28.4 acorn: 8.15.0 @@ -15154,18 +15242,18 @@ snapshots: magicast: 0.2.11 recast: 0.23.11 tslib: 2.8.1 - vinxi: 0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vinxi: 0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vinxi/server-components@0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vinxi/server-components@0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@vinxi/plugin-directives': 0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vinxi/plugin-directives': 0.5.1(vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) acorn: 8.15.0 acorn-loose: 8.5.2 acorn-typescript: 1.4.13(acorn@8.15.0) astring: 1.9.0 magicast: 0.2.11 recast: 0.23.11 - vinxi: 0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vinxi: 0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: @@ -15184,7 +15272,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.41 + '@rolldown/pluginutils': 1.0.0-beta.38 '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.4) vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vue: 3.5.22(typescript@5.9.3) @@ -15221,7 +15309,7 @@ snapshots: dependencies: '@vitest/utils': 3.2.4 pathe: 2.0.3 - strip-literal: 3.1.0 + strip-literal: 3.0.0 '@vitest/snapshot@3.2.4': dependencies: @@ -15298,6 +15386,14 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@3.5.21': + dependencies: + '@babel/parser': 7.28.4 + '@vue/shared': 3.5.21 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + '@vue/compiler-core@3.5.22': dependencies: '@babel/parser': 7.28.4 @@ -15311,6 +15407,11 @@ snapshots: '@vue/compiler-core': 3.4.19 '@vue/shared': 3.4.19 + '@vue/compiler-dom@3.5.21': + dependencies: + '@vue/compiler-core': 3.5.21 + '@vue/shared': 3.5.21 + '@vue/compiler-dom@3.5.22': dependencies: '@vue/compiler-core': 3.5.22 @@ -15372,7 +15473,7 @@ snapshots: '@vue/devtools-kit@7.7.7': dependencies: '@vue/devtools-shared': 7.7.7 - birpc: 2.6.1 + birpc: 2.5.0 hookable: 5.5.3 mitt: 3.0.1 perfect-debounce: 1.0.0 @@ -15386,9 +15487,9 @@ snapshots: '@vue/language-core@2.2.0(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 - '@vue/compiler-dom': 3.5.22 + '@vue/compiler-dom': 3.5.21 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.22 + '@vue/shared': 3.5.21 alien-signals: 0.4.14 minimatch: 9.0.5 muggle-string: 0.4.1 @@ -15396,12 +15497,13 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@vue/language-core@3.1.0(typescript@5.9.3)': + '@vue/language-core@3.0.7(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 '@vue/compiler-dom': 3.5.22 + '@vue/compiler-vue2': 2.7.16 '@vue/shared': 3.5.22 - alien-signals: 3.0.0 + alien-signals: 2.0.7 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.3 @@ -15432,6 +15534,8 @@ snapshots: '@vue/shared@3.4.19': {} + '@vue/shared@3.5.21': {} + '@vue/shared@3.5.22': {} JSONStream@1.3.5: @@ -15503,7 +15607,7 @@ snapshots: alien-signals@0.4.14: {} - alien-signals@3.0.0: {} + alien-signals@2.0.7: {} all-contributors-cli@6.26.1: dependencies: @@ -15532,7 +15636,7 @@ snapshots: dependencies: type-fest: 0.21.3 - ansi-escapes@7.1.1: + ansi-escapes@7.1.0: dependencies: environment: 1.1.0 @@ -15558,7 +15662,7 @@ snapshots: ansi-wrap@0.1.0: {} - ansis@4.2.0: {} + ansis@4.1.0: {} any-promise@1.3.0: {} @@ -15714,8 +15818,8 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: - browserslist: 4.26.3 - caniuse-lite: 1.0.30001748 + browserslist: 4.26.2 + caniuse-lite: 1.0.30001743 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -15730,7 +15834,7 @@ snapshots: axobject-query@4.1.0: {} - b4a@1.7.3: {} + b4a@1.7.1: {} babel-dead-code-elimination@1.0.10: dependencies: @@ -15766,11 +15870,12 @@ snapshots: balanced-match@1.0.2: {} - bare-events@2.7.0: {} + bare-events@2.7.0: + optional: true base64-js@1.5.1: {} - baseline-browser-mapping@2.8.12: {} + baseline-browser-mapping@2.8.6: {} before-after-hook@4.0.0: {} @@ -15786,7 +15891,7 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 - birpc@2.6.1: {} + birpc@2.5.0: {} bl@4.1.0: dependencies: @@ -15822,18 +15927,18 @@ snapshots: browserslist@4.23.3: dependencies: - caniuse-lite: 1.0.30001748 - electron-to-chromium: 1.5.230 - node-releases: 2.0.23 + caniuse-lite: 1.0.30001743 + electron-to-chromium: 1.5.222 + node-releases: 2.0.21 update-browserslist-db: 1.1.3(browserslist@4.23.3) - browserslist@4.26.3: + browserslist@4.26.2: dependencies: - baseline-browser-mapping: 2.8.12 - caniuse-lite: 1.0.30001748 - electron-to-chromium: 1.5.230 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) + baseline-browser-mapping: 2.8.6 + caniuse-lite: 1.0.30001743 + electron-to-chromium: 1.5.222 + node-releases: 2.0.21 + update-browserslist-db: 1.1.3(browserslist@4.26.2) buffer-crc32@1.0.0: {} @@ -15871,7 +15976,7 @@ snapshots: dotenv: 17.2.3 exsolve: 1.0.7 giget: 2.0.0 - jiti: 2.6.1 + jiti: 2.5.1 ohash: 2.0.11 pathe: 2.0.3 perfect-debounce: 2.0.0 @@ -15909,12 +16014,12 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.26.3 - caniuse-lite: 1.0.30001748 + browserslist: 4.26.2 + caniuse-lite: 1.0.30001743 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001748: {} + caniuse-lite@1.0.30001743: {} ccount@2.0.1: {} @@ -16140,7 +16245,7 @@ snapshots: dependencies: '@types/node': 24.7.0 cosmiconfig: 9.0.0(typescript@5.9.3) - jiti: 2.6.1 + jiti: 2.5.1 typescript: 5.9.3 cosmiconfig@8.3.6(typescript@5.9.3): @@ -16219,7 +16324,7 @@ snapshots: cssnano-preset-default@7.0.9(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 css-declaration-sorter: 7.3.0(postcss@8.5.6) cssnano-utils: 5.0.1(postcss@8.5.6) postcss: 8.5.6 @@ -16271,7 +16376,7 @@ snapshots: cssstyle@5.3.1(postcss@8.4.49): dependencies: - '@asamuzakjp/css-color': 4.0.5 + '@asamuzakjp/css-color': 4.0.4 '@csstools/css-syntax-patches-for-csstree': 1.0.14(postcss@8.4.49) css-tree: 3.1.0 transitivePeerDependencies: @@ -16280,7 +16385,7 @@ snapshots: cssstyle@5.3.1(postcss@8.5.6): dependencies: - '@asamuzakjp/css-color': 4.0.5 + '@asamuzakjp/css-color': 4.0.4 '@csstools/css-syntax-patches-for-csstree': 1.0.14(postcss@8.5.6) css-tree: 3.1.0 transitivePeerDependencies: @@ -16324,7 +16429,7 @@ snapshots: '@deno/shim-deno': 0.19.2 undici-types: 5.28.4 - db0@0.3.4: {} + db0@0.3.2: {} de-indent@1.0.2: {} @@ -16401,7 +16506,7 @@ snapshots: detect-libc@1.0.3: {} - detect-libc@2.1.2: {} + detect-libc@2.1.0: {} devalue@5.3.2: {} @@ -16482,7 +16587,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.230: {} + electron-to-chromium@1.5.222: {} emoji-regex-xs@1.0.0: {} @@ -16683,19 +16788,19 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@15.5.4(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@15.5.4(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 15.5.4 - '@rushstack/eslint-patch': 1.13.0 - '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.36.0(jiti@2.6.1) + '@rushstack/eslint-patch': 1.12.0 + '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.35.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.36.0(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.36.0(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.36.0(jiti@2.6.1)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.36.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.6.1)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.35.0(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@9.35.0(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.35.0(jiti@2.6.1)) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -16706,12 +16811,12 @@ snapshots: eslint-config-next@15.5.4(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 15.5.4 - '@rushstack/eslint-patch': 1.13.0 + '@rushstack/eslint-patch': 1.12.0 '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) eslint: 9.37.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.37.0(jiti@2.6.1)) @@ -16729,7 +16834,7 @@ snapshots: '@babel/eslint-parser': 7.28.4(@babel/core@7.28.4)(eslint@9.37.0(jiti@2.6.1)) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.4) '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@eslint/js': 9.37.0 + '@eslint/js': 9.36.0 eslint: 9.37.0(jiti@2.6.1) eslint-plugin-compat: 6.0.2(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.37.0(jiti@2.6.1)) @@ -16750,55 +16855,55 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 9.37.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.37.0(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.37.0(jiti@2.6.1) get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.36.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.35.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) eslint: 9.37.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.37.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -16816,15 +16921,15 @@ snapshots: dependencies: '@mdn/browser-compat-data': 5.7.6 ast-metadata-inferer: 0.8.1 - browserslist: 4.26.3 - caniuse-lite: 1.0.30001748 + browserslist: 4.26.2 + caniuse-lite: 1.0.30001743 eslint: 9.37.0(jiti@2.6.1) find-up: 5.0.0 globals: 15.15.0 lodash.memoize: 4.1.2 semver: 7.7.2 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.36.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -16833,9 +16938,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)))(eslint@9.36.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)))(eslint@9.35.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16847,7 +16952,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.45.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16864,7 +16969,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.37.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16911,7 +17016,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.36.0(jiti@2.6.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.35.0(jiti@2.6.1)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -16921,7 +17026,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -16958,9 +17063,9 @@ snapshots: optionalDependencies: eslint-config-prettier: 10.1.8(eslint@9.37.0(jiti@2.6.1)) - eslint-plugin-react-hooks@5.2.0(eslint@9.36.0(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.6.1)): dependencies: - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) eslint-plugin-react-hooks@5.2.0(eslint@9.37.0(jiti@2.6.1)): dependencies: @@ -16976,7 +17081,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@9.36.0(jiti@2.6.1)): + eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.6.1)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -16984,7 +17089,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.36.0(jiti@2.6.1) + eslint: 9.35.0(jiti@2.6.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -17036,15 +17141,15 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.36.0(jiti@2.6.1): + eslint@9.35.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 '@eslint/config-helpers': 0.3.1 '@eslint/core': 0.15.2 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.36.0 + '@eslint/js': 9.35.0 '@eslint/plugin-kit': 0.3.5 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 @@ -17201,10 +17306,6 @@ snapshots: eventemitter3@5.0.1: {} - events-universal@1.0.1: - dependencies: - bare-events: 2.7.0 - events@3.3.0: {} execa@8.0.1: @@ -17288,7 +17389,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-npm-meta@0.4.7: {} + fast-npm-meta@0.4.6: {} fast-uri@3.1.0: {} @@ -17382,7 +17483,7 @@ snapshots: dependencies: magic-string: 0.30.19 mlly: 1.8.0 - rollup: 4.52.4 + rollup: 4.52.0 flagged-respawn@2.0.0: {} @@ -17471,8 +17572,6 @@ snapshots: fx@39.1.0: {} - generator-function@2.0.1: {} - gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -17975,7 +18074,7 @@ snapshots: interpret@3.1.1: {} - ioredis@5.8.1: + ioredis@5.7.0: dependencies: '@ioredis/commands': 1.4.0 cluster-key-slot: 1.1.2 @@ -18075,10 +18174,9 @@ snapshots: dependencies: get-east-asian-width: 1.4.0 - is-generator-function@1.1.2: + is-generator-function@1.1.0: dependencies: call-bound: 1.0.4 - generator-function: 2.0.1 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 @@ -18267,6 +18365,8 @@ snapshots: jiti@1.21.7: {} + jiti@2.5.1: {} + jiti@2.6.1: {} jju@1.4.0: {} @@ -18288,7 +18388,7 @@ snapshots: jsdom@27.0.0(postcss@8.4.49): dependencies: - '@asamuzakjp/dom-selector': 6.6.1 + '@asamuzakjp/dom-selector': 6.5.5 cssstyle: 5.3.1(postcss@8.4.49) data-urls: 6.0.0 decimal.js: 10.6.0 @@ -18317,7 +18417,7 @@ snapshots: jsdom@27.0.0(postcss@8.5.6): dependencies: - '@asamuzakjp/dom-selector': 6.6.1 + '@asamuzakjp/dom-selector': 6.5.5 cssstyle: 5.3.1(postcss@8.5.6) data-urls: 6.0.0 decimal.js: 10.6.0 @@ -18518,7 +18618,7 @@ snapshots: get-port-please: 3.2.0 h3: 1.15.4 http-shutdown: 1.2.2 - jiti: 2.6.1 + jiti: 2.5.1 mlly: 1.8.0 node-forge: 1.3.1 pathe: 1.1.2 @@ -18618,7 +18718,7 @@ snapshots: log-update@6.1.0: dependencies: - ansi-escapes: 7.1.1 + ansi-escapes: 7.1.0 cli-cursor: 5.0.0 slice-ansi: 7.1.2 strip-ansi: 7.1.2 @@ -18640,7 +18740,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.2: {} + lru-cache@11.2.1: {} lru-cache@5.1.1: dependencies: @@ -19182,23 +19282,23 @@ snapshots: nanotar@0.2.0: {} - napi-postinstall@0.3.4: {} + napi-postinstall@0.3.3: {} natural-compare@1.4.0: {} neo-async@2.6.2: {} - next-cloudinary@6.16.0(next@15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0): + next-cloudinary@6.16.0(next@15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0): dependencies: '@cloudinary-util/types': 1.5.10 '@cloudinary-util/url-loader': 5.10.4 '@cloudinary-util/util': 4.0.0 - next: 15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next: 15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 - next-seo@6.8.0(next@15.5.4(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + next-seo@6.8.0(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - next: 15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next: 15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) @@ -19207,11 +19307,11 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - next@15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + next@15.5.4(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@next/env': 15.5.4 '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001748 + caniuse-lite: 1.0.30001743 postcss: 8.4.31 react: 19.2.0 react-dom: 19.2.0(react@19.2.0) @@ -19225,6 +19325,7 @@ snapshots: '@next/swc-linux-x64-musl': 15.5.4 '@next/swc-win32-arm64-msvc': 15.5.4 '@next/swc-win32-x64-msvc': 15.5.4 + '@opentelemetry/api': 1.9.0 '@playwright/test': 1.56.0 sharp: 0.34.4 transitivePeerDependencies: @@ -19234,14 +19335,14 @@ snapshots: nitropack@2.12.6: dependencies: '@cloudflare/kv-asset-handler': 0.4.0 - '@rollup/plugin-alias': 5.1.1(rollup@4.52.4) - '@rollup/plugin-commonjs': 28.0.6(rollup@4.52.4) - '@rollup/plugin-inject': 5.0.5(rollup@4.52.4) - '@rollup/plugin-json': 6.1.0(rollup@4.52.4) - '@rollup/plugin-node-resolve': 16.0.2(rollup@4.52.4) - '@rollup/plugin-replace': 6.0.2(rollup@4.52.4) - '@rollup/plugin-terser': 0.4.4(rollup@4.52.4) - '@vercel/nft': 0.30.2(rollup@4.52.4) + '@rollup/plugin-alias': 5.1.1(rollup@4.52.0) + '@rollup/plugin-commonjs': 28.0.6(rollup@4.52.0) + '@rollup/plugin-inject': 5.0.5(rollup@4.52.0) + '@rollup/plugin-json': 6.1.0(rollup@4.52.0) + '@rollup/plugin-node-resolve': 16.0.1(rollup@4.52.0) + '@rollup/plugin-replace': 6.0.2(rollup@4.52.0) + '@rollup/plugin-terser': 0.4.4(rollup@4.52.0) + '@vercel/nft': 0.30.1(rollup@4.52.0) archiver: 7.0.1 c12: 3.3.0(magicast@0.3.5) chokidar: 4.0.3 @@ -19252,7 +19353,7 @@ snapshots: cookie-es: 2.0.0 croner: 9.1.0 crossws: 0.3.5 - db0: 0.3.4 + db0: 0.3.2 defu: 6.1.4 destr: 2.0.5 dot-prop: 9.0.0 @@ -19265,8 +19366,8 @@ snapshots: h3: 1.15.4 hookable: 5.5.3 httpxy: 0.1.7 - ioredis: 5.8.1 - jiti: 2.6.1 + ioredis: 5.7.0 + jiti: 2.5.1 klona: 2.0.6 knitwork: 1.2.0 listhen: 1.9.0 @@ -19283,8 +19384,8 @@ snapshots: pkg-types: 2.3.0 pretty-bytes: 7.1.0 radix3: 1.1.2 - rollup: 4.52.4 - rollup-plugin-visualizer: 6.0.4(rollup@4.52.4) + rollup: 4.52.0 + rollup-plugin-visualizer: 6.0.3(rollup@4.52.0) scule: 1.3.0 semver: 7.7.2 serve-placeholder: 2.0.2 @@ -19296,9 +19397,9 @@ snapshots: uncrypto: 0.1.3 unctx: 2.4.1 unenv: 2.0.0-rc.21 - unimport: 5.4.1 + unimport: 5.3.0 unplugin-utils: 0.3.0 - unstorage: 1.17.1(db0@0.3.4)(ioredis@5.8.1) + unstorage: 1.17.1(db0@0.3.2)(ioredis@5.7.0) untyped: 2.0.0 unwasm: 0.3.11 youch: 4.1.0-beta.11 @@ -19383,7 +19484,7 @@ snapshots: transitivePeerDependencies: - '@types/node' - node-releases@2.0.23: {} + node-releases@2.0.21: {} nopt@8.1.0: dependencies: @@ -19406,15 +19507,15 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxt@4.1.3(@parcel/watcher@2.5.1)(@types/node@24.7.0)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.8.1)(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.4)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(yaml@2.8.1): + nuxt@4.1.3(@parcel/watcher@2.5.1)(@types/node@24.7.0)(@vue/compiler-sfc@3.5.22)(db0@0.3.2)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.7.0)(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.0)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(yaml@2.8.1): dependencies: - '@nuxt/cli': 3.29.0(magicast@0.3.5) + '@nuxt/cli': 3.29.2(magicast@0.3.5) '@nuxt/devalue': 2.0.2 '@nuxt/devtools': 2.6.5(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) '@nuxt/kit': 4.1.3(magicast@0.3.5) '@nuxt/schema': 4.1.3 '@nuxt/telemetry': 2.6.6(magicast@0.3.5) - '@nuxt/vite-builder': 4.1.3(@types/node@24.7.0)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.4)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1) + '@nuxt/vite-builder': 4.1.3(@types/node@24.7.0)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.25.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.0)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1) '@unhead/vue': 2.0.17(vue@3.5.22(typescript@5.9.3)) '@vue/shared': 3.5.22 c12: 3.3.0(magicast@0.3.5) @@ -19465,7 +19566,7 @@ snapshots: unimport: 5.4.1 unplugin: 2.3.10 unplugin-vue-router: 0.15.0(@vue/compiler-sfc@3.5.22)(typescript@5.9.3)(vue-router@4.5.1(vue@3.5.22(typescript@5.9.3)))(vue@3.5.22(typescript@5.9.3)) - unstorage: 1.17.1(db0@0.3.4)(ioredis@5.8.1) + unstorage: 1.17.1(db0@0.3.2)(ioredis@5.7.0) untyped: 2.0.0 vue: 3.5.22(typescript@5.9.3) vue-bundle-renderer: 2.2.0 @@ -19783,7 +19884,7 @@ snapshots: dependencies: quansync: 0.2.11 - package-manager-detector@1.4.0: {} + package-manager-detector@1.3.0: {} parent-module@1.0.1: dependencies: @@ -19842,6 +19943,11 @@ snapshots: parseurl@1.3.3: {} + pascal-case@3.1.2: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + path-browserify@1.0.1: {} path-exists@3.0.0: {} @@ -19965,7 +20071,7 @@ snapshots: postcss-colormin@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.5.6 @@ -19973,7 +20079,7 @@ snapshots: postcss-convert-values@7.0.7(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -20019,7 +20125,7 @@ snapshots: postcss-merge-rules@7.0.4(postcss@8.4.49): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 caniuse-api: 3.0.0 cssnano-utils: 5.0.1(postcss@8.4.49) postcss: 8.4.49 @@ -20027,7 +20133,7 @@ snapshots: postcss-merge-rules@7.0.6(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 caniuse-api: 3.0.0 cssnano-utils: 5.0.1(postcss@8.5.6) postcss: 8.5.6 @@ -20047,7 +20153,7 @@ snapshots: postcss-minify-params@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 cssnano-utils: 5.0.1(postcss@8.5.6) postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -20100,7 +20206,7 @@ snapshots: postcss-normalize-unicode@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -20127,7 +20233,7 @@ snapshots: postcss-reduce-initial@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 caniuse-api: 3.0.0 postcss: 8.5.6 @@ -20580,41 +20686,50 @@ snapshots: rfdc@1.4.1: {} - rollup-plugin-visualizer@6.0.4(rollup@4.52.4): + rollup-plugin-visualizer@6.0.3(rollup@4.52.0): dependencies: open: 8.4.2 picomatch: 4.0.3 source-map: 0.7.6 yargs: 17.7.2 optionalDependencies: - rollup: 4.52.4 + rollup: 4.52.0 - rollup@4.52.4: + rollup-plugin-visualizer@6.0.4(rollup@4.52.0): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.52.0 + + rollup@4.52.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.4 - '@rollup/rollup-android-arm64': 4.52.4 - '@rollup/rollup-darwin-arm64': 4.52.4 - '@rollup/rollup-darwin-x64': 4.52.4 - '@rollup/rollup-freebsd-arm64': 4.52.4 - '@rollup/rollup-freebsd-x64': 4.52.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 - '@rollup/rollup-linux-arm-musleabihf': 4.52.4 - '@rollup/rollup-linux-arm64-gnu': 4.52.4 - '@rollup/rollup-linux-arm64-musl': 4.52.4 - '@rollup/rollup-linux-loong64-gnu': 4.52.4 - '@rollup/rollup-linux-ppc64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-musl': 4.52.4 - '@rollup/rollup-linux-s390x-gnu': 4.52.4 - '@rollup/rollup-linux-x64-gnu': 4.52.4 - '@rollup/rollup-linux-x64-musl': 4.52.4 - '@rollup/rollup-openharmony-arm64': 4.52.4 - '@rollup/rollup-win32-arm64-msvc': 4.52.4 - '@rollup/rollup-win32-ia32-msvc': 4.52.4 - '@rollup/rollup-win32-x64-gnu': 4.52.4 - '@rollup/rollup-win32-x64-msvc': 4.52.4 + '@rollup/rollup-android-arm-eabi': 4.52.0 + '@rollup/rollup-android-arm64': 4.52.0 + '@rollup/rollup-darwin-arm64': 4.52.0 + '@rollup/rollup-darwin-x64': 4.52.0 + '@rollup/rollup-freebsd-arm64': 4.52.0 + '@rollup/rollup-freebsd-x64': 4.52.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.0 + '@rollup/rollup-linux-arm-musleabihf': 4.52.0 + '@rollup/rollup-linux-arm64-gnu': 4.52.0 + '@rollup/rollup-linux-arm64-musl': 4.52.0 + '@rollup/rollup-linux-loong64-gnu': 4.52.0 + '@rollup/rollup-linux-ppc64-gnu': 4.52.0 + '@rollup/rollup-linux-riscv64-gnu': 4.52.0 + '@rollup/rollup-linux-riscv64-musl': 4.52.0 + '@rollup/rollup-linux-s390x-gnu': 4.52.0 + '@rollup/rollup-linux-x64-gnu': 4.52.0 + '@rollup/rollup-linux-x64-musl': 4.52.0 + '@rollup/rollup-openharmony-arm64': 4.52.0 + '@rollup/rollup-win32-arm64-msvc': 4.52.0 + '@rollup/rollup-win32-ia32-msvc': 4.52.0 + '@rollup/rollup-win32-x64-gnu': 4.52.0 + '@rollup/rollup-win32-x64-msvc': 4.52.0 fsevents: 2.3.3 rrweb-cssom@0.8.0: {} @@ -20785,7 +20900,7 @@ snapshots: sharp@0.34.4: dependencies: '@img/colour': 1.0.0 - detect-libc: 2.1.2 + detect-libc: 2.1.0 semver: 7.7.2 optionalDependencies: '@img/sharp-darwin-arm64': 0.34.4 @@ -20969,7 +21084,7 @@ snapshots: sprintf-js@1.0.3: {} - srvx@0.8.9: + srvx@0.8.15: dependencies: cookie-es: 2.0.0 @@ -20998,11 +21113,12 @@ snapshots: dependencies: duplexer: 0.1.2 - streamx@2.23.0: + streamx@2.22.1: dependencies: - events-universal: 1.0.1 fast-fifo: 1.3.2 text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.7.0 transitivePeerDependencies: - react-native-b4a @@ -21120,6 +21236,10 @@ snapshots: strip-json-comments@3.1.1: {} + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 @@ -21143,7 +21263,7 @@ snapshots: stylehacks@7.0.6(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 postcss: 8.5.6 postcss-selector-parser: 7.1.0 @@ -21189,10 +21309,10 @@ snapshots: transitivePeerDependencies: - picomatch - svelte2tsx@0.7.44(svelte@5.39.9)(typescript@5.9.3): + svelte2tsx@0.7.43(svelte@5.39.9)(typescript@5.9.3): dependencies: dedent-js: 1.0.1 - scule: 1.3.0 + pascal-case: 3.1.2 svelte: 5.39.9 typescript: 5.9.3 @@ -21200,7 +21320,7 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 - '@sveltejs/acorn-typescript': 1.0.6(acorn@8.15.0) + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) '@types/estree': 1.0.8 acorn: 8.15.0 aria-query: 5.3.2 @@ -21243,13 +21363,13 @@ snapshots: tar-stream@3.1.7: dependencies: - b4a: 1.7.3 + b4a: 1.7.1 fast-fifo: 1.3.2 - streamx: 2.23.0 + streamx: 2.22.1 transitivePeerDependencies: - react-native-b4a - tar@7.5.1: + tar@7.4.4: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -21273,7 +21393,7 @@ snapshots: text-decoder@1.2.3: dependencies: - b4a: 1.7.3 + b4a: 1.7.1 transitivePeerDependencies: - react-native-b4a @@ -21317,11 +21437,11 @@ snapshots: title-case@4.3.2: {} - tldts-core@7.0.16: {} + tldts-core@7.0.15: {} - tldts@7.0.16: + tldts@7.0.15: dependencies: - tldts-core: 7.0.16 + tldts-core: 7.0.15 tmp@0.0.33: dependencies: @@ -21343,7 +21463,7 @@ snapshots: tough-cookie@6.0.0: dependencies: - tldts: 7.0.16 + tldts: 7.0.15 tr46@0.0.3: {} @@ -21403,7 +21523,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.0(@microsoft/api-extractor@7.53.0(@types/node@24.7.0))(@swc/core@1.13.5(@swc/helpers@0.5.17))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): + tsup@8.5.0(@microsoft/api-extractor@7.52.13(@types/node@24.7.0))(@swc/core@1.13.5(@swc/helpers@0.5.17))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.10) cac: 6.7.14 @@ -21416,14 +21536,14 @@ snapshots: picocolors: 1.1.1 postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(yaml@2.8.1) resolve-from: 5.0.0 - rollup: 4.52.4 + rollup: 4.52.0 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tinyexec: 0.3.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: - '@microsoft/api-extractor': 7.53.0(@types/node@24.7.0) + '@microsoft/api-extractor': 7.52.13(@types/node@24.7.0) '@swc/core': 1.13.5(@swc/helpers@0.5.17) postcss: 8.5.6 typescript: 5.9.3 @@ -21560,6 +21680,23 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 + unimport@5.3.0: + dependencies: + acorn: 8.15.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.1.2 + magic-string: 0.30.19 + mlly: 1.8.0 + pathe: 2.0.3 + picomatch: 4.0.3 + pkg-types: 2.3.0 + scule: 1.3.0 + strip-literal: 3.0.0 + tinyglobby: 0.2.15 + unplugin: 2.3.10 + unplugin-utils: 0.3.0 + unimport@5.4.1: dependencies: acorn: 8.15.0 @@ -21645,7 +21782,7 @@ snapshots: dependencies: '@vue-macros/common': 3.0.0-beta.16(vue@3.5.22(typescript@5.9.3)) '@vue/compiler-sfc': 3.5.22 - '@vue/language-core': 3.1.0(typescript@5.9.3) + '@vue/language-core': 3.0.7(typescript@5.9.3) ast-walker-scope: 0.8.2 chokidar: 4.0.3 json5: 2.2.3 @@ -21675,7 +21812,7 @@ snapshots: unrs-resolver@1.11.1: dependencies: - napi-postinstall: 0.3.4 + napi-postinstall: 0.3.3 optionalDependencies: '@unrs/resolver-binding-android-arm-eabi': 1.11.1 '@unrs/resolver-binding-android-arm64': 1.11.1 @@ -21697,7 +21834,7 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - unstorage@1.17.1(db0@0.3.4)(ioredis@5.8.1): + unstorage@1.17.1(db0@0.3.2)(ioredis@5.7.0): dependencies: anymatch: 3.1.3 chokidar: 4.0.3 @@ -21708,8 +21845,8 @@ snapshots: ofetch: 1.4.1 ufo: 1.6.1 optionalDependencies: - db0: 0.3.4 - ioredis: 5.8.1 + db0: 0.3.2 + ioredis: 5.7.0 untun@0.1.3: dependencies: @@ -21721,7 +21858,7 @@ snapshots: dependencies: citty: 0.1.6 defu: 6.1.4 - jiti: 2.6.1 + jiti: 2.5.1 knitwork: 1.2.0 scule: 1.3.0 @@ -21740,9 +21877,9 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - update-browserslist-db@1.1.3(browserslist@4.26.3): + update-browserslist-db@1.1.3(browserslist@4.26.2): dependencies: - browserslist: 4.26.3 + browserslist: 4.26.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -21792,7 +21929,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.4)(ioredis@5.8.1)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vinxi@0.5.8(@types/node@24.7.0)(db0@0.3.2)(ioredis@5.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: '@babel/core': 7.28.4 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) @@ -21825,7 +21962,7 @@ snapshots: ufo: 1.6.1 unctx: 2.4.1 unenv: 1.10.0 - unstorage: 1.17.1(db0@0.3.4)(ioredis@5.8.1) + unstorage: 1.17.1(db0@0.3.2)(ioredis@5.7.0) vite: 6.3.6(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) zod: 3.25.76 transitivePeerDependencies: @@ -21872,7 +22009,7 @@ snapshots: - xml2js - yaml - virtua@0.44.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(solid-js@1.9.9)(svelte@5.39.9)(vue@3.5.22(typescript@5.9.3)): + virtua@0.44.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(solid-js@1.9.9)(svelte@5.39.9)(vue@3.5.22(typescript@5.9.3)): optionalDependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) @@ -21882,7 +22019,7 @@ snapshots: vite-dev-rpc@1.1.0(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): dependencies: - birpc: 2.6.1 + birpc: 2.5.0 vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vite-hot-client: 2.1.0(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) @@ -21927,10 +22064,10 @@ snapshots: optionator: 0.9.4 typescript: 5.9.3 - vite-plugin-dts@4.5.4(@types/node@24.7.0)(rollup@4.52.4)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): + vite-plugin-dts@4.5.4(@types/node@24.7.0)(rollup@4.52.0)(typescript@5.9.3)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): dependencies: - '@microsoft/api-extractor': 7.53.0(@types/node@24.7.0) - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@microsoft/api-extractor': 7.52.13(@types/node@24.7.0) + '@rollup/pluginutils': 5.3.0(rollup@4.52.0) '@volar/typescript': 2.4.23 '@vue/language-core': 2.2.0(typescript@5.9.3) compare-versions: 6.1.1 @@ -21948,7 +22085,7 @@ snapshots: vite-plugin-inspect@11.3.3(@nuxt/kit@3.19.2(magicast@0.3.5))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): dependencies: - ansis: 4.2.0 + ansis: 4.1.0 debug: 4.4.3 error-stack-parser-es: 1.0.5 ohash: 2.0.11 @@ -21963,6 +22100,21 @@ snapshots: transitivePeerDependencies: - supports-color + vite-plugin-solid@2.11.8(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): + dependencies: + '@babel/core': 7.28.4 + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.9.9(@babel/core@7.28.4)(solid-js@1.9.9) + merge-anything: 5.1.7 + solid-js: 1.9.9 + solid-refresh: 0.6.3(solid-js@1.9.9) + vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + optionalDependencies: + '@testing-library/jest-dom': 6.9.1 + transitivePeerDependencies: + - supports-color + vite-plugin-solid@2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): dependencies: '@babel/core': 7.28.4 @@ -21978,7 +22130,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-tracer@1.0.1(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)): + vite-plugin-vue-tracer@1.0.0(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.25.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)): dependencies: estree-walker: 3.0.3 exsolve: 1.0.7 @@ -22015,7 +22167,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.4 + rollup: 4.52.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.7.0 @@ -22032,7 +22184,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.4 + rollup: 4.52.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.7.0 @@ -22173,7 +22325,7 @@ snapshots: is-async-function: 2.1.1 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.2 + is-generator-function: 1.1.0 is-regex: 1.2.1 is-weakref: 1.1.1 isarray: 2.0.5 diff --git a/shared/package.json b/shared/package.json index 2962ff37a5..309c360352 100644 --- a/shared/package.json +++ b/shared/package.json @@ -4,6 +4,7 @@ "main": "src/index.ts", "private": true, "dependencies": { + "@zag-js/image-cropper": "workspace:*", "@zag-js/tour": "workspace:*" } } diff --git a/shared/src/controls.ts b/shared/src/controls.ts index 293293dde3..bafceab9a8 100644 --- a/shared/src/controls.ts +++ b/shared/src/controls.ts @@ -308,3 +308,14 @@ export const bottomSheetControls = defineControls({ export const scrollAreaControls = defineControls({ dir: { type: "select", options: ["ltr", "rtl"] as const, defaultValue: "ltr" }, }) + +export const imageCropperControls = defineControls({ + aspectRatio: { type: "number" }, + minWidth: { type: "number", defaultValue: 40 }, + minHeight: { type: "number", defaultValue: 40 }, + maxWidth: { type: "number" }, + maxHeight: { type: "number" }, + zoomStep: { type: "number", defaultValue: 0.1 }, + minZoom: { type: "number", defaultValue: 1 }, + maxZoom: { type: "number", defaultValue: 5 }, +}) diff --git a/shared/src/css/image-cropper.css b/shared/src/css/image-cropper.css new file mode 100644 index 0000000000..e3c9b79db9 --- /dev/null +++ b/shared/src/css/image-cropper.css @@ -0,0 +1,94 @@ +[data-scope="image-cropper"][data-part="viewport"] { + position: relative; + overflow: hidden; + touch-action: none; + user-select: none; +} + +[data-scope="image-cropper"][data-part="selection"] { + position: absolute; + box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5); + border: 1px solid rgba(255, 255, 255, 0.5); + cursor: move; + touch-action: none; +} + +[data-scope="image-cropper"][data-part="image"] { + display: block; + pointer-events: none; + user-select: none; +} + +[data-scope="image-cropper"][data-part="handle"] { + position: absolute; + width: 30px; + height: 30px; + touch-action: none; + cursor: grab; +} + +[data-scope="image-cropper"][data-part="handle"] > div { + width: 10px; + height: 10px; + background: #fff; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +[data-scope="image-cropper"][data-part="handle"][data-position="top-left"] { + top: 0; + left: 0; + transform: translate(-50%, -50%); + cursor: nwse-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="top"] { + top: 0; + left: 50%; + transform: translate(-50%, -50%); + cursor: ns-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="top-right"] { + top: 0; + right: 0; + transform: translate(50%, -50%); + cursor: nesw-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="right"] { + top: 50%; + right: 0; + transform: translate(50%, -50%); + cursor: ew-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="bottom-right"] { + bottom: 0; + right: 0; + transform: translate(50%, 50%); + cursor: nwse-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="bottom"] { + bottom: 0; + left: 50%; + transform: translate(-50%, 50%); + cursor: ns-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="bottom-left"] { + bottom: 0; + left: 0; + transform: translate(-50%, 50%); + cursor: nesw-resize; +} + +[data-scope="image-cropper"][data-part="handle"][data-position="left"] { + top: 50%; + left: 0; + transform: translate(-50%, -50%); + cursor: ew-resize; +} diff --git a/shared/src/data.ts b/shared/src/data.ts index 52a5c66882..1df9e92932 100644 --- a/shared/src/data.ts +++ b/shared/src/data.ts @@ -1,4 +1,5 @@ import type { StepDetails } from "@zag-js/tour" +import type { HandlePosition } from "@zag-js/image-cropper" import { countryList } from "./country-list" export { paginationData } from "./pagination-data" @@ -379,3 +380,14 @@ export const jsonTreeData = { bigint: BigInt(123), null: null, } + +export const handlePositions: HandlePosition[] = [ + "top-left", + "top", + "top-right", + "right", + "bottom-right", + "bottom", + "bottom-left", + "left", +] diff --git a/shared/src/routes.ts b/shared/src/routes.ts index 951b491895..24a42c0989 100644 --- a/shared/src/routes.ts +++ b/shared/src/routes.ts @@ -4,6 +4,8 @@ type RouteData = { } export const routesData: RouteData[] = [ + { label: "Image Cropper", path: "/image-cropper" }, + { label: "Image Cropper (Fixed Crop Area)", path: "/image-cropper-fixed" }, { label: "Bottom Sheet", path: "/bottom-sheet" }, { label: "Bottom Sheet (Snap Points)", path: "/bottom-sheet-snap-points" }, { label: "Bottom Sheet (Active Snap Point)", path: "/bottom-sheet-default-active-snap-point" }, diff --git a/shared/src/style.css b/shared/src/style.css index 1a572ee11f..43631c1536 100644 --- a/shared/src/style.css +++ b/shared/src/style.css @@ -23,6 +23,8 @@ @import url("./css/hover-card.css"); +@import url("./css/image-cropper.css"); + @import url("./css/listbox.css"); @import url("./css/layout.css");