diff --git a/.changeset/cool-popups-stay-open.md b/.changeset/cool-popups-stay-open.md
new file mode 100644
index 0000000..7a6a3b2
--- /dev/null
+++ b/.changeset/cool-popups-stay-open.md
@@ -0,0 +1,5 @@
+---
+"@inkcre/ui-web": minor
+---
+
+Add modeless InkPopup rendering through the backward-compatible `scrim` prop.
diff --git a/AGENTS.md b/AGENTS.md
index f269c48..6c6858c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -19,4 +19,6 @@ This repository owns the InKCre design system and UI libraries.
- Package manager is PNPM
- Use changeset to summarize your changes (run `pnpm changeset` after you made changes.)
-- Run tests and build to verify your changes if possible.
+- Follow the organization-wide [Verification and Test Policy](https://github.com/InKCre/.github/blob/main/TESTING.md).
+ This repository prefers type-check, lint, generated-contract checks, story builds, and real
+ consuming-page review; it currently admits no automated unit/component suite.
diff --git a/package.json b/package.json
index eeca1bc..b0c484f 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,13 @@
"tokens:update": "tsx scripts/prepare-token-update.ts apply",
"type-check": "pnpm type-check:root && pnpm --filter @inkcre/ui-web type-check",
"type-check:root": "tsc --noEmit",
- "test": "pnpm --filter @inkcre/ui-web test",
"story": "pnpm --filter @inkcre/ui-web story:build",
"story:dev": "pnpm --filter @inkcre/ui-web story:dev",
"check:skills": "pnpm --filter @inkcre/ui-web skill:generate:check && pnpm --filter @inkcre/ui-web skill:validate",
"format": "oxfmt .oxfmtrc.json package.json pnpm-workspace.yaml tsconfig.json scripts .github/workflows/*.yml README.md && pnpm --filter @inkcre/ui-web format",
"format:check": "oxfmt --check .oxfmtrc.json package.json pnpm-workspace.yaml tsconfig.json scripts .github/workflows/*.yml README.md && pnpm --filter @inkcre/ui-web format:check",
"lint": "oxlint --deny-warnings scripts && pnpm --filter @inkcre/ui-web lint",
- "check": "pnpm format:check && pnpm lint && pnpm check:generated && pnpm check:skills && pnpm check:stories && pnpm check:token-workflow && pnpm type-check && pnpm test && pnpm build && pnpm check:package && pnpm story",
+ "check": "pnpm format:check && pnpm lint && pnpm check:generated && pnpm check:skills && pnpm check:stories && pnpm check:token-workflow && pnpm type-check && pnpm build && pnpm check:package && pnpm story",
"changeset": "changeset",
"changeset:add": "changeset add",
"changeset:version": "changeset version && pnpm build-package-metadata",
diff --git a/packages/web/.oxlintrc.json b/packages/web/.oxlintrc.json
index 43ef7c2..8ab2c86 100644
--- a/packages/web/.oxlintrc.json
+++ b/packages/web/.oxlintrc.json
@@ -1,6 +1,6 @@
{
"$schema": "../../node_modules/oxlint/configuration_schema.json",
- "plugins": ["eslint", "oxc", "typescript", "unicorn", "vue", "vitest"],
+ "plugins": ["eslint", "oxc", "typescript", "unicorn", "vue"],
"options": {
"denyWarnings": true,
"reportUnusedDisableDirectives": "error"
diff --git a/packages/web/package.json b/packages/web/package.json
index 53c0d30..07a9ac6 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -84,9 +84,9 @@
"build:skills": "pnpm run skill:generate:check",
"clean": "rimraf dist",
"preview": "vite preview",
- "format": "oxfmt --config .oxfmtrc.json src stories styles .oxfmtrc.json .oxlintrc.json package.json skill.seed.json component-manifest.json component-manifest.schema.json tsconfig.json tsconfig.build.json tsconfig.check.json tsconfig.exports.json env.d.ts histoire.config.ts uno.config.ts vite.config.js vite.subpaths.config.js vitest.config.ts",
- "format:check": "oxfmt --check --config .oxfmtrc.json src stories styles .oxfmtrc.json .oxlintrc.json package.json skill.seed.json component-manifest.json component-manifest.schema.json tsconfig.json tsconfig.build.json tsconfig.check.json tsconfig.exports.json env.d.ts histoire.config.ts uno.config.ts vite.config.js vite.subpaths.config.js vitest.config.ts",
- "lint": "oxlint --config .oxlintrc.json src stories histoire.config.ts uno.config.ts vite.config.js vite.subpaths.config.js vitest.config.ts",
+ "format": "oxfmt --config .oxfmtrc.json src stories styles .oxfmtrc.json .oxlintrc.json package.json skill.seed.json component-manifest.json component-manifest.schema.json tsconfig.json tsconfig.build.json tsconfig.check.json tsconfig.exports.json env.d.ts histoire.config.ts uno.config.ts vite.config.js vite.subpaths.config.js",
+ "format:check": "oxfmt --check --config .oxfmtrc.json src stories styles .oxfmtrc.json .oxlintrc.json package.json skill.seed.json component-manifest.json component-manifest.schema.json tsconfig.json tsconfig.build.json tsconfig.check.json tsconfig.exports.json env.d.ts histoire.config.ts uno.config.ts vite.config.js vite.subpaths.config.js",
+ "lint": "oxlint --config .oxlintrc.json src stories histoire.config.ts uno.config.ts vite.config.js vite.subpaths.config.js",
"lint:fix": "pnpm run lint --fix",
"skill:generate": "tsx ../../scripts/build-agent-skills.ts",
"skill:generate:check": "tsx ../../scripts/build-agent-skills.ts --check",
@@ -94,11 +94,7 @@
"story:dev": "histoire dev",
"story:build": "histoire build",
"story:preview": "histoire preview",
- "type-check": "vue-tsc --noEmit -p tsconfig.check.json",
- "test": "vitest run",
- "test:watch": "vitest",
- "test:ui": "vitest --ui",
- "test:coverage": "vitest --coverage"
+ "type-check": "vue-tsc --noEmit -p tsconfig.check.json"
},
"dependencies": {
"@vue/shared": "3.5.25"
@@ -116,13 +112,9 @@
"@unocss/preset-icons": "^66.5.10",
"@unocss/preset-wind3": "^66.5.10",
"@vitejs/plugin-vue": "^6.0.3",
- "@vitest/coverage-v8": "^4.0.15",
- "@vitest/ui": "^4.0.15",
- "@vue/test-utils": "^2.4.6",
"@vueuse/core": "^14.1.0",
"cpr": "^3.0.1",
"dayjs": "^1.11.19",
- "happy-dom": "^20.0.11",
"histoire": "1.0.0-alpha.5",
"rimraf": "^6.0.1",
"rollup-plugin-visualizer": "^6.0.5",
@@ -130,7 +122,6 @@
"unocss": "^66.5.10",
"vite": "^7.2.7",
"vite-plugin-dts": "^4.5.4",
- "vitest": "^4.0.15",
"vscode-json-languageservice": "^5.6.4",
"vscode-languageserver-textdocument": "^1.0.12",
"vue": "^3.4.0",
diff --git a/packages/web/skills/ui-web/references/components/InkPopup.md b/packages/web/skills/ui-web/references/components/InkPopup.md
index 4803c19..8c93486 100644
--- a/packages/web/skills/ui-web/references/components/InkPopup.md
+++ b/packages/web/skills/ui-web/references/components/InkPopup.md
@@ -25,11 +25,11 @@
## Public API Facts
- Import: `import { InkPopup } from "@inkcre/ui-web";`
-- Props: `closeOnScrim`, `position`
+- Props: `closeOnScrim`, `position`, `scrim`
- Events: `scrim-click`
- Slots: `default`
- Public types: None
-- Story variants: `Default Popup`
+- Story variants: `Default Popup`, `Modeless Popup`
## API Caveats
diff --git a/packages/web/src/components/inkAutoForm/inkAutoForm.test.ts b/packages/web/src/components/inkAutoForm/inkAutoForm.test.ts
deleted file mode 100644
index 8fea224..0000000
--- a/packages/web/src/components/inkAutoForm/inkAutoForm.test.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkAutoForm from "./inkAutoForm.vue";
-import { mapSchemaPropertyToComponent, type JSONSchemaProperty } from "./inkAutoForm";
-
-describe("inkAutoForm", () => {
- describe("Component Rendering", () => {
- it("renders form with valid schema", () => {
- const schema = {
- type: "object" as const,
- properties: {
- name: {
- type: "string" as const,
- title: "Name",
- },
- },
- };
-
- const wrapper = mount(InkAutoForm, {
- props: {
- schema,
- formData: {},
- },
- });
-
- expect(wrapper.find(".ink-auto-form__error").exists()).toBe(false);
- });
-
- it("shows error for invalid schema", () => {
- const invalidSchema: any = {
- type: "string",
- };
-
- const wrapper = mount(InkAutoForm, {
- props: {
- schema: invalidSchema,
- formData: {},
- },
- });
-
- expect(wrapper.find(".ink-auto-form__error").exists()).toBe(true);
- expect(wrapper.find(".ink-auto-form__error").text()).toContain("Invalid schema");
- });
- });
-
- describe("Schema-to-Component Mapping", () => {
- it("maps string type to inkInput", () => {
- const property: JSONSchemaProperty = {
- type: "string",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkInput");
- });
-
- it("maps string with long maxLength to inkTextarea", () => {
- const property: JSONSchemaProperty = {
- type: "string",
- maxLength: 200,
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkTextarea");
- });
-
- it("maps boolean type to inkSwitch", () => {
- const property: JSONSchemaProperty = {
- type: "boolean",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkSwitch");
- });
-
- it("maps string with enum to inkDropdown", () => {
- const property: JSONSchemaProperty = {
- type: "string",
- enum: ["option1", "option2", "option3"],
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkDropdown");
- expect(result.props.options).toHaveLength(3);
- expect(result.props.options[0]).toEqual({ label: "option1", value: "option1" });
- });
-
- it("maps string with date format to inkPicker", () => {
- const property: JSONSchemaProperty = {
- type: "string",
- format: "date",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkPicker");
- expect(result.props.type).toBe("date");
- });
-
- it("maps string with time format to inkPicker", () => {
- const property: JSONSchemaProperty = {
- type: "string",
- format: "time",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkPicker");
- expect(result.props.type).toBe("time");
- });
-
- it("maps string with date-time format to inkPicker", () => {
- const property: JSONSchemaProperty = {
- type: "string",
- format: "date-time",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkPicker");
- expect(result.props.type).toBe("datetime");
- });
-
- it("maps number type to inkInput", () => {
- const property: JSONSchemaProperty = {
- type: "number",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkInput");
- });
-
- it("maps integer type to inkInput", () => {
- const property: JSONSchemaProperty = {
- type: "integer",
- };
-
- const result = mapSchemaPropertyToComponent(property);
-
- expect(result.component).toBe("inkInput");
- });
- });
-
- describe("Form Data Updates", () => {
- it("emits update:formData when field value changes", async () => {
- const schema = {
- type: "object" as const,
- properties: {
- name: {
- type: "string" as const,
- title: "Name",
- },
- },
- };
-
- const wrapper = mount(InkAutoForm, {
- props: {
- schema,
- formData: {},
- },
- });
-
- // Find the input component and trigger update
- const input = wrapper.findComponent({ name: "InkInput" });
- await input.vm.$emit("update:modelValue", "John Doe");
-
- expect(wrapper.emitted("update:formData")).toBeTruthy();
- const emitted = wrapper.emitted("update:formData") as any[];
- expect(emitted[emitted.length - 1][0]).toEqual({ name: "John Doe" });
- });
- });
-
- describe("Default Values", () => {
- it("initializes form data with default values from schema", async () => {
- const schema = {
- type: "object" as const,
- properties: {
- username: {
- type: "string" as const,
- title: "Username",
- default: "guest",
- },
- notifications: {
- type: "boolean" as const,
- title: "Notifications",
- default: true,
- },
- },
- };
-
- const wrapper = mount(InkAutoForm, {
- props: {
- schema,
- formData: {},
- },
- });
-
- await wrapper.vm.$nextTick();
-
- const emitted = wrapper.emitted("update:formData") as any[];
- expect(emitted).toBeTruthy();
- expect(emitted[0][0]).toEqual({
- username: "guest",
- notifications: true,
- });
- });
- });
-});
diff --git a/packages/web/src/components/inkButton/inkButton.test.ts b/packages/web/src/components/inkButton/inkButton.test.ts
deleted file mode 100644
index 361e463..0000000
--- a/packages/web/src/components/inkButton/inkButton.test.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkButton from "./inkButton.vue";
-
-describe("InkButton", () => {
- it("renders button with text", () => {
- const wrapper = mount(InkButton, {
- props: {
- text: "Click me",
- type: "primary",
- size: "md",
- },
- });
-
- expect(wrapper.text()).toContain("Click me");
- });
-
- it("applies correct CSS classes for theme, type and size", () => {
- const wrapper = mount(InkButton, {
- props: {
- text: "Test",
- theme: "danger",
- type: "square",
- size: "sm",
- },
- });
-
- const button = wrapper.find("button");
- expect(button.classes()).toContain("ink-button--theme-danger");
- expect(button.classes()).toContain("ink-button--type-square");
- expect(button.classes()).toContain("ink-button--size-sm");
- });
-
- it("emits click event when clicked", async () => {
- const wrapper = mount(InkButton, {
- props: {
- text: "Click me",
- },
- });
-
- await wrapper.find("button").trigger("click");
- expect(wrapper.emitted()).toHaveProperty("click");
- });
-
- it("does not emit click event when loading", async () => {
- const wrapper = mount(InkButton, {
- props: {
- text: "Click me",
- isLoading: true,
- },
- });
-
- await wrapper.find("button").trigger("click");
- expect(wrapper.emitted()).not.toHaveProperty("click");
- expect(wrapper.find("button").attributes()).toHaveProperty("disabled");
- });
-
- it("renders icon when provided", () => {
- const wrapper = mount(InkButton, {
- props: {
- text: "Settings",
- icon: "i-mdi-cog",
- },
- });
-
- expect(wrapper.find(".ink-button__icon").exists()).toBe(true);
- expect(wrapper.find(".ink-button__icon").classes()).toContain("i-mdi-cog");
- });
-
- it("uses default values when props not provided", () => {
- const wrapper = mount(InkButton);
- const button = wrapper.find("button");
-
- expect(button.classes()).toContain("ink-button--theme-subtle");
- expect(button.classes()).toContain("ink-button--size-md");
- expect(button.classes()).toContain("ink-button--type-default");
- });
-});
diff --git a/packages/web/src/components/inkDialog/inkDialog.test.ts b/packages/web/src/components/inkDialog/inkDialog.test.ts
deleted file mode 100644
index bcc34b6..0000000
--- a/packages/web/src/components/inkDialog/inkDialog.test.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkDialog from "./inkDialog.vue";
-import { INK_I18N_KEY } from "../../i18n";
-
-const transitionStubs = {
- Teleport: {
- template: "
",
- },
- Transition: {
- template: "
",
- },
-};
-
-describe("InkDialog", () => {
- it("renders its public content and default actions", () => {
- const wrapper = mount(InkDialog, {
- props: {
- modelValue: true,
- title: "Test Dialog",
- subtitle: "Test Subtitle",
- },
- global: {
- stubs: transitionStubs,
- },
- });
-
- expect(wrapper.get(".ink-dialog__title").text()).toBe("Test Dialog");
- expect(wrapper.get(".ink-dialog__subtitle").text()).toBe("Test Subtitle");
- expect(wrapper.text()).toContain("Cancel");
- expect(wrapper.text()).toContain("Confirm");
- });
-
- it("emits cancel and requests closing when the cancel action is clicked", async () => {
- const wrapper = mount(InkDialog, {
- props: {
- modelValue: true,
- },
- global: {
- stubs: transitionStubs,
- },
- });
-
- const cancelButton = wrapper.findAll("button").find((button) => button.text() === "Cancel");
- expect(cancelButton).toBeDefined();
-
- await cancelButton!.trigger("click");
-
- expect(wrapper.emitted("cancel")).toHaveLength(1);
- expect(wrapper.emitted("update:modelValue")).toEqual([[false]]);
- });
-
- it("emits confirm when the confirm action is clicked", async () => {
- const wrapper = mount(InkDialog, {
- props: {
- modelValue: true,
- },
- global: {
- stubs: transitionStubs,
- },
- });
-
- const confirmButton = wrapper.findAll("button").find((button) => button.text() === "Confirm");
- expect(confirmButton).toBeDefined();
-
- await confirmButton!.trigger("click");
-
- expect(wrapper.emitted("confirm")).toHaveLength(1);
- });
-
- it("supports custom action visibility and text", () => {
- const wrapper = mount(InkDialog, {
- props: {
- modelValue: true,
- showCancel: false,
- confirmText: "Continue",
- },
- global: {
- stubs: transitionStubs,
- },
- });
-
- expect(wrapper.text()).not.toContain("Cancel");
- expect(wrapper.text()).toContain("Continue");
- });
-
- it("applies position without closing when scrim close is disabled", async () => {
- const wrapper = mount(InkDialog, {
- props: {
- modelValue: true,
- position: "left",
- closeOnScrim: false,
- },
- global: {
- stubs: transitionStubs,
- },
- });
-
- expect(wrapper.get(".ink-popup").classes()).toContain("ink-popup--left");
-
- await wrapper.get(".ink-popup-overlay").trigger("click");
-
- expect(wrapper.find(".ink-dialog").exists()).toBe(true);
- expect(wrapper.emitted("update:modelValue")).toBeUndefined();
- });
-
- it("renders translated action labels when i18n is provided", () => {
- const mockI18n = {
- t: (key: string) =>
- ({
- "dialog.cancel": "Translated Cancel",
- "dialog.confirm": "Translated Confirm",
- })[key] ?? key,
- locale: { value: "en" },
- };
-
- const wrapper = mount(InkDialog, {
- props: {
- modelValue: true,
- },
- global: {
- stubs: transitionStubs,
- provide: {
- [INK_I18N_KEY as symbol]: mockI18n,
- },
- },
- });
-
- expect(wrapper.text()).toContain("Translated Cancel");
- expect(wrapper.text()).toContain("Translated Confirm");
- });
-});
diff --git a/packages/web/src/components/inkDropdown/inkDropdown.test.ts b/packages/web/src/components/inkDropdown/inkDropdown.test.ts
deleted file mode 100644
index 809aff2..0000000
--- a/packages/web/src/components/inkDropdown/inkDropdown.test.ts
+++ /dev/null
@@ -1,399 +0,0 @@
-import { describe, it, expect, vi } from "vitest";
-import { mount } from "@vue/test-utils";
-import { nextTick } from "vue";
-import InkDropdown from "./inkDropdown.vue";
-import InkButton from "../inkButton/inkButton.vue";
-import type { DropdownOption } from "./inkDropdown";
-
-describe("InkDropdown", () => {
- const staticOptions: DropdownOption[] = [
- { label: "Option 1", value: "opt1" },
- { label: "Option 2", value: "opt2" },
- { label: "Option 3", value: "opt3" },
- ];
-
- it("renders with static options", () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options: staticOptions,
- modelValue: "",
- },
- });
-
- expect(wrapper.find(".ink-dropdown").exists()).toBe(true);
- });
-
- it("displays placeholder when no value is selected", () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options: staticOptions,
- modelValue: "",
- placeholder: "Select an option",
- },
- });
-
- expect(wrapper.find(".ink-dropdown__value").text()).toBe("Select an option");
- });
-
- it("displays selected option label", () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options: staticOptions,
- modelValue: "opt2",
- },
- });
-
- expect(wrapper.find(".ink-dropdown__value").text()).toBe("Option 2");
- });
-
- it("emits update:modelValue when option is selected", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options: staticOptions,
- modelValue: "",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- // Select an option
- const options = wrapper.findAll(".ink-dropdown__option");
- await options[1].trigger("click");
- await nextTick();
-
- expect(wrapper.emitted("update:modelValue")).toBeTruthy();
- expect(wrapper.emitted("update:modelValue")?.[0]).toEqual(["opt2"]);
- });
-
- it("loads lazy options immediately when modelValue is set", async () => {
- const lazyOptions: DropdownOption[] = [
- { label: "Lazy 1", value: "lazy1" },
- { label: "Lazy 2", value: "lazy2" },
- { label: "Lazy 3", value: "lazy3" },
- ];
-
- const refresher = vi.fn<() => Promise>(async () => {
- return Promise.resolve(lazyOptions);
- });
-
- mount(InkDropdown, {
- props: {
- refresher,
- modelValue: "lazy2",
- },
- });
-
- // Wait for mounted hook and async loading
- await nextTick();
- await vi.waitFor(() => expect(refresher).toHaveBeenCalled());
-
- // The refresher should be called immediately on mount
- expect(refresher).toHaveBeenCalledTimes(1);
- });
-
- it("does not load lazy options immediately when modelValue is empty", async () => {
- const refresher = vi.fn<() => Promise>(async () => {
- return Promise.resolve([]);
- });
-
- mount(InkDropdown, {
- props: {
- refresher,
- modelValue: "",
- },
- });
-
- await nextTick();
-
- // Refresher should not be called for empty modelValue
- expect(refresher).not.toHaveBeenCalled();
- });
-
- it("does not load lazy options immediately when modelValue is null", async () => {
- const refresher = vi.fn<() => Promise>(async () => {
- return Promise.resolve([]);
- });
-
- mount(InkDropdown, {
- props: {
- refresher,
- modelValue: null,
- },
- });
-
- await nextTick();
-
- // Refresher should not be called for null modelValue
- expect(refresher).not.toHaveBeenCalled();
- });
-
- it("does not load lazy options when static options already exist", async () => {
- const refresher = vi.fn<() => Promise>(async () => {
- return Promise.resolve([]);
- });
-
- mount(InkDropdown, {
- props: {
- options: staticOptions,
- refresher,
- modelValue: "opt1",
- },
- });
-
- await nextTick();
-
- // Refresher should not be called when options are already provided
- expect(refresher).not.toHaveBeenCalled();
- });
-
- it("displays refresh button when refresher is provided", () => {
- const wrapper = mount(InkDropdown, {
- props: {
- refresher: async () => [],
- },
- });
-
- expect(wrapper.find(".ink-dropdown__refresh").exists()).toBe(true);
- });
-
- it("calls refresher when refresh button is clicked", async () => {
- const refresher = vi.fn<() => Promise>(async () => []);
-
- const wrapper = mount(InkDropdown, {
- props: {
- refresher,
- editable: true,
- },
- });
-
- await wrapper.find(".ink-dropdown__refresh").trigger("click");
- await nextTick();
-
- expect(refresher).toHaveBeenCalled();
- });
-
- describe("stepping", () => {
- const options = [
- { label: "Opt 1", value: "v1" },
- { label: "Opt 2", value: "v2" },
- { label: "Opt 3", value: "v3" },
- ];
-
- it("loops forward correctly", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- modelValue: "v1",
- options,
- enableStepping: true,
- },
- });
-
- const nextBtn = wrapper.findAllComponents(InkButton).at(1);
- await nextBtn?.trigger("click");
- expect(wrapper.emitted("update:modelValue")?.[0]).toEqual(["v2"]);
-
- await wrapper.setProps({ modelValue: "v3" });
- await nextBtn?.trigger("click");
- expect(wrapper.emitted("update:modelValue")?.[1]).toEqual(["v1"]);
- });
-
- it("loops backward correctly", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- modelValue: "v1",
- options,
- enableStepping: true,
- },
- });
-
- const prevBtn = wrapper.findAllComponents(InkButton).at(0);
- await prevBtn?.trigger("click");
- expect(wrapper.emitted("update:modelValue")?.[0]).toEqual(["v3"]);
-
- await wrapper.setProps({ modelValue: "v2" });
- await prevBtn?.trigger("click");
- expect(wrapper.emitted("update:modelValue")?.[1]).toEqual(["v1"]);
- });
-
- it("is disabled when editable is false", () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- enableStepping: true,
- editable: false,
- },
- });
-
- const buttons = wrapper.findAllComponents(InkButton);
- expect(buttons.at(0)?.find("button").element.disabled).toBe(true);
- expect(buttons.at(1)?.find("button").element.disabled).toBe(true);
- });
-
- it("is disabled when options are empty", () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options: [],
- enableStepping: true,
- },
- });
-
- const buttons = wrapper.findAllComponents(InkButton);
- expect(buttons.at(0)?.find("button").element.disabled).toBe(true);
- expect(buttons.at(1)?.find("button").element.disabled).toBe(true);
- });
- });
-
- describe("keyboard navigation", () => {
- const options: DropdownOption[] = [
- { label: "Option 1", value: "opt1" },
- { label: "Option 2", value: "opt2" },
- { label: "Option 3", value: "opt3" },
- ];
-
- it("navigates down with ArrowDown key", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- modelValue: "",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- const container = wrapper.find(".ink-dropdown-container");
-
- // Press ArrowDown
- await container.trigger("keydown", { key: "ArrowDown" });
- await nextTick();
-
- // First option should be hovered (index 1 after initial 0)
- const optionElements = wrapper.findAll(".ink-dropdown__option");
- expect(optionElements[1].classes()).toContain("ink-dropdown__option--hovered");
- });
-
- it("navigates up with ArrowUp key", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- modelValue: "",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- const container = wrapper.find(".ink-dropdown-container");
-
- // Press ArrowUp (should wrap to last option)
- await container.trigger("keydown", { key: "ArrowUp" });
- await nextTick();
-
- // Last option should be hovered
- const optionElements = wrapper.findAll(".ink-dropdown__option");
- expect(optionElements[2].classes()).toContain("ink-dropdown__option--hovered");
- });
-
- it("wraps around when navigating past last option", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- modelValue: "",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- const container = wrapper.find(".ink-dropdown-container");
-
- // Press ArrowDown 3 times (0 -> 1 -> 2 -> 0)
- await container.trigger("keydown", { key: "ArrowDown" });
- await container.trigger("keydown", { key: "ArrowDown" });
- await container.trigger("keydown", { key: "ArrowDown" });
- await nextTick();
-
- // Should wrap back to first option
- const optionElements = wrapper.findAll(".ink-dropdown__option");
- expect(optionElements[0].classes()).toContain("ink-dropdown__option--hovered");
- });
-
- it("selects hovered option with Enter key", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- modelValue: "",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- const container = wrapper.find(".ink-dropdown-container");
-
- // Navigate to second option
- await container.trigger("keydown", { key: "ArrowDown" });
- await nextTick();
-
- // Press Enter to select
- await container.trigger("keydown", { key: "Enter" });
- await nextTick();
-
- expect(wrapper.emitted("update:modelValue")).toBeTruthy();
- expect(wrapper.emitted("update:modelValue")?.[0]).toEqual(["opt2"]);
- });
-
- it("closes dropdown with Escape key", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- modelValue: "",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- expect(wrapper.find(".ink-dropdown__options").exists()).toBe(true);
-
- const container = wrapper.find(".ink-dropdown-container");
-
- // Press Escape
- await container.trigger("keydown", { key: "Escape" });
- await nextTick();
-
- expect(wrapper.find(".ink-dropdown__options").exists()).toBe(false);
- });
-
- it("initializes hover to current selection when opening", async () => {
- const wrapper = mount(InkDropdown, {
- props: {
- options,
- modelValue: "opt2",
- editable: true,
- },
- });
-
- // Open dropdown
- await wrapper.find(".ink-dropdown").trigger("click");
- await nextTick();
-
- // Second option should be hovered (matching modelValue)
- const optionElements = wrapper.findAll(".ink-dropdown__option");
- expect(optionElements[1].classes()).toContain("ink-dropdown__option--hovered");
- });
- });
-});
diff --git a/packages/web/src/components/inkField/inkField.test.ts b/packages/web/src/components/inkField/inkField.test.ts
deleted file mode 100644
index 56ea984..0000000
--- a/packages/web/src/components/inkField/inkField.test.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkField from "./inkField.vue";
-
-describe("InkField", () => {
- it("renders label and value", () => {
- const wrapper = mount(InkField, {
- props: {
- label: "Username",
- value: "john.doe",
- layout: "col",
- },
- });
-
- expect(wrapper.text()).toContain("Username");
- expect(wrapper.text()).toContain("john.doe");
- });
-
- it("applies correct layout class", () => {
- const wrapper = mount(InkField, {
- props: {
- label: "Test",
- layout: "inline",
- },
- });
-
- expect(wrapper.classes()).toContain("ink-field--inline");
- });
-
- it("shows required indicator when required is true", () => {
- const wrapper = mount(InkField, {
- props: {
- label: "Password",
- required: true,
- },
- });
-
- expect(wrapper.find(".ink-field__required").exists()).toBe(true);
- });
-
- it("emits value-click when editable value is clicked", async () => {
- const wrapper = mount(InkField, {
- props: {
- label: "Bio",
- value: "Click me",
- editable: true,
- },
- });
-
- await wrapper.find(".ink-field__value").trigger("click");
- expect(wrapper.emitted()).toHaveProperty("value-click");
- });
-
- it("renders slot content when provided", () => {
- const wrapper = mount(InkField, {
- props: {
- label: "Custom",
- },
- slots: {
- default: "",
- },
- });
-
- expect(wrapper.html()).toContain("Custom Input");
- });
-});
diff --git a/packages/web/src/components/inkImage/inkImage.test.ts b/packages/web/src/components/inkImage/inkImage.test.ts
deleted file mode 100644
index 42dc239..0000000
--- a/packages/web/src/components/inkImage/inkImage.test.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-import { afterEach, describe, expect, it } from "vitest";
-import { mount, type VueWrapper } from "@vue/test-utils";
-import InkImage from "./inkImage.vue";
-
-const defaultProps = {
- src: "https://example.com/image.jpg",
- alt: "Test image",
-};
-
-const mountedWrappers: VueWrapper[] = [];
-
-const mountImage = (options: Parameters>[1] = {}) => {
- const wrapper = mount(InkImage, {
- ...options,
- props: {
- ...defaultProps,
- ...options.props,
- },
- global: {
- ...options.global,
- stubs: {
- Teleport: {
- template: "
",
- },
- Transition: {
- template: "
",
- },
- ...options.global?.stubs,
- },
- },
- });
-
- mountedWrappers.push(wrapper);
- return wrapper;
-};
-
-const openImage = async (wrapper: VueWrapper) => {
- await wrapper.get("[data-testid='ink-image-thumbnail']").trigger("click");
-};
-
-afterEach(() => {
- mountedWrappers.splice(0).forEach((wrapper) => wrapper.unmount());
-});
-
-describe("InkImage", () => {
- describe("rendering", () => {
- it("renders the thumbnail with accessible image attributes", () => {
- const wrapper = mountImage();
- const image = wrapper.get("[data-testid='ink-image-img']");
-
- expect(image.attributes("src")).toBe(defaultProps.src);
- expect(image.attributes("alt")).toBe(defaultProps.alt);
- expect(image.attributes("loading")).toBe("lazy");
- });
-
- it("supports a custom thumbnail", () => {
- const wrapper = mountImage({
- slots: {
- thumbnail: "Custom
",
- },
- });
-
- expect(wrapper.get(".custom-thumbnail").text()).toBe("Custom");
- expect(wrapper.find("[data-testid='ink-image-img']").exists()).toBe(false);
- });
-
- it("shows the expanded title and custom header", async () => {
- const wrapper = mountImage({
- props: {
- title: "Test Image Title",
- },
- slots: {
- "expanded-header": "",
- },
- });
-
- await openImage(wrapper);
-
- expect(wrapper.get("[data-testid='ink-scrim']").exists()).toBe(true);
- expect(wrapper.get(".custom-header").text()).toBe("Header");
- expect(wrapper.get(".ink-image__expanded-title").text()).toBe("Test Image Title");
- });
- });
-
- describe("expanded state", () => {
- it("opens from the thumbnail and publishes the state change", async () => {
- const wrapper = mountImage();
-
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(false);
-
- await openImage(wrapper);
-
- expect(wrapper.get("[data-testid='ink-scrim']").exists()).toBe(true);
- expect(wrapper.emitted("expand")).toHaveLength(1);
- expect(wrapper.emitted("update:expanded")).toEqual([[true]]);
- });
-
- it("closes from the scrim and publishes the close action", async () => {
- const wrapper = mountImage();
- await openImage(wrapper);
-
- await wrapper.get("[data-testid='ink-scrim']").trigger("click");
-
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(false);
- expect(wrapper.emitted("close")).toHaveLength(1);
- expect(wrapper.emitted("update:expanded")).toEqual([[true], [false]]);
- });
-
- it("closes on Escape", async () => {
- const wrapper = mountImage();
- await openImage(wrapper);
-
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
- await wrapper.vm.$nextTick();
-
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(false);
- expect(wrapper.emitted("close")).toHaveLength(1);
- expect(wrapper.emitted("update:expanded")).toEqual([[true], [false]]);
- });
-
- it("leaves a controlled model unchanged until its parent updates it", async () => {
- const wrapper = mountImage({
- props: {
- expanded: false,
- },
- });
-
- await openImage(wrapper);
-
- expect(wrapper.emitted("update:expanded")).toEqual([[true]]);
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(false);
-
- await wrapper.setProps({ expanded: true });
- expect(wrapper.get("[data-testid='ink-scrim']").exists()).toBe(true);
-
- await wrapper.get("[data-testid='ink-scrim']").trigger("click");
- expect(wrapper.emitted("update:expanded")).toEqual([[true], [false]]);
- expect(wrapper.get("[data-testid='ink-scrim']").exists()).toBe(true);
-
- await wrapper.setProps({ expanded: false });
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(false);
- });
- });
-
- it("emits the failed source with image load errors", async () => {
- const wrapper = mountImage();
-
- await wrapper.get("[data-testid='ink-image-img']").trigger("error");
-
- expect(wrapper.emitted("error")).toHaveLength(1);
- expect(wrapper.emitted("error")?.[0]?.[0]).toMatchObject({
- src: defaultProps.src,
- });
- });
-});
diff --git a/packages/web/src/components/inkJsonEditor/inkJsonEditor.test.ts b/packages/web/src/components/inkJsonEditor/inkJsonEditor.test.ts
deleted file mode 100644
index 6b23ce9..0000000
--- a/packages/web/src/components/inkJsonEditor/inkJsonEditor.test.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import { describe, it, expect, vi, beforeEach } from "vitest";
-import { mount } from "@vue/test-utils";
-import { nextTick } from "vue";
-import InkJsonEditor from "./inkJsonEditor.vue";
-import { jsonService } from "./jsonSchemaService";
-
-// Mock the jsonService.configure method
-vi.mock("./jsonSchemaService", () => ({
- jsonService: {
- configure: vi.fn<(settings: unknown) => void>(),
- parseJSONDocument: vi.fn<() => Record>(() => ({})),
- doValidation: vi.fn<() => Promise>(async () => []),
- doComplete: vi.fn<() => Promise>(async () => null),
- },
-}));
-
-describe("InkJsonEditor", () => {
- beforeEach(() => {
- vi.clearAllMocks();
- });
-
- it("configures schema on mount when schema prop is provided", async () => {
- const schema = {
- type: "object",
- properties: {
- name: { type: "string" },
- },
- };
-
- mount(InkJsonEditor, {
- props: {
- modelValue: "{}",
- schema,
- schemaUri: "test://schema.json",
- },
- });
-
- await nextTick();
-
- expect(jsonService.configure).toHaveBeenCalledWith({
- schemas: [
- {
- uri: "test://schema.json",
- fileMatch: ["*"],
- schema,
- },
- ],
- });
- });
-
- it("reconfigures schema when schema prop changes", async () => {
- const initialSchema = {
- type: "object",
- properties: {
- name: { type: "string" },
- },
- };
-
- const updatedSchema = {
- type: "object",
- properties: {
- name: { type: "string" },
- version: { type: "string" },
- },
- };
-
- const wrapper = mount(InkJsonEditor, {
- props: {
- modelValue: "{}",
- schema: initialSchema,
- schemaUri: "test://schema.json",
- },
- });
-
- await nextTick();
- const initialCallCount = (jsonService.configure as any).mock.calls.length;
-
- await wrapper.setProps({ schema: updatedSchema });
- await nextTick();
-
- const finalCallCount = (jsonService.configure as any).mock.calls.length;
- expect(finalCallCount).toBeGreaterThan(initialCallCount);
-
- const lastCall = (jsonService.configure as any).mock.calls[finalCallCount - 1];
- expect(lastCall[0]).toEqual({
- schemas: [
- {
- uri: "test://schema.json",
- fileMatch: ["*"],
- schema: updatedSchema,
- },
- ],
- });
- });
-
- it("does not configure schema when schema prop is not provided", async () => {
- mount(InkJsonEditor, {
- props: {
- modelValue: "{}",
- },
- });
-
- await nextTick();
-
- expect(jsonService.configure).toHaveBeenCalledWith({
- schemas: [],
- });
- });
-
- it("clears schema configuration when schema prop becomes undefined", async () => {
- const initialSchema = {
- type: "object",
- properties: {
- name: { type: "string" },
- },
- };
-
- const wrapper = mount(InkJsonEditor, {
- props: {
- modelValue: "{}",
- schema: initialSchema,
- schemaUri: "test://schema.json",
- },
- });
-
- await nextTick();
- vi.clearAllMocks();
-
- await wrapper.setProps({ schema: undefined });
- await nextTick();
-
- expect(jsonService.configure).toHaveBeenCalledWith({
- schemas: [],
- });
- });
-});
diff --git a/packages/web/src/components/inkLoading/inkLoading.test.ts b/packages/web/src/components/inkLoading/inkLoading.test.ts
deleted file mode 100644
index 07f72bc..0000000
--- a/packages/web/src/components/inkLoading/inkLoading.test.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkLoading from "./inkLoading.vue";
-
-describe("InkLoading", () => {
- it("renders loading spinner", () => {
- const wrapper = mount(InkLoading);
- expect(wrapper.find(".ink-loading").exists()).toBe(true);
- });
-
- it("has the correct structure with blocks", () => {
- const wrapper = mount(InkLoading);
- const blocks = wrapper.findAll(".ink-loading__block");
- expect(blocks).toHaveLength(3);
- });
-});
diff --git a/packages/web/src/components/inkPagination/inkPagination.test.ts b/packages/web/src/components/inkPagination/inkPagination.test.ts
deleted file mode 100644
index 901cd2e..0000000
--- a/packages/web/src/components/inkPagination/inkPagination.test.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkPagination from "./inkPagination.vue";
-
-describe("InkPagination", () => {
- it("renders page buttons correctly for few pages", () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 1,
- totalPages: 5,
- },
- });
-
- const pageButtons = wrapper.findAll(".ink-pagination__page");
- expect(pageButtons.length).toBe(5);
- });
-
- it("highlights the current page", () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 3,
- totalPages: 5,
- },
- });
-
- const activeButton = wrapper.find(".ink-pagination__page--active");
- expect(activeButton.text()).toBe("3");
- });
-
- it("emits page-change event when page button is clicked", async () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 1,
- totalPages: 5,
- },
- });
-
- const pageButtons = wrapper.findAll(".ink-pagination__page");
- await pageButtons[2].trigger("click"); // Click page 3
-
- expect(wrapper.emitted("page-change")).toBeTruthy();
- expect(wrapper.emitted("page-change")?.[0]).toEqual([3]);
- });
-
- it("disables prev button on first page", () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 1,
- totalPages: 5,
- },
- });
-
- const prevButton = wrapper.find(".ink-pagination__nav--prev");
- expect(prevButton.attributes("disabled")).toBeDefined();
- });
-
- it("disables next button on last page", () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 5,
- totalPages: 5,
- },
- });
-
- const nextButton = wrapper.find(".ink-pagination__nav--next");
- expect(nextButton.attributes("disabled")).toBeDefined();
- });
-
- it("emits page-change when prev button is clicked", async () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 3,
- totalPages: 5,
- },
- });
-
- const prevButton = wrapper.find(".ink-pagination__nav--prev");
- await prevButton.trigger("click");
-
- expect(wrapper.emitted("page-change")?.[0]).toEqual([2]);
- });
-
- it("emits page-change when next button is clicked", async () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 3,
- totalPages: 5,
- },
- });
-
- const nextButton = wrapper.find(".ink-pagination__nav--next");
- await nextButton.trigger("click");
-
- expect(wrapper.emitted("page-change")?.[0]).toEqual([4]);
- });
-
- it("shows ellipsis for many pages", () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 10,
- totalPages: 20,
- },
- });
-
- const ellipsisButtons = wrapper.findAll(".ink-pagination__page--ellipsis");
- expect(ellipsisButtons.length).toBeGreaterThan(0);
- });
-
- it("does not emit event when clicking current page", async () => {
- const wrapper = mount(InkPagination, {
- props: {
- currentPage: 3,
- totalPages: 5,
- },
- });
-
- const activeButton = wrapper.find(".ink-pagination__page--active");
- await activeButton.trigger("click");
-
- expect(wrapper.emitted("page-change")).toBeFalsy();
- });
-
- describe("Text type", () => {
- it("renders text buttons instead of icon buttons", () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 1,
- totalPages: 5,
- },
- });
-
- const textNavButtons = wrapper.findAll(".ink-pagination__text-nav");
- expect(textNavButtons.length).toBe(2);
-
- const iconButtons = wrapper.findAll(".ink-pagination__nav");
- expect(iconButtons.length).toBe(0);
- });
-
- it("displays page info in 'x of y' format", () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 3,
- totalPages: 10,
- },
- });
-
- const pageInfo = wrapper.find(".ink-pagination__page-info");
- expect(pageInfo.text()).toBe("3 of 10");
- });
-
- it("does not render numbered page buttons", () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 1,
- totalPages: 5,
- },
- });
-
- const pageButtons = wrapper.findAll(".ink-pagination__page");
- expect(pageButtons.length).toBe(0);
- });
-
- it("disables Previous button on first page", () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 1,
- totalPages: 5,
- },
- });
-
- const prevButton = wrapper.findAll(".ink-pagination__text-nav")[0];
- expect(prevButton.attributes("disabled")).toBeDefined();
- });
-
- it("disables Next button on last page", () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 5,
- totalPages: 5,
- },
- });
-
- const nextButton = wrapper.findAll(".ink-pagination__text-nav")[1];
- expect(nextButton.attributes("disabled")).toBeDefined();
- });
-
- it("emits page-change when Previous button is clicked", async () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 3,
- totalPages: 5,
- },
- });
-
- const prevButton = wrapper.findAll(".ink-pagination__text-nav")[0];
- await prevButton.trigger("click");
-
- expect(wrapper.emitted("page-change")?.[0]).toEqual([2]);
- });
-
- it("emits page-change when Next button is clicked", async () => {
- const wrapper = mount(InkPagination, {
- props: {
- type: "text",
- currentPage: 3,
- totalPages: 5,
- },
- });
-
- const nextButton = wrapper.findAll(".ink-pagination__text-nav")[1];
- await nextButton.trigger("click");
-
- expect(wrapper.emitted("page-change")?.[0]).toEqual([4]);
- });
- });
-});
diff --git a/packages/web/src/components/inkPlaceholder/inkPlaceholder.test.ts b/packages/web/src/components/inkPlaceholder/inkPlaceholder.test.ts
deleted file mode 100644
index 1fd5b4d..0000000
--- a/packages/web/src/components/inkPlaceholder/inkPlaceholder.test.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkPlaceholder from "./inkPlaceholder.vue";
-import { INK_I18N_KEY } from "../../i18n";
-
-describe("InkPlaceholder", () => {
- it("renders with default empty state", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- });
-
- expect(wrapper.find(".ink-placeholder").exists()).toBe(true);
- expect(wrapper.find(".ink-placeholder--empty").exists()).toBe(true);
- });
-
- it("renders with error state", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "error",
- },
- });
-
- expect(wrapper.find(".ink-placeholder--error").exists()).toBe(true);
- });
-
- it("displays custom title", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- title: "Custom Title",
- },
- });
-
- expect(wrapper.text()).toContain("Custom Title");
- });
-
- it("displays custom description", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- description: "Custom Description",
- },
- });
-
- expect(wrapper.text()).toContain("Custom Description");
- });
-
- it("displays default title for empty state", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- });
-
- expect(wrapper.text()).toContain("No data");
- });
-
- it("displays default title for error state", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "error",
- },
- });
-
- expect(wrapper.text()).toContain("Something went wrong");
- });
-
- it("renders actions slot when provided", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- slots: {
- actions: '',
- },
- });
-
- expect(wrapper.find(".ink-placeholder__actions").exists()).toBe(true);
- expect(wrapper.find(".test-action").exists()).toBe(true);
- });
-
- it("does not render actions container when no actions slot provided", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- });
-
- expect(wrapper.find(".ink-placeholder__actions").exists()).toBe(false);
- });
-
- it("renders custom illustration slot", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- slots: {
- illustration: '🎨
',
- },
- });
-
- expect(wrapper.find(".custom-icon").exists()).toBe(true);
- });
-
- it("renders custom title slot", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- slots: {
- title: 'Custom
',
- },
- });
-
- expect(wrapper.find(".custom-title").exists()).toBe(true);
- });
-
- it("renders custom description slot", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- slots: {
- description: 'Custom description
',
- },
- });
-
- expect(wrapper.find(".custom-desc").exists()).toBe(true);
- });
-
- it("uses custom illustration prop when provided", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- illustration: "i-mdi-custom-icon",
- },
- });
-
- expect(wrapper.find(".i-mdi-custom-icon").exists()).toBe(true);
- });
-
- describe("i18n integration", () => {
- it("uses i18n translations when provided", () => {
- const mockI18n = {
- t: (key: string) => {
- const translations: Record = {
- "placeholder.empty.title": "Translated Empty Title",
- "placeholder.empty.description": "Translated Empty Description",
- "placeholder.error.title": "Translated Error Title",
- "placeholder.error.description": "Translated Error Description",
- };
- return translations[key] || key;
- },
- locale: { value: "en" },
- };
-
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- global: {
- provide: {
- [INK_I18N_KEY as symbol]: mockI18n,
- },
- },
- });
-
- expect(wrapper.text()).toContain("Translated Empty Title");
- expect(wrapper.text()).toContain("Translated Empty Description");
- });
-
- it("falls back to English when i18n not provided", () => {
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "empty",
- },
- });
-
- expect(wrapper.text()).toContain("No data");
- expect(wrapper.text()).toContain("There's nothing here yet.");
- });
-
- it("uses i18n translations for error state", () => {
- const mockI18n = {
- t: (key: string) => {
- const translations: Record = {
- "placeholder.error.title": "Translated Error",
- "placeholder.error.description": "Translated Error Description",
- };
- return translations[key] || key;
- },
- locale: { value: "en" },
- };
-
- const wrapper = mount(InkPlaceholder, {
- props: {
- state: "error",
- },
- global: {
- provide: {
- [INK_I18N_KEY as symbol]: mockI18n,
- },
- },
- });
-
- expect(wrapper.text()).toContain("Translated Error");
- expect(wrapper.text()).toContain("Translated Error Description");
- });
- });
-});
diff --git a/packages/web/src/components/inkPopup/inkPopup.ts b/packages/web/src/components/inkPopup/inkPopup.ts
index af476a4..e68fe44 100644
--- a/packages/web/src/components/inkPopup/inkPopup.ts
+++ b/packages/web/src/components/inkPopup/inkPopup.ts
@@ -17,6 +17,7 @@ export const inkPopupProps = {
default: "center",
},
closeOnScrim: makeBooleanProp(true),
+ scrim: makeBooleanProp(true),
} as const;
// --- Emits ---
diff --git a/packages/web/src/components/inkPopup/inkPopup.vue b/packages/web/src/components/inkPopup/inkPopup.vue
index 1719894..55bfcc3 100644
--- a/packages/web/src/components/inkPopup/inkPopup.vue
+++ b/packages/web/src/components/inkPopup/inkPopup.vue
@@ -43,7 +43,12 @@ const onScrimClick = () => {
-
+
diff --git a/packages/web/src/components/inkScrim/inkScrim.test.ts b/packages/web/src/components/inkScrim/inkScrim.test.ts
deleted file mode 100644
index d883e09..0000000
--- a/packages/web/src/components/inkScrim/inkScrim.test.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import InkScrim from "./inkScrim.vue";
-
-describe("InkScrim", () => {
- const mountOptions = {
- global: {
- stubs: {
- Teleport: {
- template: "
",
- },
- Transition: {
- template: "
",
- },
- },
- },
- };
-
- describe("rendering", () => {
- it("renders scrim overlay when open is true", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: true,
- },
- });
-
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(true);
- });
-
- it("does not render scrim when open is false", () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: false,
- },
- });
-
- expect(wrapper.find("[data-testid='ink-scrim']").exists()).toBe(false);
- });
- });
-
- describe("close functionality", () => {
- it("closes scrim when clicked if closeOnScrim is true", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: true,
- closeOnScrim: true,
- },
- });
-
- expect(wrapper.vm.open).toBe(true);
-
- const scrim = wrapper.find("[data-testid='ink-scrim']");
- await scrim.trigger("click");
-
- expect(wrapper.vm.open).toBe(false);
- });
-
- it("emits scrim-click event when scrim is clicked", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: true,
- },
- });
-
- const scrim = wrapper.find("[data-testid='ink-scrim']");
- await scrim.trigger("click");
-
- expect(wrapper.emitted("scrim-click")).toHaveLength(1);
- });
-
- it("does not close scrim when clicked if closeOnScrim is false", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: true,
- closeOnScrim: false,
- },
- });
-
- const scrim = wrapper.find("[data-testid='ink-scrim']");
- await scrim.trigger("click");
-
- expect(wrapper.vm.open).toBe(true);
- });
-
- it("closes once when the close button is clicked", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: true,
- showCloseButton: true,
- },
- });
-
- await wrapper.get("[data-testid='ink-scrim-close-btn']").trigger("click");
-
- expect(wrapper.emitted("close")).toHaveLength(1);
- expect(wrapper.emitted("update:open")).toEqual([[false]]);
- expect(wrapper.emitted("scrim-click")).toBeUndefined();
- });
- });
-
- describe("v-model:open", () => {
- it("updates open state via v-model", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: false,
- },
- });
-
- expect(wrapper.vm.open).toBe(false);
-
- await wrapper.setProps({ open: true });
-
- expect(wrapper.vm.open).toBe(true);
- });
- });
-
- describe("transitions", () => {
- it("applies fade transition when opening", async () => {
- const wrapper = mount(InkScrim, {
- ...mountOptions,
- props: {
- open: false,
- },
- });
-
- await wrapper.setProps({ open: true });
-
- const transition = wrapper.findComponent({ name: "Transition" });
- expect(transition.props("name")).toBe("ink-scrim-fade");
- });
- });
-});
diff --git a/packages/web/stories/feedback/inkPopup.story.md b/packages/web/stories/feedback/inkPopup.story.md
index fda9a25..2eace46 100644
--- a/packages/web/stories/feedback/inkPopup.story.md
+++ b/packages/web/stories/feedback/inkPopup.story.md
@@ -5,7 +5,7 @@ A flexible popup component with support for multiple positions, scrim overlay, a
## Features
- **Flexible Positioning**: Support for predefined positions (`center`, `left`, `right`, `top`, `bottom`) or custom coordinates
-- **Scrim Control**: Overlay that can close the popup on click
+- **Scrim Control**: Optional overlay that can close the popup on click
- **V-Model Support**: Easy open/close state management
- **Transitions**: Smooth fade and slide animations
- **Teleport**: Renders at the document root to avoid z-index stacking issues
@@ -55,6 +55,17 @@ const isOpen = ref(false);
```
+### Modeless Popup
+
+Use `scrim="false"` when the popup is a modeless outlet and the surrounding navigation host
+must remain pointer-accessible. `closeOnScrim` has no effect while the scrim is absent.
+
+```vue
+
+ Modeless content
+
+```
+
## Props
| Prop | Type | Default | Description |
@@ -62,6 +73,7 @@ const isOpen = ref(false);
| `open` | `boolean` | `false` | Controls popup visibility (supports v-model) |
| `position` | `PopupPosition` | `'center'` | Position of the popup: `'center'`, `'left'`, `'right'`, `'top'`, `'bottom'`, or array `[top, right, bottom, left]` |
| `closeOnScrim` | `boolean` | `true` | Whether clicking the scrim closes the popup |
+| `scrim` | `boolean` | `true` | Whether the popup renders a page-covering scrim |
## Types
diff --git a/packages/web/stories/feedback/inkPopup.story.vue b/packages/web/stories/feedback/inkPopup.story.vue
index f57964c..de92f34 100644
--- a/packages/web/stories/feedback/inkPopup.story.vue
+++ b/packages/web/stories/feedback/inkPopup.story.vue
@@ -4,13 +4,14 @@ import InkPopup from "../../src/components/inkPopup/inkPopup.vue";
import InkButton from "../../src/components/inkButton/inkButton.vue";
const visible = ref(false);
+const modelessVisible = ref(false);
-
+
Popup Content
This is the popup content.
@@ -18,5 +19,15 @@ const visible = ref(false);
+
+
+
+
+
Modeless content
+
The page outside this popup remains visible and pointer-accessible.
+
+
+
+
diff --git a/packages/web/stories/theme.test.ts b/packages/web/stories/theme.test.ts
deleted file mode 100644
index ca853a1..0000000
--- a/packages/web/stories/theme.test.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { describe, expect, test } from "vitest";
-import { installThemeBridge, resolveStoryTheme, synchronizeStoryTheme } from "./theme";
-
-describe("Histoire theme bridge", () => {
- test("maps the catalog light and dark classes to the token theme", async () => {
- const root = document.createElement("html");
-
- expect(resolveStoryTheme(root)).toBe("light");
- expect(synchronizeStoryTheme(root)).toBe("light");
- expect(root.dataset.theme).toBe("light");
-
- const disconnect = installThemeBridge(root);
- root.classList.add("dark");
- await new Promise((resolve) => setTimeout(resolve, 0));
-
- expect(root.dataset.theme).toBe("dark");
- disconnect();
- });
-});
diff --git a/packages/web/vitest.config.ts b/packages/web/vitest.config.ts
deleted file mode 100644
index 39efea3..0000000
--- a/packages/web/vitest.config.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { defineConfig } from "vitest/config";
-import vue from "@vitejs/plugin-vue";
-import { resolve } from "path";
-
-export default defineConfig({
- plugins: [vue()],
- test: {
- globals: true,
- environment: "happy-dom",
- coverage: {
- provider: "v8",
- reporter: ["text", "json", "html"],
- exclude: [
- "node_modules/",
- "dist/",
- "**/*.config.*",
- "**/*.d.ts",
- "**/index.ts",
- "stories/**/*.story.*",
- "stories/histoire.setup.ts",
- ],
- },
- },
- resolve: {
- alias: {
- "@": resolve(__dirname, "src"),
- },
- },
-});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e26a71c..8b16698 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -84,15 +84,6 @@ importers:
'@vitejs/plugin-vue':
specifier: ^6.0.3
version: 6.0.3(vite@7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0))(vue@3.5.25(typescript-native-bridge@6.0.3-bridge.7.tsgo.7.0.2))
- '@vitest/coverage-v8':
- specifier: ^4.0.15
- version: 4.0.15(supports-color@8.1.1)(vitest@4.0.15)
- '@vitest/ui':
- specifier: ^4.0.15
- version: 4.0.15(vitest@4.0.15)
- '@vue/test-utils':
- specifier: ^2.4.6
- version: 2.4.6
'@vueuse/core':
specifier: ^14.1.0
version: 14.1.0(vue@3.5.25(typescript-native-bridge@6.0.3-bridge.7.tsgo.7.0.2))
@@ -102,9 +93,6 @@ importers:
dayjs:
specifier: ^1.11.19
version: 1.11.19
- happy-dom:
- specifier: ^20.0.11
- version: 20.0.11
histoire:
specifier: 1.0.0-alpha.5
version: 1.0.0-alpha.5(@types/node@25.0.2)(sass@1.94.2)(supports-color@8.1.1)(tsx@4.21.0)(vite@7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)
@@ -126,9 +114,6 @@ importers:
vite-plugin-dts:
specifier: ^4.5.4
version: 4.5.4(@types/node@25.0.2)(rollup@4.53.3)(supports-color@8.1.1)(typescript-native-bridge@6.0.3-bridge.7.tsgo.7.0.2)(vite@7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0))
- vitest:
- specifier: ^4.0.15
- version: 4.0.15(@types/node@25.0.2)(@vitest/ui@4.0.15)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@25.0.1(supports-color@10.2.2))(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0)
vscode-json-languageservice:
specifier: ^5.6.4
version: 5.6.4
@@ -202,10 +187,6 @@ packages:
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
- '@bcoe/v8-coverage@1.0.2':
- resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
- engines: {node: '>=18'}
-
'@bundled-es-modules/deepmerge@4.3.1':
resolution: {integrity: sha512-Rk453EklPUPC3NRWc3VUNI/SSUjdBaFoaQvFRmNBNtMHVtOFD5AntiWg5kEE1hqcPqedYFDzxE3ZcMYPcA195w==}
@@ -1165,9 +1146,6 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
- '@one-ini/wasm@0.1.1':
- resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
-
'@oxfmt/binding-android-arm-eabi@0.60.0':
resolution: {integrity: sha512-1q4q4Jc8FlOMVojEisyFAVyl8h1yawNv6phjgmhGVEDeyeOdsSnSr9x0+D4mOnEKvpO5L4mxKZ/DP9X6U3A/Mw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1500,10 +1478,6 @@ packages:
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
engines: {node: '>= 10.0.0'}
- '@pkgjs/parseargs@0.11.0':
- resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
- engines: {node: '>=14'}
-
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
@@ -1714,9 +1688,6 @@ packages:
'@speed-highlight/core@1.2.23':
resolution: {integrity: sha512-iRoq6i6JDJP6Mt2A5JaPvzw0pgYHH6k92ij+yXiTrB7T2y9N789aWE3EHWj/5ztlJBokcCBja3iYLVdu5wgnkg==}
- '@standard-schema/spec@1.0.0':
- resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
-
'@tanstack/intent@0.3.6':
resolution: {integrity: sha512-ylew/4T3layUXSfE/SDGUSAi1B3U/wuoNUE0adC3j/s6wzX7omV6e6hAv0WyMC52Inren8kqvwpHj+G/ZBbQHQ==}
hasBin: true
@@ -1724,12 +1695,6 @@ packages:
'@types/argparse@1.0.38':
resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
- '@types/chai@5.2.3':
- resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
-
- '@types/deep-eql@4.0.2':
- resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
-
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -1757,9 +1722,6 @@ packages:
'@types/node@12.20.55':
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
- '@types/node@20.19.26':
- resolution: {integrity: sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==}
-
'@types/node@25.0.2':
resolution: {integrity: sha512-gWEkeiyYE4vqjON/+Obqcoeffmk0NF15WSBwSs7zwVA2bAbTaE0SJ7P0WNGoJn8uE7fiaV5a7dKYIJriEqOrmA==}
@@ -1769,9 +1731,6 @@ packages:
'@types/web-bluetooth@0.0.21':
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
- '@types/whatwg-mimetype@3.0.2':
- resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==}
-
'@typescript-native-bridge/darwin-arm64@6.0.3-bridge.7.tsgo.7.0.2':
resolution: {integrity: sha512-fLCYcIC3BOBZlrtwwtxQI0fMQ5GKg5ZQHLjcMASWNOClVAxPiPR0EigOktiuAPx9Pgjas9E4cDC2bgz7jwYNWg==}
cpu: [arm64]
@@ -1904,49 +1863,6 @@ packages:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
vue: ^3.2.25
- '@vitest/coverage-v8@4.0.15':
- resolution: {integrity: sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==}
- peerDependencies:
- '@vitest/browser': 4.0.15
- vitest: 4.0.15
- peerDependenciesMeta:
- '@vitest/browser':
- optional: true
-
- '@vitest/expect@4.0.15':
- resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==}
-
- '@vitest/mocker@4.0.15':
- resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==}
- peerDependencies:
- msw: ^2.4.9
- vite: ^6.0.0 || ^7.0.0-0
- peerDependenciesMeta:
- msw:
- optional: true
- vite:
- optional: true
-
- '@vitest/pretty-format@4.0.15':
- resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==}
-
- '@vitest/runner@4.0.15':
- resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==}
-
- '@vitest/snapshot@4.0.15':
- resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==}
-
- '@vitest/spy@4.0.15':
- resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==}
-
- '@vitest/ui@4.0.15':
- resolution: {integrity: sha512-sxSyJMaKp45zI0u+lHrPuZM1ZJQ8FaVD35k+UxVrha1yyvQ+TZuUYllUixwvQXlB7ixoDc7skf3lQPopZIvaQw==}
- peerDependencies:
- vitest: 4.0.15
-
- '@vitest/utils@4.0.15':
- resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==}
-
'@volar/language-core@2.4.26':
resolution: {integrity: sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A==}
@@ -2014,9 +1930,6 @@ packages:
'@vue/shared@3.5.25':
resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==}
- '@vue/test-utils@2.4.6':
- resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
-
'@vueuse/core@14.1.0':
resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==}
peerDependencies:
@@ -2034,10 +1947,6 @@ packages:
resolution: {integrity: sha512-0fztsk/0ryJ+2PPr9EyXS5/Co7OK8q3zY/xOoozEWaUsL5x+C0cyZ4YyMuUffOO2Dx/rAdq4JMPqW0VUtm+vzA==}
engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=18.0.0'}
- abbrev@2.0.0:
- resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'}
@@ -2112,13 +2021,6 @@ packages:
assert@2.1.0:
resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
- assertion-error@2.0.1:
- resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
- engines: {node: '>=12'}
-
- ast-v8-to-istanbul@0.3.8:
- resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==}
-
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -2178,10 +2080,6 @@ packages:
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
- chai@6.2.1:
- resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==}
- engines: {node: '>=18'}
-
chalk@5.6.2:
resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
@@ -2231,10 +2129,6 @@ packages:
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
- commander@10.0.1:
- resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
- engines: {node: '>=14'}
-
commander@12.1.0:
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
engines: {node: '>=18'}
@@ -2255,9 +2149,6 @@ packages:
confbox@0.2.2:
resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
- config-chain@1.1.13:
- resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
-
connect@3.7.0:
resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
engines: {node: '>= 0.10.0'}
@@ -2389,11 +2280,6 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- editorconfig@1.0.4:
- resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
- engines: {node: '>=14'}
- hasBin: true
-
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
@@ -2471,17 +2357,10 @@ packages:
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
- estree-walker@3.0.3:
- resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
-
events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
- expect-type@1.3.0:
- resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
- engines: {node: '>=12.0.0'}
-
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
@@ -2511,9 +2390,6 @@ packages:
picomatch:
optional: true
- fflate@0.8.2:
- resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
-
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
@@ -2526,9 +2402,6 @@ packages:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
- flatted@3.3.3:
- resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
-
for-each@0.3.5:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
@@ -2597,11 +2470,6 @@ packages:
peerDependencies:
tslib: '2'
- glob@10.5.0:
- resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
- deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
- hasBin: true
-
glob@11.1.0:
resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==}
engines: {node: 20 || >=22}
@@ -2643,10 +2511,6 @@ packages:
resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
engines: {node: '>=10'}
- happy-dom@20.0.11:
- resolution: {integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==}
- engines: {node: '>=20.0.0'}
-
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -2686,9 +2550,6 @@ packages:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
- html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
-
html-void-elements@3.0.0:
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
@@ -2744,9 +2605,6 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- ini@1.3.8:
- resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
-
is-arguments@1.2.0:
resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==}
engines: {node: '>= 0.4'}
@@ -2826,25 +2684,6 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
-
- istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
-
- istanbul-lib-source-maps@5.0.6:
- resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
- engines: {node: '>=10'}
-
- istanbul-reports@3.2.0:
- resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
- engines: {node: '>=8'}
-
- jackspeak@3.4.3:
- resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
-
jackspeak@4.1.1:
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
engines: {node: 20 || >=22}
@@ -2856,21 +2695,9 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
- js-beautify@1.15.4:
- resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
- engines: {node: '>=14'}
- hasBin: true
-
- js-cookie@3.0.5:
- resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
- engines: {node: '>=14'}
-
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-tokens@9.0.1:
- resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
-
js-yaml@3.14.2:
resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
hasBin: true
@@ -2955,13 +2782,6 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
- magicast@0.5.1:
- resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==}
-
- make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
-
markdown-it-anchor@9.2.0:
resolution: {integrity: sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg==}
peerDependencies:
@@ -3043,10 +2863,6 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
- minimatch@9.0.1:
- resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
- engines: {node: '>=16 || 14 >=14.17'}
-
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -3235,11 +3051,6 @@ packages:
version: 22.22.3
hasBin: true
- nopt@7.2.1:
- resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- hasBin: true
-
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
@@ -3263,9 +3074,6 @@ packages:
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
engines: {node: '>= 0.4'}
- obug@2.1.1:
- resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
-
ofetch@1.5.1:
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
@@ -3369,10 +3177,6 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
- path-scurry@1.11.1:
- resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
- engines: {node: '>=16 || 14 >=14.18'}
-
path-scurry@2.0.1:
resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
engines: {node: 20 || >=22}
@@ -3453,9 +3257,6 @@ packages:
property-information@7.1.0:
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
- proto-list@1.2.4:
- resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
-
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@@ -3643,9 +3444,6 @@ packages:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
- siginfo@2.0.0:
- resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
-
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@@ -3683,16 +3481,10 @@ packages:
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
- stackback@0.0.2:
- resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
-
statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'}
- std-env@3.10.0:
- resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
-
std-env@4.2.0:
resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==}
@@ -3749,10 +3541,6 @@ packages:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
- supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
-
supports-color@8.1.1:
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
engines: {node: '>=10'}
@@ -3774,9 +3562,6 @@ packages:
peerDependencies:
tslib: ^2
- tinybench@2.9.0:
- resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
-
tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
@@ -3792,10 +3577,6 @@ packages:
resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==}
engines: {node: ^20.0.0 || >=22.0.0}
- tinyrainbow@3.0.3:
- resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==}
- engines: {node: '>=14.0.0'}
-
tldts-core@6.1.86:
resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
@@ -3853,9 +3634,6 @@ packages:
unconfig@7.4.2:
resolution: {integrity: sha512-nrMlWRQ1xdTjSnSUqvYqJzbTBFugoqHobQj58B2bc8qxHKBBHMNNsWQFP3Cd3/JZK907voM2geYPWqD4VK3MPQ==}
- undici-types@6.21.0:
- resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
-
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
@@ -3990,40 +3768,6 @@ packages:
yaml:
optional: true
- vitest@4.0.15:
- resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==}
- engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
- hasBin: true
- peerDependencies:
- '@edge-runtime/vm': '*'
- '@opentelemetry/api': ^1.9.0
- '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
- '@vitest/browser-playwright': 4.0.15
- '@vitest/browser-preview': 4.0.15
- '@vitest/browser-webdriverio': 4.0.15
- '@vitest/ui': 4.0.15
- happy-dom: '*'
- jsdom: '*'
- peerDependenciesMeta:
- '@edge-runtime/vm':
- optional: true
- '@opentelemetry/api':
- optional: true
- '@types/node':
- optional: true
- '@vitest/browser-playwright':
- optional: true
- '@vitest/browser-preview':
- optional: true
- '@vitest/browser-webdriverio':
- optional: true
- '@vitest/ui':
- optional: true
- happy-dom:
- optional: true
- jsdom:
- optional: true
-
vscode-json-languageservice@5.6.4:
resolution: {integrity: sha512-i0MhkFmnQAbYr+PiE6Th067qa3rwvvAErCEUo0ql+ghFXHvxbwG3kLbwMaIUrrbCLUDEeULiLgROJjtuyYoIsA==}
@@ -4036,9 +3780,6 @@ packages:
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
- vue-component-type-helpers@2.2.12:
- resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==}
-
vue-flow-layout@0.2.0:
resolution: {integrity: sha512-zKgsWWkXq0xrus7H4Mc+uFs1ESrmdTXlO0YNbR6wMdPaFvosL3fMB8N7uTV308UhGy9UvTrGhIY7mVz9eN+L0Q==}
@@ -4084,10 +3825,6 @@ packages:
engines: {node: '>=18'}
deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
- whatwg-mimetype@3.0.0:
- resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
- engines: {node: '>=12'}
-
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
@@ -4105,11 +3842,6 @@ packages:
engines: {node: '>= 8'}
hasBin: true
- why-is-node-running@2.3.0:
- resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
- engines: {node: '>=8'}
- hasBin: true
-
workerd@1.20260801.1:
resolution: {integrity: sha512-/g9JGTyqnHtoIscpBHqKD8swE2V4StBs2i69PmLiOhH45OP95jCFICl4F1hKlgN57rqfni5LiCitttoX5OOkVA==}
engines: {node: '>=16'}
@@ -4264,8 +3996,6 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
- '@bcoe/v8-coverage@1.0.2': {}
-
'@bundled-es-modules/deepmerge@4.3.1':
dependencies:
deepmerge: 4.3.1
@@ -5116,8 +4846,6 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
- '@one-ini/wasm@0.1.1': {}
-
'@oxfmt/binding-android-arm-eabi@0.60.0':
optional: true
@@ -5293,9 +5021,6 @@ snapshots:
'@parcel/watcher-win32-x64': 2.5.1
optional: true
- '@pkgjs/parseargs@0.11.0':
- optional: true
-
'@polka/url@1.0.0-next.29': {}
'@poppinss/colors@4.1.6':
@@ -5468,8 +5193,6 @@ snapshots:
'@speed-highlight/core@1.2.23': {}
- '@standard-schema/spec@1.0.0': {}
-
'@tanstack/intent@0.3.6':
dependencies:
cac: 6.7.14
@@ -5480,13 +5203,6 @@ snapshots:
'@types/argparse@1.0.38': {}
- '@types/chai@5.2.3':
- dependencies:
- '@types/deep-eql': 4.0.2
- assertion-error: 2.0.1
-
- '@types/deep-eql@4.0.2': {}
-
'@types/estree@1.0.8': {}
'@types/fs-extra@11.0.4':
@@ -5517,10 +5233,6 @@ snapshots:
'@types/node@12.20.55': {}
- '@types/node@20.19.26':
- dependencies:
- undici-types: 6.21.0
-
'@types/node@25.0.2':
dependencies:
undici-types: 7.16.0
@@ -5529,8 +5241,6 @@ snapshots:
'@types/web-bluetooth@0.0.21': {}
- '@types/whatwg-mimetype@3.0.2': {}
-
'@typescript-native-bridge/darwin-arm64@6.0.3-bridge.7.tsgo.7.0.2':
optional: true
@@ -5707,73 +5417,6 @@ snapshots:
vite: 7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0)
vue: 3.5.25(typescript-native-bridge@6.0.3-bridge.7.tsgo.7.0.2)
- '@vitest/coverage-v8@4.0.15(supports-color@8.1.1)(vitest@4.0.15)':
- dependencies:
- '@bcoe/v8-coverage': 1.0.2
- '@vitest/utils': 4.0.15
- ast-v8-to-istanbul: 0.3.8
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 5.0.6(supports-color@8.1.1)
- istanbul-reports: 3.2.0
- magicast: 0.5.1
- obug: 2.1.1
- std-env: 3.10.0
- tinyrainbow: 3.0.3
- vitest: 4.0.15(@types/node@25.0.2)(@vitest/ui@4.0.15)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@25.0.1(supports-color@10.2.2))(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0)
- transitivePeerDependencies:
- - supports-color
-
- '@vitest/expect@4.0.15':
- dependencies:
- '@standard-schema/spec': 1.0.0
- '@types/chai': 5.2.3
- '@vitest/spy': 4.0.15
- '@vitest/utils': 4.0.15
- chai: 6.2.1
- tinyrainbow: 3.0.3
-
- '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0))':
- dependencies:
- '@vitest/spy': 4.0.15
- estree-walker: 3.0.3
- magic-string: 0.30.21
- optionalDependencies:
- vite: 7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0)
-
- '@vitest/pretty-format@4.0.15':
- dependencies:
- tinyrainbow: 3.0.3
-
- '@vitest/runner@4.0.15':
- dependencies:
- '@vitest/utils': 4.0.15
- pathe: 2.0.3
-
- '@vitest/snapshot@4.0.15':
- dependencies:
- '@vitest/pretty-format': 4.0.15
- magic-string: 0.30.21
- pathe: 2.0.3
-
- '@vitest/spy@4.0.15': {}
-
- '@vitest/ui@4.0.15(vitest@4.0.15)':
- dependencies:
- '@vitest/utils': 4.0.15
- fflate: 0.8.2
- flatted: 3.3.3
- pathe: 2.0.3
- sirv: 3.0.2
- tinyglobby: 0.2.15
- tinyrainbow: 3.0.3
- vitest: 4.0.15(@types/node@25.0.2)(@vitest/ui@4.0.15)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@25.0.1(supports-color@10.2.2))(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0)
-
- '@vitest/utils@4.0.15':
- dependencies:
- '@vitest/pretty-format': 4.0.15
- tinyrainbow: 3.0.3
-
'@volar/language-core@2.4.26':
dependencies:
'@volar/source-map': 2.4.26
@@ -5884,11 +5527,6 @@ snapshots:
'@vue/shared@3.5.25': {}
- '@vue/test-utils@2.4.6':
- dependencies:
- js-beautify: 1.15.4
- vue-component-type-helpers: 2.2.12
-
'@vueuse/core@14.1.0(vue@3.5.25(typescript-native-bridge@6.0.3-bridge.7.tsgo.7.0.2))':
dependencies:
'@types/web-bluetooth': 0.0.21
@@ -5904,8 +5542,6 @@ snapshots:
'@zip.js/zip.js@2.8.11': {}
- abbrev@2.0.0: {}
-
acorn@8.15.0: {}
agent-base@7.1.4: {}
@@ -5969,14 +5605,6 @@ snapshots:
object.assign: 4.1.7
util: 0.12.5
- assertion-error@2.0.1: {}
-
- ast-v8-to-istanbul@0.3.8:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.31
- estree-walker: 3.0.3
- js-tokens: 9.0.1
-
asynckit@0.4.0: {}
available-typed-arrays@1.0.7:
@@ -6036,8 +5664,6 @@ snapshots:
ccount@2.0.1: {}
- chai@6.2.1: {}
-
chalk@5.6.2: {}
change-case@5.4.4: {}
@@ -6086,8 +5712,6 @@ snapshots:
comma-separated-tokens@2.0.3: {}
- commander@10.0.1: {}
-
commander@12.1.0: {}
compare-versions@6.1.1: {}
@@ -6100,11 +5724,6 @@ snapshots:
confbox@0.2.2: {}
- config-chain@1.1.13:
- dependencies:
- ini: 1.3.8
- proto-list: 1.2.4
-
connect@3.7.0(supports-color@8.1.1):
dependencies:
debug: 2.6.9(supports-color@8.1.1)
@@ -6227,13 +5846,6 @@ snapshots:
eastasianwidth@0.2.0: {}
- editorconfig@1.0.4:
- dependencies:
- '@one-ini/wasm': 0.1.1
- commander: 10.0.1
- minimatch: 9.0.1
- semver: 7.7.3
-
ee-first@1.1.1: {}
emoji-regex@8.0.0: {}
@@ -6365,14 +5977,8 @@ snapshots:
estree-walker@2.0.2: {}
- estree-walker@3.0.3:
- dependencies:
- '@types/estree': 1.0.8
-
events@3.3.0: {}
- expect-type@1.3.0: {}
-
exsolve@1.0.8: {}
extend-shallow@2.0.1:
@@ -6399,8 +6005,6 @@ snapshots:
optionalDependencies:
picomatch: 4.0.3
- fflate@0.8.2: {}
-
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
@@ -6422,8 +6026,6 @@ snapshots:
locate-path: 5.0.0
path-exists: 4.0.0
- flatted@3.3.3: {}
-
for-each@0.3.5:
dependencies:
is-callable: 1.2.7
@@ -6502,15 +6104,6 @@ snapshots:
dependencies:
tslib: 2.8.1
- glob@10.5.0:
- dependencies:
- foreground-child: 3.3.1
- jackspeak: 3.4.3
- minimatch: 9.0.5
- minipass: 7.1.2
- package-json-from-dist: 1.0.1
- path-scurry: 1.11.1
-
glob@11.1.0:
dependencies:
foreground-child: 3.3.1
@@ -6570,12 +6163,6 @@ snapshots:
dependencies:
duplexer: 0.1.2
- happy-dom@20.0.11:
- dependencies:
- '@types/node': 20.19.26
- '@types/whatwg-mimetype': 3.0.2
- whatwg-mimetype: 3.0.0
-
has-flag@4.0.0: {}
has-property-descriptors@1.0.2:
@@ -6664,8 +6251,6 @@ snapshots:
dependencies:
whatwg-encoding: 3.1.1
- html-escaper@2.0.2: {}
-
html-void-elements@3.0.0: {}
http-proxy-agent@7.0.2(supports-color@10.2.2):
@@ -6713,8 +6298,6 @@ snapshots:
inherits@2.0.4: {}
- ini@1.3.8: {}
-
is-arguments@1.2.0:
dependencies:
call-bound: 1.0.4
@@ -6784,33 +6367,6 @@ snapshots:
isexe@2.0.0: {}
- istanbul-lib-coverage@3.2.2: {}
-
- istanbul-lib-report@3.0.1:
- dependencies:
- istanbul-lib-coverage: 3.2.2
- make-dir: 4.0.0
- supports-color: 7.2.0
-
- istanbul-lib-source-maps@5.0.6(supports-color@8.1.1):
- dependencies:
- '@jridgewell/trace-mapping': 0.3.31
- debug: 4.4.3(supports-color@8.1.1)
- istanbul-lib-coverage: 3.2.2
- transitivePeerDependencies:
- - supports-color
-
- istanbul-reports@3.2.0:
- dependencies:
- html-escaper: 2.0.2
- istanbul-lib-report: 3.0.1
-
- jackspeak@3.4.3:
- dependencies:
- '@isaacs/cliui': 8.0.2
- optionalDependencies:
- '@pkgjs/parseargs': 0.11.0
-
jackspeak@4.1.1:
dependencies:
'@isaacs/cliui': 8.0.2
@@ -6819,20 +6375,8 @@ snapshots:
jju@1.4.0: {}
- js-beautify@1.15.4:
- dependencies:
- config-chain: 1.1.13
- editorconfig: 1.0.4
- glob: 10.5.0
- js-cookie: 3.0.5
- nopt: 7.2.1
-
- js-cookie@3.0.5: {}
-
js-tokens@4.0.0: {}
- js-tokens@9.0.1: {}
-
js-yaml@3.14.2:
dependencies:
argparse: 1.0.10
@@ -6929,16 +6473,6 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
- magicast@0.5.1:
- dependencies:
- '@babel/parser': 7.28.5
- '@babel/types': 7.28.5
- source-map-js: 1.2.1
-
- make-dir@4.0.0:
- dependencies:
- semver: 7.7.3
-
markdown-it-anchor@9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0):
dependencies:
'@types/markdown-it': 14.1.2
@@ -7040,10 +6574,6 @@ snapshots:
dependencies:
brace-expansion: 1.1.12
- minimatch@9.0.1:
- dependencies:
- brace-expansion: 2.0.2
-
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.2
@@ -7082,10 +6612,6 @@ snapshots:
node@runtime:22.22.3: {}
- nopt@7.2.1:
- dependencies:
- abbrev: 2.0.0
-
normalize-path@3.0.0: {}
nwsapi@2.2.23: {}
@@ -7108,8 +6634,6 @@ snapshots:
has-symbols: 1.1.0
object-keys: 1.1.1
- obug@2.1.1: {}
-
ofetch@1.5.1:
dependencies:
destr: 2.0.5
@@ -7226,11 +6750,6 @@ snapshots:
path-parse@1.0.7: {}
- path-scurry@1.11.1:
- dependencies:
- lru-cache: 10.4.3
- minipass: 7.1.2
-
path-scurry@2.0.1:
dependencies:
lru-cache: 11.2.2
@@ -7293,8 +6812,6 @@ snapshots:
property-information@7.1.0: {}
- proto-list@1.2.4: {}
-
punycode.js@2.3.1: {}
punycode@1.4.1: {}
@@ -7531,8 +7048,6 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
- siginfo@2.0.0: {}
-
signal-exit@4.1.0: {}
sirv@3.0.2:
@@ -7560,12 +7075,8 @@ snapshots:
sprintf-js@1.0.3: {}
- stackback@0.0.2: {}
-
statuses@1.5.0: {}
- std-env@3.10.0: {}
-
std-env@4.2.0: {}
stream@0.0.3:
@@ -7628,10 +7139,6 @@ snapshots:
supports-color@10.2.2: {}
- supports-color@7.2.0:
- dependencies:
- has-flag: 4.0.0
-
supports-color@8.1.1:
dependencies:
has-flag: 4.0.0
@@ -7646,8 +7153,6 @@ snapshots:
dependencies:
tslib: 2.8.1
- tinybench@2.9.0: {}
-
tinycolor2@1.6.0: {}
tinyexec@1.0.2: {}
@@ -7659,8 +7164,6 @@ snapshots:
tinypool@2.1.0: {}
- tinyrainbow@3.0.3: {}
-
tldts-core@6.1.86: {}
tldts@6.1.86:
@@ -7723,8 +7226,6 @@ snapshots:
quansync: 1.0.0
unconfig-core: 7.4.2
- undici-types@6.21.0: {}
-
undici-types@7.16.0: {}
undici@7.28.0: {}
@@ -7885,46 +7386,6 @@ snapshots:
tsx: 4.21.0
yaml: 2.9.0
- vitest@4.0.15(@types/node@25.0.2)(@vitest/ui@4.0.15)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@25.0.1(supports-color@10.2.2))(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0):
- dependencies:
- '@vitest/expect': 4.0.15
- '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0))
- '@vitest/pretty-format': 4.0.15
- '@vitest/runner': 4.0.15
- '@vitest/snapshot': 4.0.15
- '@vitest/spy': 4.0.15
- '@vitest/utils': 4.0.15
- es-module-lexer: 1.7.0
- expect-type: 1.3.0
- magic-string: 0.30.21
- obug: 2.1.1
- pathe: 2.0.3
- picomatch: 4.0.3
- std-env: 3.10.0
- tinybench: 2.9.0
- tinyexec: 1.0.2
- tinyglobby: 0.2.15
- tinyrainbow: 3.0.3
- vite: 7.2.7(@types/node@25.0.2)(jiti@2.6.1)(sass@1.94.2)(tsx@4.21.0)(yaml@2.9.0)
- why-is-node-running: 2.3.0
- optionalDependencies:
- '@types/node': 25.0.2
- '@vitest/ui': 4.0.15(vitest@4.0.15)
- happy-dom: 20.0.11
- jsdom: 25.0.1(supports-color@10.2.2)
- transitivePeerDependencies:
- - jiti
- - less
- - lightningcss
- - msw
- - sass
- - sass-embedded
- - stylus
- - sugarss
- - terser
- - tsx
- - yaml
-
vscode-json-languageservice@5.6.4:
dependencies:
'@vscode/l10n': 0.0.18
@@ -7939,8 +7400,6 @@ snapshots:
vscode-uri@3.1.0: {}
- vue-component-type-helpers@2.2.12: {}
-
vue-flow-layout@0.2.0: {}
vue-i18n@11.2.7(vue@3.5.25(typescript-native-bridge@6.0.3-bridge.7.tsgo.7.0.2)):
@@ -7983,8 +7442,6 @@ snapshots:
dependencies:
iconv-lite: 0.6.3
- whatwg-mimetype@3.0.0: {}
-
whatwg-mimetype@4.0.0: {}
whatwg-url@14.2.0:
@@ -8006,11 +7463,6 @@ snapshots:
dependencies:
isexe: 2.0.0
- why-is-node-running@2.3.0:
- dependencies:
- siginfo: 2.0.0
- stackback: 0.0.2
-
workerd@1.20260801.1:
optionalDependencies:
'@cloudflare/workerd-darwin-64': 1.20260801.1