storybook-addon-vis 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import "./global_matcher_augment-CYxLwns2.js";
2
2
  import { ComparisonMethod, FailureThresholdOptions, ImageSnapshotCompareOptions, ImageSnapshotKeyOptions, ImageSnapshotKeyOptions as ImageSnapshotKeyOptions$1, ImageSnapshotSubjectOptions, ImageSnapshotTimeoutOptions, PixelComparisonOptions, SsimComparisonOptions, ToMatchImageSnapshotOptions } from "vitest-plugin-vis/client-api";
3
+ import * as storybook_internal_csf0 from "storybook/internal/csf";
4
+ import { SetupVisOptions } from "vitest-plugin-vis";
3
5
  import { BrowserPage } from "vitest/browser";
4
6
  import "vitest/suite";
5
- import * as storybook_internal_csf0 from "storybook/internal/csf";
6
7
  export * from "vitest-plugin-vis";
7
8
 
8
9
  //#region src/client/vitest_proxy.d.ts
@@ -28,12 +29,7 @@ declare function defineAutoSnapshotParam<M extends ComparisonMethod>(snapshot: T
28
29
  declare function isSnapshotEnabled(tags: string[]): boolean;
29
30
  //#endregion
30
31
  //#region src/index.d.ts
31
- declare const _default: (options?: {
32
- auto: boolean;
33
- }) => {
34
- beforeEach(ctx: storybook_internal_csf0.StoryContext<any, storybook_internal_csf0.Args>): void;
35
- tags: string[];
36
- };
32
+ declare const _default: (options?: SetupVisOptions) => storybook_internal_csf0.PreviewAddon<storybook_internal_csf0.AddonTypes>;
37
33
  //#endregion
38
34
  export { type ComparisonMethod, type FailureThresholdOptions, type ImageSnapshotCompareOptions, type ImageSnapshotKeyOptions, type ImageSnapshotSubjectOptions, type ImageSnapshotTimeoutOptions, type PixelComparisonOptions, type SsimComparisonOptions, type ToMatchImageSnapshotOptions, _default as default, defineAutoSnapshotParam, hasImageSnapshot, isSnapshotEnabled, page };
39
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/client/vitest_proxy.ts","../src/client/has_image_snapshot.ts","../src/client/storybook/param.ts","../src/client/storybook/tags.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAiBa,MAAI;;;;;;iBCVD,gBAAA,WAA2B,gDAAmC;;;;;;iBCqB9D,kCAAkC,4BACvC,4BAA4B,KAAK;;;;AFZ5C,CAAA;;;iBGjBgB,iBAAA;;;cCYD;EJKF,IAAA,EAAA,OAQX;;kBIba,uBAAA,CAAA,kBAAA,uBAAA,CAAA,IAAA;;AHLf,CAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/client/vitest_proxy.ts","../src/client/has_image_snapshot.ts","../src/client/storybook/param.ts","../src/client/storybook/tags.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;cAiBa,MAAI;;;;;;iBCVD,gBAAA,WAA2B,gDAAmC;;;;;;iBCqB9D,kCAAkC,4BACvC,4BAA4B,KAAK;;;;;;;iBC7B5B,iBAAA;;;cCgBD,qBAEU,oBAAiC,uBAAA,CAAA,aAAA,uBAAA,CAAA,UAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import { a as page, i as getCurrentTest, n as isSnapshotEnabled, r as commands, t as visAnnotations } from "./vis_annotation-Dpsgn_4P.js";
2
- import { hasImageSnapshotAction, toTaskId } from "vitest-plugin-vis/client-api";
1
+ import { a as page, i as getCurrentTest, n as isSnapshotEnabled, r as commands, t as visAnnotations } from "./vis_annotation-DqZTkmEN.js";
2
+ import { expect } from "storybook/test";
3
+ import { autoSnapshotMatcher, hasImageSnapshotAction, setAutoSnapshotOptions, toTaskId } from "vitest-plugin-vis/client-api";
4
+ import { definePreviewAddon } from "storybook/internal/csf";
3
5
 
4
6
  export * from "vitest-plugin-vis"
5
7
 
@@ -34,10 +36,23 @@ function defineAutoSnapshotParam(snapshot) {
34
36
  //#endregion
35
37
  //#region src/index.ts
36
38
  var src_default = (options = { auto: false }) => {
37
- return {
39
+ let matcher;
40
+ let matcherFn;
41
+ return definePreviewAddon({
38
42
  tags: options.auto ? ["snapshot"] : [],
43
+ async beforeAll() {
44
+ matcher = autoSnapshotMatcher(commands, expect);
45
+ if (typeof options?.auto === "function") matcherFn = matcher.createMatcher({ auto: options.auto });
46
+ else if (typeof options?.auto === "object") matcherFn = matcher.createMatcher(options.auto);
47
+ else matcherFn = matcher.createMatcher({ async auto() {} });
48
+ await matcher.setup();
49
+ await setAutoSnapshotOptions(true);
50
+ },
51
+ afterEach() {
52
+ if (matcherFn) return matcherFn();
53
+ },
39
54
  ...visAnnotations
40
- };
55
+ });
41
56
  };
42
57
 
43
58
  //#endregion
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/client/ctx.ts","../src/client/has_image_snapshot.ts","../src/client/storybook/param.ts","../src/index.ts"],"sourcesContent":["import { getCurrentTest } from './vitest_proxy.ts'\n\nexport const ctx = {\n\tgetCurrentTest,\n\t__test__reset() {\n\t\tctx.getCurrentTest = getCurrentTest\n\t},\n}\n","import { hasImageSnapshotAction, toTaskId, type ImageSnapshotKeyOptions } from 'vitest-plugin-vis/client-api'\nimport { ctx } from './ctx.ts'\nimport { commands } from './vitest_proxy.ts'\n\n/**\n * Check if the snapshot image exists.\n */\nexport function hasImageSnapshot(options?: ImageSnapshotKeyOptions | undefined) {\n\tconst test = ctx.getCurrentTest()\n\tif (!test) return false\n\n\treturn hasImageSnapshotAction(commands, toTaskId(test), options)\n}\n","import type {\n\tComparisonMethod,\n\tFailureThresholdOptions,\n\tImageSnapshotCompareOptions,\n\tImageSnapshotKeyOptions,\n\tImageSnapshotSubjectOptions,\n\tImageSnapshotTimeoutOptions,\n\tPixelComparisonOptions,\n\tSsimComparisonOptions,\n\tToMatchImageSnapshotOptions,\n} from 'vitest-plugin-vis/client-api'\n\n// This fix the inferred type cannot be named error\nexport type {\n\tComparisonMethod,\n\tFailureThresholdOptions,\n\tImageSnapshotCompareOptions,\n\tImageSnapshotKeyOptions,\n\tImageSnapshotSubjectOptions,\n\tImageSnapshotTimeoutOptions,\n\tPixelComparisonOptions,\n\tSsimComparisonOptions,\n\tToMatchImageSnapshotOptions,\n}\n\n/**\n * Define snapshot parameter for auto snapshot.\n */\nexport function defineAutoSnapshotParam<M extends ComparisonMethod>(\n\tsnapshot: ToMatchImageSnapshotOptions<M> & ImageSnapshotSubjectOptions,\n) {\n\treturn { snapshot }\n}\n","// `storybook-addon-vis` provides code that can be used in test files.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport { page } from './client/vitest_proxy.ts'\nimport { visAnnotations } from './preview/vis_annotation.ts'\n\nexport * from 'vitest-plugin-vis'\nexport * from './client/has_image_snapshot.ts'\nexport * from './client/storybook/param.ts'\nexport * from './client/storybook/tags.ts'\n\nexport { page }\n\nexport default (options: { auto: boolean } = { auto: false }) => {\n\treturn {\n\t\ttags: options.auto ? ['snapshot'] : [],\n\t\t...visAnnotations,\n\t}\n}\n"],"mappings":";;;;;;AAEA,MAAa,MAAM;CAClB;CACA,gBAAgB;AACf,MAAI,iBAAiB;;CAEtB;;;;;;;ACAD,SAAgB,iBAAiB,SAA+C;CAC/E,MAAM,OAAO,IAAI,gBAAgB;AACjC,KAAI,CAAC,KAAM,QAAO;AAElB,QAAO,uBAAuB,UAAU,SAAS,KAAK,EAAE,QAAQ;;;;;;;;ACiBjE,SAAgB,wBACf,UACC;AACD,QAAO,EAAE,UAAU;;;;;ACjBpB,mBAAgB,UAA6B,EAAE,MAAM,OAAO,KAAK;AAChE,QAAO;EACN,MAAM,QAAQ,OAAO,CAAC,WAAW,GAAG,EAAE;EACtC,GAAG;EACH"}
1
+ {"version":3,"file":"index.js","names":["matcher: ReturnType<typeof autoSnapshotMatcher>","matcherFn: () => Promise<void>"],"sources":["../src/client/ctx.ts","../src/client/has_image_snapshot.ts","../src/client/storybook/param.ts","../src/index.ts"],"sourcesContent":["import { getCurrentTest } from './vitest_proxy.ts'\n\nexport const ctx = {\n\tgetCurrentTest,\n\t__test__reset() {\n\t\tctx.getCurrentTest = getCurrentTest\n\t},\n}\n","import { hasImageSnapshotAction, toTaskId, type ImageSnapshotKeyOptions } from 'vitest-plugin-vis/client-api'\nimport { ctx } from './ctx.ts'\nimport { commands } from './vitest_proxy.ts'\n\n/**\n * Check if the snapshot image exists.\n */\nexport function hasImageSnapshot(options?: ImageSnapshotKeyOptions | undefined) {\n\tconst test = ctx.getCurrentTest()\n\tif (!test) return false\n\n\treturn hasImageSnapshotAction(commands, toTaskId(test), options)\n}\n","import type {\n\tComparisonMethod,\n\tFailureThresholdOptions,\n\tImageSnapshotCompareOptions,\n\tImageSnapshotKeyOptions,\n\tImageSnapshotSubjectOptions,\n\tImageSnapshotTimeoutOptions,\n\tPixelComparisonOptions,\n\tSsimComparisonOptions,\n\tToMatchImageSnapshotOptions,\n} from 'vitest-plugin-vis/client-api'\n\n// This fix the inferred type cannot be named error\nexport type {\n\tComparisonMethod,\n\tFailureThresholdOptions,\n\tImageSnapshotCompareOptions,\n\tImageSnapshotKeyOptions,\n\tImageSnapshotSubjectOptions,\n\tImageSnapshotTimeoutOptions,\n\tPixelComparisonOptions,\n\tSsimComparisonOptions,\n\tToMatchImageSnapshotOptions,\n}\n\n/**\n * Define snapshot parameter for auto snapshot.\n */\nexport function defineAutoSnapshotParam<M extends ComparisonMethod>(\n\tsnapshot: ToMatchImageSnapshotOptions<M> & ImageSnapshotSubjectOptions,\n) {\n\treturn { snapshot }\n}\n","// `storybook-addon-vis` provides code that can be used in test files.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport { definePreviewAddon } from 'storybook/internal/csf'\nimport { expect } from 'storybook/test'\nimport type { SetupVisOptions } from 'vitest-plugin-vis'\nimport { autoSnapshotMatcher, setAutoSnapshotOptions } from 'vitest-plugin-vis/client-api'\nimport { commands, page } from './client/vitest_proxy.ts'\nimport { visAnnotations } from './preview/vis_annotation.ts'\n\nexport * from 'vitest-plugin-vis'\nexport * from './client/has_image_snapshot.ts'\nexport * from './client/storybook/param.ts'\nexport * from './client/storybook/tags.ts'\n\nexport { page }\n\nexport default (options: SetupVisOptions = { auto: false }) => {\n\tlet matcher: ReturnType<typeof autoSnapshotMatcher>\n\tlet matcherFn: () => Promise<void>\n\treturn definePreviewAddon({\n\t\ttags: options.auto ? ['snapshot'] : [],\n\t\tasync beforeAll() {\n\t\t\tmatcher = autoSnapshotMatcher(commands, expect)\n\t\t\tif (typeof options?.auto === 'function') {\n\t\t\t\tmatcherFn = matcher.createMatcher({\n\t\t\t\t\tauto: options.auto,\n\t\t\t\t})\n\t\t\t} else if (typeof options?.auto === 'object') {\n\t\t\t\tmatcherFn = matcher.createMatcher(options.auto)\n\t\t\t} else matcherFn = matcher.createMatcher({ async auto() {} })\n\n\t\t\tawait matcher.setup()\n\t\t\tawait setAutoSnapshotOptions(true)\n\t\t},\n\t\tafterEach() {\n\t\t\tif (matcherFn) {\n\t\t\t\treturn matcherFn()\n\t\t\t}\n\t\t},\n\t\t...visAnnotations,\n\t})\n}\n"],"mappings":";;;;;;;;AAEA,MAAa,MAAM;CAClB;CACA,gBAAgB;AACf,MAAI,iBAAiB;;CAEtB;;;;;;;ACAD,SAAgB,iBAAiB,SAA+C;CAC/E,MAAM,OAAO,IAAI,gBAAgB;AACjC,KAAI,CAAC,KAAM,QAAO;AAElB,QAAO,uBAAuB,UAAU,SAAS,KAAK,EAAE,QAAQ;;;;;;;;ACiBjE,SAAgB,wBACf,UACC;AACD,QAAO,EAAE,UAAU;;;;;ACbpB,mBAAgB,UAA2B,EAAE,MAAM,OAAO,KAAK;CAC9D,IAAIA;CACJ,IAAIC;AACJ,QAAO,mBAAmB;EACzB,MAAM,QAAQ,OAAO,CAAC,WAAW,GAAG,EAAE;EACtC,MAAM,YAAY;AACjB,aAAU,oBAAoB,UAAU,OAAO;AAC/C,OAAI,OAAO,SAAS,SAAS,WAC5B,aAAY,QAAQ,cAAc,EACjC,MAAM,QAAQ,MACd,CAAC;YACQ,OAAO,SAAS,SAAS,SACnC,aAAY,QAAQ,cAAc,QAAQ,KAAK;OACzC,aAAY,QAAQ,cAAc,EAAE,MAAM,OAAO,IAAI,CAAC;AAE7D,SAAM,QAAQ,OAAO;AACrB,SAAM,uBAAuB,KAAK;;EAEnC,YAAY;AACX,OAAI,UACH,QAAO,WAAW;;EAGpB,GAAG;EACH,CAAC"}
package/dist/manager.js CHANGED
@@ -65,7 +65,7 @@ addons.register(NAME, (api) => {
65
65
  if (event.importPath !== storyData.importPath) return;
66
66
  if (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) setSnapshotResults(event.results);
67
67
  })];
68
- api.emit(NAME, requestImageSnapshotResults(storyData));
68
+ if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData));
69
69
  return () => disposes.forEach((dispose) => {
70
70
  dispose();
71
71
  });
@@ -75,7 +75,7 @@ addons.register(NAME, (api) => {
75
75
  active,
76
76
  snapshotResults,
77
77
  onRefresh: () => {
78
- api.emit(NAME, requestImageSnapshotResults(storyData));
78
+ if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData));
79
79
  }
80
80
  });
81
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","names":["VisPanel"],"sources":["../src/components/vis_panel.tsx","../src/shared/contants.ts","../src/shared/events.ts","../src/manager.tsx"],"sourcesContent":["import { RefreshIcon } from '@storybook/icons'\nimport React, { memo } from 'react'\nimport { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'\nimport { styled } from 'storybook/theming'\nimport { SNAPSHOT_ROOT_DIR } from 'vitest-plugin-vis/client-api'\nimport type { ImageSnapshotResults } from '../shared/events.ts'\n\ninterface PanelProps {\n\tactive: boolean\n\tsnapshotResults: ImageSnapshotResults[]\n\tonRefresh: () => void\n}\n\nexport const VisPanel = memo(function VisPanel({ active, snapshotResults = [], onRefresh }: PanelProps) {\n\tconst groupedResults = snapshotResults.reduce(\n\t\t(acc, result) => {\n\t\t\tconst suiteName = result.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length + 1)\n\t\t\tconst key = `(${suiteName}) ${result.fileName}`\n\t\t\tacc[key] = [...(acc[key] ?? []), result]\n\t\t\treturn acc\n\t\t},\n\t\t{} as Record<string, ImageSnapshotResults[]>,\n\t)\n\treturn (\n\t\t<AddonPanel active={active}>\n\t\t\t{snapshotResults.length > 0 ? (\n\t\t\t\t<ScrollArea vertical>\n\t\t\t\t\t{Object.entries(groupedResults).map(([key, results]) => (\n\t\t\t\t\t\t<div key={key}>\n\t\t\t\t\t\t\t{results.some((result) => result.type === 'diff') ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<SnapshotRow failed>{key}</SnapshotRow>\n\t\t\t\t\t\t\t\t\t{results.map((result) => (\n\t\t\t\t\t\t\t\t\t\t<img key={result.filePath} src={`data:image/png;base64,${result.base64}`} alt={result.fileName} />\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<SnapshotRow>\n\t\t\t\t\t\t\t\t\t\t<span>{key}</span>\n\t\t\t\t\t\t\t\t\t\t<IconButton onClick={() => onRefresh()}>\n\t\t\t\t\t\t\t\t\t\t\t<RefreshIcon />\n\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t</SnapshotRow>\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tkey={results[0].filePath}\n\t\t\t\t\t\t\t\t\t\tsrc={`data:image/png;base64,${results[0].base64}`}\n\t\t\t\t\t\t\t\t\t\talt={results[0].fileName}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</ScrollArea>\n\t\t\t) : (\n\t\t\t\t<Placeholder>There is no snapshots for this story</Placeholder>\n\t\t\t)}\n\t\t</AddonPanel>\n\t)\n})\n\nconst SnapshotRow = styled.div<{ failed?: boolean }>(({ theme, failed }) => ({\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '0.5rem',\n\tpaddingBlock: '0.5rem',\n\tpaddingInline: '0.2rem',\n\tbackgroundColor: failed ? theme.background.negative : theme.background.positive,\n\tcolor: theme.barTextColor,\n}))\n","export const NAME = 'storybook-addon-vis'\nexport const VIS_PANEL_ID = `${NAME}/vis_panel`\n","export type VisEvent = ImageSnapshotResultsRequest | ImageSnapshotResultsResponse\n\nexport const IMAGE_SNAPSHOT_RESULTS_REQUEST = 'IMAGE_SNAPSHOT_RESULTS_REQUEST'\nexport const IMAGE_SNAPSHOT_RESULTS_RESPONSE = 'IMAGE_SNAPSHOT_RESULTS_RESPONSE'\n\nexport function requestImageSnapshotResults({ name, importPath }: { name: string; importPath: string }) {\n\treturn {\n\t\ttype: IMAGE_SNAPSHOT_RESULTS_REQUEST,\n\t\tname,\n\t\timportPath,\n\t}\n}\n\nexport type ImageSnapshotResultsRequest = {\n\ttype: typeof IMAGE_SNAPSHOT_RESULTS_REQUEST\n\tname: string\n\timportPath: string\n}\n\nexport type ImageSnapshotResultsResponse = {\n\ttype: typeof IMAGE_SNAPSHOT_RESULTS_RESPONSE\n\tname: string\n\timportPath: string\n\tresults: ImageSnapshotResults[]\n}\n\nexport type ImageSnapshotResults = {\n\tfilePath: string\n\tfileName: string\n\tsnapshotRootDir: string\n\ttype: 'baseline' | 'diff' | 'result'\n\tbase64: string\n}\n","import React, { useEffect, useState } from 'react'\nimport { addons, types } from 'storybook/manager-api'\nimport { VisPanel } from './components/vis_panel.tsx'\nimport { NAME, VIS_PANEL_ID } from './shared/contants.ts'\nimport {\n\tIMAGE_SNAPSHOT_RESULTS_RESPONSE,\n\trequestImageSnapshotResults,\n\ttype ImageSnapshotResults,\n\ttype VisEvent,\n} from './shared/events.ts'\n\n// Register the addon\naddons.register(NAME, (api) => {\n\t// Register the tool\n\tif ((globalThis as any).CONFIG_TYPE === 'DEVELOPMENT') {\n\t\taddons.add(VIS_PANEL_ID, {\n\t\t\ttype: types.PANEL,\n\t\t\ttitle: 'Vis',\n\t\t\tmatch: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n\t\t\trender({ active }) {\n\t\t\t\tconst [snapshotResults, setSnapshotResults] = useState<ImageSnapshotResults[]>([])\n\n\t\t\t\tconst storyData = api.getCurrentStoryData()\n\n\t\t\t\tuseEffect(() => {\n\t\t\t\t\tconst disposes = [\n\t\t\t\t\t\tapi.on(NAME, (event: VisEvent) => {\n\t\t\t\t\t\t\tif (event.name !== storyData.name) return\n\t\t\t\t\t\t\tif (event.importPath !== storyData.importPath) return\n\n\t\t\t\t\t\t\tif (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) {\n\t\t\t\t\t\t\t\tsetSnapshotResults(event.results)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t// api.on('UNIVERSAL_STORE:storybook/test', (event) => {\n\t\t\t\t\t\t// \tconsole.log('storybook/test', event)\n\t\t\t\t\t\t// }),\n\t\t\t\t\t]\n\t\t\t\t\tapi.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\t\treturn () =>\n\t\t\t\t\t\tdisposes.forEach((dispose) => {\n\t\t\t\t\t\t\tdispose()\n\t\t\t\t\t\t})\n\t\t\t\t}, [storyData])\n\n\t\t\t\tif (!active) return null\n\n\t\t\t\treturn (\n\t\t\t\t\t<VisPanel\n\t\t\t\t\t\tactive={active}\n\t\t\t\t\t\tsnapshotResults={snapshotResults}\n\t\t\t\t\t\tonRefresh={() => {\n\t\t\t\t\t\t\tapi.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\t},\n\t\t})\n\t}\n})\n"],"mappings":";;;;;;;;AAaA,MAAa,WAAW,KAAK,SAASA,WAAS,EAAE,QAAQ,kBAAkB,EAAE,EAAE,aAAyB;CACvG,MAAM,iBAAiB,gBAAgB,QACrC,KAAK,WAAW;EAEhB,MAAM,MAAM,IADM,OAAO,gBAAgB,MAAM,kBAAkB,SAAS,EAAE,CAClD,IAAI,OAAO;AACrC,MAAI,OAAO,CAAC,GAAI,IAAI,QAAQ,EAAE,EAAG,OAAO;AACxC,SAAO;IAER,EAAE,CACF;AACD,QACC,oCAAC,cAAmB,UAClB,gBAAgB,SAAS,IACzB,oCAAC,cAAW,kBACV,OAAO,QAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,aAC1C,oCAAC,SAAS,OACR,QAAQ,MAAM,WAAW,OAAO,SAAS,OAAO,GAChD,0DACC,oCAAC,eAAY,gBAAQ,IAAkB,EACtC,QAAQ,KAAK,WACb,oCAAC;EAAI,KAAK,OAAO;EAAU,KAAK,yBAAyB,OAAO;EAAU,KAAK,OAAO;GAAY,CACjG,CACA,GAEH,0DACC,oCAAC,mBACA,oCAAC,cAAM,IAAW,EAClB,oCAAC,cAAW,eAAe,WAAW,IACrC,oCAAC,kBAAc,CACH,CACA,EACd,oCAAC;EACA,KAAK,QAAQ,GAAG;EAChB,KAAK,yBAAyB,QAAQ,GAAG;EACzC,KAAK,QAAQ,GAAG;GACf,CACA,CAEC,CACL,CACU,GAEb,oCAAC,mBAAY,uCAAkD,CAEpD;EAEb;AAEF,MAAM,cAAc,OAAO,KAA2B,EAAE,OAAO,cAAc;CAC5E,SAAS;CACT,YAAY;CACZ,KAAK;CACL,cAAc;CACd,eAAe;CACf,iBAAiB,SAAS,MAAM,WAAW,WAAW,MAAM,WAAW;CACvE,OAAO,MAAM;CACb,EAAE;;;;ACrEH,MAAa,OAAO;AACpB,MAAa,eAAe,GAAG,KAAK;;;;ACCpC,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAE/C,SAAgB,4BAA4B,EAAE,MAAM,cAAoD;AACvG,QAAO;EACN,MAAM;EACN;EACA;EACA;;;;;ACEF,OAAO,SAAS,OAAO,QAAQ;AAE9B,KAAK,WAAmB,gBAAgB,cACvC,QAAO,IAAI,cAAc;EACxB,MAAM,MAAM;EACZ,OAAO;EACP,QAAQ,EAAE,OAAO,eAAe,CAAC,SAAS,aAAa;EACvD,OAAO,EAAE,UAAU;GAClB,MAAM,CAAC,iBAAiB,sBAAsB,SAAiC,EAAE,CAAC;GAElF,MAAM,YAAY,IAAI,qBAAqB;AAE3C,mBAAgB;IACf,MAAM,WAAW,CAChB,IAAI,GAAG,OAAO,UAAoB;AACjC,SAAI,MAAM,SAAS,UAAU,KAAM;AACnC,SAAI,MAAM,eAAe,UAAU,WAAY;AAE/C,SAAI,MAAM,SAAS,gCAClB,oBAAmB,MAAM,QAAQ;MAEjC,CAIF;AACD,QAAI,KAAK,MAAM,4BAA4B,UAAU,CAAC;AACtD,iBACC,SAAS,SAAS,YAAY;AAC7B,cAAS;MACR;MACD,CAAC,UAAU,CAAC;AAEf,OAAI,CAAC,OAAQ,QAAO;AAEpB,UACC,oCAAC;IACQ;IACS;IACjB,iBAAiB;AAChB,SAAI,KAAK,MAAM,4BAA4B,UAAU,CAAC;;KAEtD;;EAGJ,CAAC;EAEF"}
1
+ {"version":3,"file":"manager.js","names":["VisPanel"],"sources":["../src/components/vis_panel.tsx","../src/shared/contants.ts","../src/shared/events.ts","../src/manager.tsx"],"sourcesContent":["import { RefreshIcon } from '@storybook/icons'\nimport React, { memo } from 'react'\nimport { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'\nimport { styled } from 'storybook/theming'\nimport { SNAPSHOT_ROOT_DIR } from 'vitest-plugin-vis/client-api'\nimport type { ImageSnapshotResults } from '../shared/events.ts'\n\ninterface PanelProps {\n\tactive: boolean\n\tsnapshotResults: ImageSnapshotResults[]\n\tonRefresh: () => void\n}\n\nexport const VisPanel = memo(function VisPanel({ active, snapshotResults = [], onRefresh }: PanelProps) {\n\tconst groupedResults = snapshotResults.reduce(\n\t\t(acc, result) => {\n\t\t\tconst suiteName = result.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length + 1)\n\t\t\tconst key = `(${suiteName}) ${result.fileName}`\n\t\t\tacc[key] = [...(acc[key] ?? []), result]\n\t\t\treturn acc\n\t\t},\n\t\t{} as Record<string, ImageSnapshotResults[]>,\n\t)\n\treturn (\n\t\t<AddonPanel active={active}>\n\t\t\t{snapshotResults.length > 0 ? (\n\t\t\t\t<ScrollArea vertical>\n\t\t\t\t\t{Object.entries(groupedResults).map(([key, results]) => (\n\t\t\t\t\t\t<div key={key}>\n\t\t\t\t\t\t\t{results.some((result) => result.type === 'diff') ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<SnapshotRow failed>{key}</SnapshotRow>\n\t\t\t\t\t\t\t\t\t{results.map((result) => (\n\t\t\t\t\t\t\t\t\t\t<img key={result.filePath} src={`data:image/png;base64,${result.base64}`} alt={result.fileName} />\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<SnapshotRow>\n\t\t\t\t\t\t\t\t\t\t<span>{key}</span>\n\t\t\t\t\t\t\t\t\t\t<IconButton onClick={() => onRefresh()}>\n\t\t\t\t\t\t\t\t\t\t\t<RefreshIcon />\n\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t</SnapshotRow>\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tkey={results[0].filePath}\n\t\t\t\t\t\t\t\t\t\tsrc={`data:image/png;base64,${results[0].base64}`}\n\t\t\t\t\t\t\t\t\t\talt={results[0].fileName}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</ScrollArea>\n\t\t\t) : (\n\t\t\t\t<Placeholder>There is no snapshots for this story</Placeholder>\n\t\t\t)}\n\t\t</AddonPanel>\n\t)\n})\n\nconst SnapshotRow = styled.div<{ failed?: boolean }>(({ theme, failed }) => ({\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '0.5rem',\n\tpaddingBlock: '0.5rem',\n\tpaddingInline: '0.2rem',\n\tbackgroundColor: failed ? theme.background.negative : theme.background.positive,\n\tcolor: theme.barTextColor,\n}))\n","export const NAME = 'storybook-addon-vis'\nexport const VIS_PANEL_ID = `${NAME}/vis_panel`\n","export type VisEvent = ImageSnapshotResultsRequest | ImageSnapshotResultsResponse\n\nexport const IMAGE_SNAPSHOT_RESULTS_REQUEST = 'IMAGE_SNAPSHOT_RESULTS_REQUEST'\nexport const IMAGE_SNAPSHOT_RESULTS_RESPONSE = 'IMAGE_SNAPSHOT_RESULTS_RESPONSE'\n\nexport function requestImageSnapshotResults({ name, importPath }: { name: string; importPath: string }) {\n\treturn {\n\t\ttype: IMAGE_SNAPSHOT_RESULTS_REQUEST,\n\t\tname,\n\t\timportPath,\n\t}\n}\n\nexport type ImageSnapshotResultsRequest = {\n\ttype: typeof IMAGE_SNAPSHOT_RESULTS_REQUEST\n\tname: string\n\timportPath: string\n}\n\nexport type ImageSnapshotResultsResponse = {\n\ttype: typeof IMAGE_SNAPSHOT_RESULTS_RESPONSE\n\tname: string\n\timportPath: string\n\tresults: ImageSnapshotResults[]\n}\n\nexport type ImageSnapshotResults = {\n\tfilePath: string\n\tfileName: string\n\tsnapshotRootDir: string\n\ttype: 'baseline' | 'diff' | 'result'\n\tbase64: string\n}\n","import React, { useEffect, useState } from 'react'\nimport { addons, types } from 'storybook/manager-api'\nimport { VisPanel } from './components/vis_panel.tsx'\nimport { NAME, VIS_PANEL_ID } from './shared/contants.ts'\nimport {\n\tIMAGE_SNAPSHOT_RESULTS_RESPONSE,\n\trequestImageSnapshotResults,\n\ttype ImageSnapshotResults,\n\ttype VisEvent,\n} from './shared/events.ts'\n\n// Register the addon\naddons.register(NAME, (api) => {\n\t// Register the tool\n\tif ((globalThis as any).CONFIG_TYPE === 'DEVELOPMENT') {\n\t\taddons.add(VIS_PANEL_ID, {\n\t\t\ttype: types.PANEL,\n\t\t\ttitle: 'Vis',\n\t\t\tmatch: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n\t\t\trender({ active }) {\n\t\t\t\tconst [snapshotResults, setSnapshotResults] = useState<ImageSnapshotResults[]>([])\n\n\t\t\t\tconst storyData = api.getCurrentStoryData()\n\n\t\t\t\tuseEffect(() => {\n\t\t\t\t\tconst disposes = [\n\t\t\t\t\t\tapi.on(NAME, (event: VisEvent) => {\n\t\t\t\t\t\t\tif (event.name !== storyData.name) return\n\t\t\t\t\t\t\tif (event.importPath !== storyData.importPath) return\n\n\t\t\t\t\t\t\tif (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) {\n\t\t\t\t\t\t\t\tsetSnapshotResults(event.results)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t// api.on('UNIVERSAL_STORE:storybook/test', (event) => {\n\t\t\t\t\t\t// \tconsole.log('storybook/test', event)\n\t\t\t\t\t\t// }),\n\t\t\t\t\t]\n\t\t\t\t\tif (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\t\treturn () =>\n\t\t\t\t\t\tdisposes.forEach((dispose) => {\n\t\t\t\t\t\t\tdispose()\n\t\t\t\t\t\t})\n\t\t\t\t}, [storyData])\n\n\t\t\t\tif (!active) return null\n\n\t\t\t\treturn (\n\t\t\t\t\t<VisPanel\n\t\t\t\t\t\tactive={active}\n\t\t\t\t\t\tsnapshotResults={snapshotResults}\n\t\t\t\t\t\tonRefresh={() => {\n\t\t\t\t\t\t\tif (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\t},\n\t\t})\n\t}\n})\n"],"mappings":";;;;;;;;AAaA,MAAa,WAAW,KAAK,SAASA,WAAS,EAAE,QAAQ,kBAAkB,EAAE,EAAE,aAAyB;CACvG,MAAM,iBAAiB,gBAAgB,QACrC,KAAK,WAAW;EAEhB,MAAM,MAAM,IADM,OAAO,gBAAgB,MAAM,kBAAkB,SAAS,EAAE,CAClD,IAAI,OAAO;AACrC,MAAI,OAAO,CAAC,GAAI,IAAI,QAAQ,EAAE,EAAG,OAAO;AACxC,SAAO;IAER,EAAE,CACF;AACD,QACC,oCAAC,cAAmB,UAClB,gBAAgB,SAAS,IACzB,oCAAC,cAAW,kBACV,OAAO,QAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,aAC1C,oCAAC,SAAS,OACR,QAAQ,MAAM,WAAW,OAAO,SAAS,OAAO,GAChD,0DACC,oCAAC,eAAY,gBAAQ,IAAkB,EACtC,QAAQ,KAAK,WACb,oCAAC;EAAI,KAAK,OAAO;EAAU,KAAK,yBAAyB,OAAO;EAAU,KAAK,OAAO;GAAY,CACjG,CACA,GAEH,0DACC,oCAAC,mBACA,oCAAC,cAAM,IAAW,EAClB,oCAAC,cAAW,eAAe,WAAW,IACrC,oCAAC,kBAAc,CACH,CACA,EACd,oCAAC;EACA,KAAK,QAAQ,GAAG;EAChB,KAAK,yBAAyB,QAAQ,GAAG;EACzC,KAAK,QAAQ,GAAG;GACf,CACA,CAEC,CACL,CACU,GAEb,oCAAC,mBAAY,uCAAkD,CAEpD;EAEb;AAEF,MAAM,cAAc,OAAO,KAA2B,EAAE,OAAO,cAAc;CAC5E,SAAS;CACT,YAAY;CACZ,KAAK;CACL,cAAc;CACd,eAAe;CACf,iBAAiB,SAAS,MAAM,WAAW,WAAW,MAAM,WAAW;CACvE,OAAO,MAAM;CACb,EAAE;;;;ACrEH,MAAa,OAAO;AACpB,MAAa,eAAe,GAAG,KAAK;;;;ACCpC,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAE/C,SAAgB,4BAA4B,EAAE,MAAM,cAAoD;AACvG,QAAO;EACN,MAAM;EACN;EACA;EACA;;;;;ACEF,OAAO,SAAS,OAAO,QAAQ;AAE9B,KAAK,WAAmB,gBAAgB,cACvC,QAAO,IAAI,cAAc;EACxB,MAAM,MAAM;EACZ,OAAO;EACP,QAAQ,EAAE,OAAO,eAAe,CAAC,SAAS,aAAa;EACvD,OAAO,EAAE,UAAU;GAClB,MAAM,CAAC,iBAAiB,sBAAsB,SAAiC,EAAE,CAAC;GAElF,MAAM,YAAY,IAAI,qBAAqB;AAE3C,mBAAgB;IACf,MAAM,WAAW,CAChB,IAAI,GAAG,OAAO,UAAoB;AACjC,SAAI,MAAM,SAAS,UAAU,KAAM;AACnC,SAAI,MAAM,eAAe,UAAU,WAAY;AAE/C,SAAI,MAAM,SAAS,gCAClB,oBAAmB,MAAM,QAAQ;MAEjC,CAIF;AACD,QAAI,UAAW,KAAI,KAAK,MAAM,4BAA4B,UAAU,CAAC;AACrE,iBACC,SAAS,SAAS,YAAY;AAC7B,cAAS;MACR;MACD,CAAC,UAAU,CAAC;AAEf,OAAI,CAAC,OAAQ,QAAO;AAEpB,UACC,oCAAC;IACQ;IACS;IACjB,iBAAiB;AAChB,SAAI,UAAW,KAAI,KAAK,MAAM,4BAA4B,UAAU,CAAC;;KAErE;;EAGJ,CAAC;EAEF"}
@@ -1,6 +1,6 @@
1
1
  import { expect } from "storybook/test";
2
2
  import { matchImageSnapshotAction, matchPageImageSnapshotAction, success, toTaskId } from "vitest-plugin-vis/client-api";
3
- import { setAutoSnapshotOptions } from "vitest-plugin-vis";
3
+ import { setAutoSnapshotOptions as setAutoSnapshotOptions$1 } from "vitest-plugin-vis";
4
4
 
5
5
  //#region src/client/page/to_match_image_snapshot.ts
6
6
  function toMatchImageSnapshot$1(options) {
@@ -61,7 +61,7 @@ function isSnapshotEnabled(tags) {
61
61
  //#region src/preview/vis_annotation.ts
62
62
  const visAnnotations = { beforeEach(ctx) {
63
63
  const test = getCurrentTest();
64
- setAutoSnapshotOptions({
64
+ setAutoSnapshotOptions$1({
65
65
  enable: isSnapshotEnabled(ctx.tags),
66
66
  ...ctx.parameters?.snapshot,
67
67
  tags: ctx.tags,
@@ -71,4 +71,4 @@ const visAnnotations = { beforeEach(ctx) {
71
71
 
72
72
  //#endregion
73
73
  export { page as a, getCurrentTest as i, isSnapshotEnabled as n, commands as r, visAnnotations as t };
74
- //# sourceMappingURL=vis_annotation-Dpsgn_4P.js.map
74
+ //# sourceMappingURL=vis_annotation-DqZTkmEN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vis_annotation-Dpsgn_4P.js","names":["toMatchImageSnapshot","browserContext: Awaited<typeof import('vitest/browser')>","vitestSuite: Awaited<typeof import('vitest/suite')>"],"sources":["../src/client/page/to_match_image_snapshot.ts","../src/client/vitest_proxy.ts","../src/client/expect/to_match_image_snapshot.ts","../src/client/storybook/expect_extend.ts","../src/client/storybook/tags.ts","../src/preview/vis_annotation.ts"],"sourcesContent":["import {\n\ttype ComparisonMethod,\n\ttype ToMatchPageImageSnapshotOptions,\n\tmatchPageImageSnapshotAction,\n\ttoTaskId,\n} from 'vitest-plugin-vis/client-api'\nimport { commands, getCurrentTest } from '../vitest_proxy.ts'\n\nexport function toMatchImageSnapshot<M extends ComparisonMethod = 'pixel'>(\n\toptions?: ToMatchPageImageSnapshotOptions<M> | undefined,\n) {\n\tconst test = getCurrentTest()\n\n\t/* v8 ignore start: stub as success when not in a test (e.g. in a story) */\n\tif (!test) return Promise.resolve()\n\t/* v8 ignore end */\n\n\treturn matchPageImageSnapshotAction(commands, toTaskId(test), options)\n}\n","import type { SnapshotTestMeta } from 'vitest-plugin-vis/client-api'\nimport type { BrowserCommands, BrowserPage } from 'vitest/browser'\nimport { toMatchImageSnapshot } from './page/to_match_image_snapshot.ts'\n\nlet browserContext: Awaited<typeof import('vitest/browser')>\nlet vitestSuite: Awaited<typeof import('vitest/suite')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest/browser').then((m) => {\n\t\tm.page.extend({ toMatchImageSnapshot })\n\t\tbrowserContext = m\n\t})\n\timport('vitest/suite').then((m) => {\n\t\tvitestSuite = m\n\t})\n}\n\nexport const page = new Proxy<BrowserPage>({} as any, {\n\tget(_target, prop) {\n\t\tconst r = (browserContext?.page as any)?.[prop]\n\t\tif (prop === 'toMatchImageSnapshot' && r === undefined) {\n\t\t\treturn () => {}\n\t\t}\n\t\treturn r\n\t},\n})\n\nexport const commands = new Proxy<BrowserCommands>({} as any, {\n\tget(_target, prop) {\n\t\treturn (browserContext?.commands as any)?.[prop]\n\t},\n})\n\nexport const getCurrentTest = () =>\n\tvitestSuite?.getCurrentTest() as (ReturnType<typeof vitestSuite.getCurrentTest> & SnapshotTestMeta) | undefined\n","import type { AsyncExpectationResult } from '@vitest/expect'\nimport {\n\ttype ComparisonMethod,\n\ttype ToMatchImageSnapshotOptions,\n\tmatchImageSnapshotAction,\n\tsuccess,\n\ttoTaskId,\n} from 'vitest-plugin-vis/client-api'\nimport { commands, getCurrentTest } from '../vitest_proxy.ts'\n\nexport function toMatchImageSnapshot<M extends ComparisonMethod>(\n\t/**\n\t * The element or locator to take the snapshot of,\n\t * or the base64 value of the image to compare against.\n\t */\n\tsubject: any,\n\toptions?: ToMatchImageSnapshotOptions<M> | undefined,\n): AsyncExpectationResult {\n\tconst test = getCurrentTest()\n\n\t/* v8 ignore start: stub as success when not in a test (e.g. in a story) */\n\tif (!test) return Promise.resolve(success)\n\t/* v8 ignore end */\n\n\treturn matchImageSnapshotAction(commands, toTaskId(test), subject, options).then(() => success)\n}\n","import { expect } from 'storybook/test'\nimport { toMatchImageSnapshot } from '../expect/to_match_image_snapshot.ts'\n\nexpect.extend({ toMatchImageSnapshot })\n","export function isSnapshotEnabled(tags: string[]) {\n\tconst noSnapshotIndex = tags.lastIndexOf('!snapshot')\n\tconst snapshotIndex = tags.lastIndexOf('snapshot')\n\n\tif (noSnapshotIndex < 0 && snapshotIndex < 0) return false\n\n\treturn noSnapshotIndex < snapshotIndex\n}\n","import type { NamedOrDefaultProjectAnnotations } from 'storybook/internal/types'\nimport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nimport { isSnapshotEnabled } from '../client/storybook/tags.ts'\nimport { getCurrentTest } from '../client/vitest_proxy.ts'\n\nexport const visAnnotations = {\n\tbeforeEach(ctx) {\n\t\tconst test = getCurrentTest()\n\n\t\tsetAutoSnapshotOptions({\n\t\t\tenable: isSnapshotEnabled(ctx.tags),\n\t\t\t...ctx.parameters?.snapshot,\n\t\t\ttags: ctx.tags,\n\t\t\t...test?.meta.vis,\n\t\t})\n\t},\n} satisfies NamedOrDefaultProjectAnnotations<any>\n"],"mappings":";;;;;AAQA,SAAgBA,uBACf,SACC;CACD,MAAM,OAAO,gBAAgB;;AAG7B,KAAI,CAAC,KAAM,QAAO,QAAQ,SAAS;;AAGnC,QAAO,6BAA6B,UAAU,SAAS,KAAK,EAAE,QAAQ;;;;;ACbvE,IAAIC;AACJ,IAAIC;AAEJ,IAAK,WAAmB,oBAAoB;AAC3C,QAAO,kBAAkB,MAAM,MAAM;AACpC,IAAE,KAAK,OAAO,EAAE,8CAAsB,CAAC;AACvC,mBAAiB;GAChB;AACF,QAAO,gBAAgB,MAAM,MAAM;AAClC,gBAAc;GACb;;AAGH,MAAa,OAAO,IAAI,MAAmB,EAAE,EAAS,EACrD,IAAI,SAAS,MAAM;CAClB,MAAM,KAAK,gBAAgB,QAAe;AAC1C,KAAI,SAAS,0BAA0B,MAAM,OAC5C,cAAa;AAEd,QAAO;GAER,CAAC;AAEF,MAAa,WAAW,IAAI,MAAuB,EAAE,EAAS,EAC7D,IAAI,SAAS,MAAM;AAClB,SAAQ,gBAAgB,YAAmB;GAE5C,CAAC;AAEF,MAAa,uBACZ,aAAa,gBAAgB;;;;ACxB9B,SAAgB,qBAKf,SACA,SACyB;CACzB,MAAM,OAAO,gBAAgB;;AAG7B,KAAI,CAAC,KAAM,QAAO,QAAQ,QAAQ,QAAQ;;AAG1C,QAAO,yBAAyB,UAAU,SAAS,KAAK,EAAE,SAAS,QAAQ,CAAC,WAAW,QAAQ;;;;;ACrBhG,OAAO,OAAO,EAAE,sBAAsB,CAAC;;;;ACHvC,SAAgB,kBAAkB,MAAgB;CACjD,MAAM,kBAAkB,KAAK,YAAY,YAAY;CACrD,MAAM,gBAAgB,KAAK,YAAY,WAAW;AAElD,KAAI,kBAAkB,KAAK,gBAAgB,EAAG,QAAO;AAErD,QAAO,kBAAkB;;;;;ACD1B,MAAa,iBAAiB,EAC7B,WAAW,KAAK;CACf,MAAM,OAAO,gBAAgB;AAE7B,wBAAuB;EACtB,QAAQ,kBAAkB,IAAI,KAAK;EACnC,GAAG,IAAI,YAAY;EACnB,MAAM,IAAI;EACV,GAAG,MAAM,KAAK;EACd,CAAC;GAEH"}
1
+ {"version":3,"file":"vis_annotation-DqZTkmEN.js","names":["toMatchImageSnapshot","browserContext: Awaited<typeof import('vitest/browser')>","vitestSuite: Awaited<typeof import('vitest/suite')>"],"sources":["../src/client/page/to_match_image_snapshot.ts","../src/client/vitest_proxy.ts","../src/client/expect/to_match_image_snapshot.ts","../src/client/storybook/expect_extend.ts","../src/client/storybook/tags.ts","../src/preview/vis_annotation.ts"],"sourcesContent":["import {\n\ttype ComparisonMethod,\n\ttype ToMatchPageImageSnapshotOptions,\n\tmatchPageImageSnapshotAction,\n\ttoTaskId,\n} from 'vitest-plugin-vis/client-api'\nimport { commands, getCurrentTest } from '../vitest_proxy.ts'\n\nexport function toMatchImageSnapshot<M extends ComparisonMethod = 'pixel'>(\n\toptions?: ToMatchPageImageSnapshotOptions<M> | undefined,\n) {\n\tconst test = getCurrentTest()\n\n\t/* v8 ignore start: stub as success when not in a test (e.g. in a story) */\n\tif (!test) return Promise.resolve()\n\t/* v8 ignore end */\n\n\treturn matchPageImageSnapshotAction(commands, toTaskId(test), options)\n}\n","import type { SnapshotTestMeta } from 'vitest-plugin-vis/client-api'\nimport type { BrowserCommands, BrowserPage } from 'vitest/browser'\nimport { toMatchImageSnapshot } from './page/to_match_image_snapshot.ts'\n\nlet browserContext: Awaited<typeof import('vitest/browser')>\nlet vitestSuite: Awaited<typeof import('vitest/suite')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest/browser').then((m) => {\n\t\tm.page.extend({ toMatchImageSnapshot })\n\t\tbrowserContext = m\n\t})\n\timport('vitest/suite').then((m) => {\n\t\tvitestSuite = m\n\t})\n}\n\nexport const page = new Proxy<BrowserPage>({} as any, {\n\tget(_target, prop) {\n\t\tconst r = (browserContext?.page as any)?.[prop]\n\t\tif (prop === 'toMatchImageSnapshot' && r === undefined) {\n\t\t\treturn () => {}\n\t\t}\n\t\treturn r\n\t},\n})\n\nexport const commands = new Proxy<BrowserCommands>({} as any, {\n\tget(_target, prop) {\n\t\treturn (browserContext?.commands as any)?.[prop]\n\t},\n})\n\nexport const getCurrentTest = () =>\n\tvitestSuite?.getCurrentTest() as (ReturnType<typeof vitestSuite.getCurrentTest> & SnapshotTestMeta) | undefined\n","import type { AsyncExpectationResult } from '@vitest/expect'\nimport {\n\ttype ComparisonMethod,\n\ttype ToMatchImageSnapshotOptions,\n\tmatchImageSnapshotAction,\n\tsuccess,\n\ttoTaskId,\n} from 'vitest-plugin-vis/client-api'\nimport { commands, getCurrentTest } from '../vitest_proxy.ts'\n\nexport function toMatchImageSnapshot<M extends ComparisonMethod>(\n\t/**\n\t * The element or locator to take the snapshot of,\n\t * or the base64 value of the image to compare against.\n\t */\n\tsubject: any,\n\toptions?: ToMatchImageSnapshotOptions<M> | undefined,\n): AsyncExpectationResult {\n\tconst test = getCurrentTest()\n\n\t/* v8 ignore start: stub as success when not in a test (e.g. in a story) */\n\tif (!test) return Promise.resolve(success)\n\t/* v8 ignore end */\n\n\treturn matchImageSnapshotAction(commands, toTaskId(test), subject, options).then(() => success)\n}\n","import { expect } from 'storybook/test'\nimport { toMatchImageSnapshot } from '../expect/to_match_image_snapshot.ts'\n\nexpect.extend({ toMatchImageSnapshot })\n","export function isSnapshotEnabled(tags: string[]) {\n\tconst noSnapshotIndex = tags.lastIndexOf('!snapshot')\n\tconst snapshotIndex = tags.lastIndexOf('snapshot')\n\n\tif (noSnapshotIndex < 0 && snapshotIndex < 0) return false\n\n\treturn noSnapshotIndex < snapshotIndex\n}\n","import type { NamedOrDefaultProjectAnnotations } from 'storybook/internal/types'\nimport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nimport { isSnapshotEnabled } from '../client/storybook/tags.ts'\nimport { getCurrentTest } from '../client/vitest_proxy.ts'\n\nexport const visAnnotations = {\n\tbeforeEach(ctx) {\n\t\tconst test = getCurrentTest()\n\n\t\tsetAutoSnapshotOptions({\n\t\t\tenable: isSnapshotEnabled(ctx.tags),\n\t\t\t...ctx.parameters?.snapshot,\n\t\t\ttags: ctx.tags,\n\t\t\t...test?.meta.vis,\n\t\t})\n\t},\n} satisfies NamedOrDefaultProjectAnnotations<any>\n"],"mappings":";;;;;AAQA,SAAgBA,uBACf,SACC;CACD,MAAM,OAAO,gBAAgB;;AAG7B,KAAI,CAAC,KAAM,QAAO,QAAQ,SAAS;;AAGnC,QAAO,6BAA6B,UAAU,SAAS,KAAK,EAAE,QAAQ;;;;;ACbvE,IAAIC;AACJ,IAAIC;AAEJ,IAAK,WAAmB,oBAAoB;AAC3C,QAAO,kBAAkB,MAAM,MAAM;AACpC,IAAE,KAAK,OAAO,EAAE,8CAAsB,CAAC;AACvC,mBAAiB;GAChB;AACF,QAAO,gBAAgB,MAAM,MAAM;AAClC,gBAAc;GACb;;AAGH,MAAa,OAAO,IAAI,MAAmB,EAAE,EAAS,EACrD,IAAI,SAAS,MAAM;CAClB,MAAM,KAAK,gBAAgB,QAAe;AAC1C,KAAI,SAAS,0BAA0B,MAAM,OAC5C,cAAa;AAEd,QAAO;GAER,CAAC;AAEF,MAAa,WAAW,IAAI,MAAuB,EAAE,EAAS,EAC7D,IAAI,SAAS,MAAM;AAClB,SAAQ,gBAAgB,YAAmB;GAE5C,CAAC;AAEF,MAAa,uBACZ,aAAa,gBAAgB;;;;ACxB9B,SAAgB,qBAKf,SACA,SACyB;CACzB,MAAM,OAAO,gBAAgB;;AAG7B,KAAI,CAAC,KAAM,QAAO,QAAQ,QAAQ,QAAQ;;AAG1C,QAAO,yBAAyB,UAAU,SAAS,KAAK,EAAE,SAAS,QAAQ,CAAC,WAAW,QAAQ;;;;;ACrBhG,OAAO,OAAO,EAAE,sBAAsB,CAAC;;;;ACHvC,SAAgB,kBAAkB,MAAgB;CACjD,MAAM,kBAAkB,KAAK,YAAY,YAAY;CACrD,MAAM,gBAAgB,KAAK,YAAY,WAAW;AAElD,KAAI,kBAAkB,KAAK,gBAAgB,EAAG,QAAO;AAErD,QAAO,kBAAkB;;;;;ACD1B,MAAa,iBAAiB,EAC7B,WAAW,KAAK;CACf,MAAM,OAAO,gBAAgB;AAE7B,0BAAuB;EACtB,QAAQ,kBAAkB,IAAI,KAAK;EACnC,GAAG,IAAI,YAAY;EACnB,MAAM,IAAI;EACV,GAAG,MAAM,KAAK;EACd,CAAC;GAEH"}
@@ -1,7 +1,7 @@
1
1
  import "./global_matcher_augment-CYxLwns2.js";
2
+ import * as storybook_internal_csf1 from "storybook/internal/csf";
2
3
  import { setAutoSnapshotOptions } from "vitest-plugin-vis";
3
4
  import * as vitest_plugin_vis_setup0 from "vitest-plugin-vis/setup";
4
- import * as storybook_internal_csf1 from "storybook/internal/csf";
5
5
 
6
6
  //#region src/preview/vis_annotation.d.ts
7
7
  declare const visAnnotations: {
@@ -1 +1 @@
1
- {"version":3,"file":"vitest-setup.d.ts","names":[],"sources":["../src/preview/vis_annotation.ts","../src/vitest-setup.ts"],"sourcesContent":[],"mappings":";;;;;;cAKa;kBAWoC,uBAAA,CAAA,kBAAA,uBAAA,CAAA,IAAA;;;;cCRpC,KAA6C,wBAAA,CAA1C"}
1
+ {"version":3,"file":"vitest-setup.d.ts","names":[],"sources":["../src/preview/vis_annotation.ts","../src/vitest-setup.ts"],"sourcesContent":[],"mappings":";;;;;;cAKa;kBAWoC,uBAAA,CAAA,kBAAA,uBAAA,CAAA,IAAA;;;;cCTpC,KAA6C,wBAAA,CAA1C"}
@@ -1,4 +1,4 @@
1
- import { r as commands, t as visAnnotations } from "./vis_annotation-Dpsgn_4P.js";
1
+ import { r as commands, t as visAnnotations } from "./vis_annotation-DqZTkmEN.js";
2
2
  import { setAutoSnapshotOptions } from "vitest-plugin-vis";
3
3
  import { createVis } from "vitest-plugin-vis/setup";
4
4
 
@@ -1 +1 @@
1
- {"version":3,"file":"vitest-setup.js","names":[],"sources":["../src/vitest-setup.ts"],"sourcesContent":["// `storybook-addon-vis/vitest-setup` provides code needed in `vitest.setup.ts`.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport 'vitest-plugin-vis/setup' // for Vitest extends\nimport { createVis } from 'vitest-plugin-vis/setup'\nimport { commands } from './client/vitest_proxy.ts'\n\nexport const vis = createVis<{ tags: string[] }>(commands)\nexport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nexport { visAnnotations } from './preview/vis_annotation.ts'\n"],"mappings":";;;;;AAQA,MAAa,MAAM,UAA8B,SAAS"}
1
+ {"version":3,"file":"vitest-setup.js","names":[],"sources":["../src/vitest-setup.ts"],"sourcesContent":["// `storybook-addon-vis/vitest-setup` provides code needed in `vitest.setup.ts`.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport { createVis } from 'vitest-plugin-vis/setup'\nimport { commands } from './client/vitest_proxy.ts'\n\nexport const vis = createVis<{ tags: string[] }>(commands)\nexport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nexport { visAnnotations } from './preview/vis_annotation.ts'\n"],"mappings":";;;;;AAOA,MAAa,MAAM,UAA8B,SAAS"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-vis",
3
- "version": "3.0.1",
3
+ "version": "3.1.1",
4
4
  "description": "Storybook Vitest visual testing addon",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -67,16 +67,16 @@
67
67
  "memoize": "^10.1.0",
68
68
  "pathe": "^2.0.3",
69
69
  "type-plus": "8.0.0-beta.7",
70
- "vitest-plugin-vis": "^4.0.0"
70
+ "vitest-plugin-vis": "^4.1.0"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@repobuddy/storybook": "^2.1.2",
74
74
  "@storybook-community/storybook-dark-mode": "^7.0.3",
75
- "@storybook/addon-docs": "^10.1.2",
76
- "@storybook/addon-vitest": "^10.1.2",
77
- "@storybook/react-vite": "^10.1.2",
75
+ "@storybook/addon-docs": "^10.1.10",
76
+ "@storybook/addon-vitest": "^10.1.10",
77
+ "@storybook/react-vite": "^10.1.10",
78
78
  "@tailwindcss/cli": "^4.1.7",
79
- "@tailwindcss/vite": "^4.1.14",
79
+ "@tailwindcss/vite": "^4.1.17",
80
80
  "@testing-library/react": "^16.0.1",
81
81
  "@types/react": "^19.2.2",
82
82
  "@types/react-dom": "^19.2.1",
@@ -93,10 +93,10 @@
93
93
  "playwright": "latest",
94
94
  "react": "^19.0.0",
95
95
  "react-dom": "^19.0.0",
96
- "storybook": "^10.1.2",
96
+ "storybook": "^10.1.10",
97
97
  "storybook-addon-tag-badges": "^3.0.2",
98
98
  "tailwindcss": "^4.1.14",
99
- "tsdown": "^0.16.6",
99
+ "tsdown": "^0.18.0",
100
100
  "typescript": "^5.9.3",
101
101
  "vite": "^7.1.12",
102
102
  "vitest": "^4.0.9",
@@ -105,9 +105,9 @@
105
105
  "zx": "^8.0.0"
106
106
  },
107
107
  "peerDependencies": {
108
- "@storybook/addon-vitest": "^10.1.2",
108
+ "@storybook/addon-vitest": "^10.1.10",
109
109
  "@vitest/browser": "^4",
110
- "storybook": "^10.1.2",
110
+ "storybook": "^10.1.10",
111
111
  "vitest": "^4"
112
112
  },
113
113
  "publishConfig": {
package/src/index.ts CHANGED
@@ -2,7 +2,11 @@
2
2
  import './client/storybook/expect_extend.ts'
3
3
  import './shared/global_matcher_augment.ts'
4
4
 
5
- import { page } from './client/vitest_proxy.ts'
5
+ import { definePreviewAddon } from 'storybook/internal/csf'
6
+ import { expect } from 'storybook/test'
7
+ import type { SetupVisOptions } from 'vitest-plugin-vis'
8
+ import { autoSnapshotMatcher, setAutoSnapshotOptions } from 'vitest-plugin-vis/client-api'
9
+ import { commands, page } from './client/vitest_proxy.ts'
6
10
  import { visAnnotations } from './preview/vis_annotation.ts'
7
11
 
8
12
  export * from 'vitest-plugin-vis'
@@ -12,9 +16,29 @@ export * from './client/storybook/tags.ts'
12
16
 
13
17
  export { page }
14
18
 
15
- export default (options: { auto: boolean } = { auto: false }) => {
16
- return {
19
+ export default (options: SetupVisOptions = { auto: false }) => {
20
+ let matcher: ReturnType<typeof autoSnapshotMatcher>
21
+ let matcherFn: () => Promise<void>
22
+ return definePreviewAddon({
17
23
  tags: options.auto ? ['snapshot'] : [],
24
+ async beforeAll() {
25
+ matcher = autoSnapshotMatcher(commands, expect)
26
+ if (typeof options?.auto === 'function') {
27
+ matcherFn = matcher.createMatcher({
28
+ auto: options.auto,
29
+ })
30
+ } else if (typeof options?.auto === 'object') {
31
+ matcherFn = matcher.createMatcher(options.auto)
32
+ } else matcherFn = matcher.createMatcher({ async auto() {} })
33
+
34
+ await matcher.setup()
35
+ await setAutoSnapshotOptions(true)
36
+ },
37
+ afterEach() {
38
+ if (matcherFn) {
39
+ return matcherFn()
40
+ }
41
+ },
18
42
  ...visAnnotations,
19
- }
43
+ })
20
44
  }
package/src/manager.tsx CHANGED
@@ -36,7 +36,7 @@ addons.register(NAME, (api) => {
36
36
  // console.log('storybook/test', event)
37
37
  // }),
38
38
  ]
39
- api.emit(NAME, requestImageSnapshotResults(storyData))
39
+ if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))
40
40
  return () =>
41
41
  disposes.forEach((dispose) => {
42
42
  dispose()
@@ -50,7 +50,7 @@ addons.register(NAME, (api) => {
50
50
  active={active}
51
51
  snapshotResults={snapshotResults}
52
52
  onRefresh={() => {
53
- api.emit(NAME, requestImageSnapshotResults(storyData))
53
+ if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))
54
54
  }}
55
55
  />
56
56
  )
package/src/overview.mdx CHANGED
@@ -98,8 +98,8 @@ const annotations = setProjectAnnotations([
98
98
 
99
99
  beforeAll(annotations.beforeAll)
100
100
 
101
- // ADD THIS to setup automatic visual testing
102
- vis.setup({ auto: true })
101
+ // ADD THIS to enable visual testing
102
+ vis.setup()
103
103
  ```
104
104
 
105
105
  For [Storybook], you need to add the addon to your `.storybook/main.ts`:
@@ -141,6 +141,16 @@ export default config
141
141
 
142
142
  The `getAbsolutePath` function is a helper function typically added by [Storybook] automatically.
143
143
 
144
+ In `.storybook/preview.ts`, you can enable automatic snapshot by adding the `addonVis` addon and setting `auto` to `true`.
145
+ This will enable automatic snapshot taking at the end of each test.
146
+
147
+ ```ts
148
+ // .storybook/preview.ts
149
+ export default {
150
+ tags: ['snapshot'],
151
+ }
152
+ ```
153
+
144
154
  ### Ignore snapshot folders
145
155
 
146
156
  Since [storybook-addon-vis][storybook-addon-vis] will save snapshot on your file system,
@@ -180,6 +190,7 @@ Or use the triple-slash reference:
180
190
  "includes": [..., "types"]
181
191
  }
182
192
 
193
+ ```
183
194
 
184
195
  ```ts
185
196
  // types/storybook-addon-vis.d.ts
@@ -219,10 +230,27 @@ causes inconsistency and confuses both the editor and you.
219
230
  ### Basic Setup for CSF Next
220
231
 
221
232
  If you are writing your stories in CSF Next,
222
- You need to setup the visual testing also in `.storybook/preview.ts`.
223
-
233
+ You don't need to setup the visual testing in `vitest.setup.ts`.
234
+ Instead, you should setup the visual testing in `.storybook/preview.ts`.
224
235
 
225
236
  ```ts
237
+ // vitest.config.ts
238
+ // vitest.config.ts
239
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'
240
+ import { storybookVis } from 'storybook-addon-vis/vitest-plugin'
241
+ import { defineConfig } from 'vitest/config'
242
+
243
+ export default defineConfig({
244
+ plugins: [
245
+ storybookTest(),
246
+ storybookVis() // ADD THIS
247
+ ],
248
+ test: {
249
+ browser: { ... }, // your Vitest Browser Mode configuration
250
+ // setupFiles: ['./vitest.setup.ts'], // REMOVE THIS
251
+ }
252
+ })
253
+
226
254
  // .storybook/preview.ts
227
255
  import addonVis from 'storybook-addon-vis'
228
256
  import { definePreview } from '@storybook/your-framework/node'
@@ -2,7 +2,6 @@
2
2
  import './client/storybook/expect_extend.ts'
3
3
  import './shared/global_matcher_augment.ts'
4
4
 
5
- import 'vitest-plugin-vis/setup' // for Vitest extends
6
5
  import { createVis } from 'vitest-plugin-vis/setup'
7
6
  import { commands } from './client/vitest_proxy.ts'
8
7