storybook-addon-vis 1.0.0 → 1.0.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/manager.js CHANGED
@@ -1,2 +1,2 @@
1
- import {memo,useState,useEffect}from'react';import {addons,types}from'storybook/internal/manager-api';import {AddonPanel,ScrollArea,Placeholder}from'storybook/internal/components';import {styled}from'storybook/internal/theming';import {SNAPSHOT_ROOT_DIR}from'vitest-plugin-vis/client-api';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var g=memo(function({active:a,snapshotResults:r=[]}){let p=r.reduce((t,e)=>{let S=`(${e.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length+1)}) ${e.fileName}`;return t[S]=[...t[S]??[],e],t},{});return jsx(AddonPanel,{active:a,children:r.length>0?jsx(ScrollArea,{vertical:true,children:Object.entries(p).map(([t,e])=>jsx("div",{children:e.some(s=>s.type==="diff")?jsxs(Fragment,{children:[jsx(m,{failed:true,children:t}),e.map(s=>jsx("img",{src:`data:image/png;base64,${s.base64}`,alt:s.fileName},s.filePath))]}):jsxs(Fragment,{children:[jsx(m,{children:t}),jsx("img",{src:`data:image/png;base64,${e[0].base64}`,alt:e[0].fileName},e[0].filePath)]})},t))}):jsx(Placeholder,{children:"There is no snapshots for this story"})})}),m=styled.div(({theme:o,failed:a})=>({paddingBlock:"0.5rem",paddingInline:"0.2rem",backgroundColor:a?o.background.negative:o.background.positive,color:o.barTextColor}));var i="storybook-addon-vis",E=`${i}/vis_panel`;var A="IMAGE_SNAPSHOT_RESULTS_REQUEST",h="IMAGE_SNAPSHOT_RESULTS_RESPONSE";function u({name:o,importPath:a}){return {type:A,name:o,importPath:a}}addons.register(i,o=>{addons.add(E,{type:types.PANEL,title:"Vis",match:({tabId:a,viewMode:r})=>!a&&r==="story",render({active:a}){if(!a)return null;let[r,p]=useState([]),t=o.getCurrentStoryData();return useEffect(()=>{let e=o.on(i,s=>{s.name===t.name&&s.importPath===t.importPath&&s.type===h&&p(s.results);});return o.emit(i,u(t)),e},[t]),jsx(g,{active:a,snapshotResults:r})}});});//# sourceMappingURL=manager.js.map
1
+ import {memo,useState,useEffect}from'react';import {addons,types}from'storybook/internal/manager-api';import {RefreshIcon}from'@storybook/icons';import {AddonPanel,ScrollArea,IconButton,Placeholder}from'storybook/internal/components';import {styled}from'storybook/internal/theming';import {SNAPSHOT_ROOT_DIR}from'vitest-plugin-vis/client-api';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var h=memo(function({active:s,snapshotResults:r=[],onRefresh:S}){let a=r.reduce((n,e)=>{let R=`(${e.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length+1)}) ${e.fileName}`;return n[R]=[...n[R]??[],e],n},{});return jsx(AddonPanel,{active:s,children:r.length>0?jsx(ScrollArea,{vertical:true,children:Object.entries(a).map(([n,e])=>jsx("div",{children:e.some(i=>i.type==="diff")?jsxs(Fragment,{children:[jsx(g,{failed:true,children:n}),e.map(i=>jsx("img",{src:`data:image/png;base64,${i.base64}`,alt:i.fileName},i.filePath))]}):jsxs(Fragment,{children:[jsxs(g,{children:[jsx("span",{children:n}),jsx(IconButton,{onClick:()=>S(),children:jsx(RefreshIcon,{})})]}),jsx("img",{src:`data:image/png;base64,${e[0].base64}`,alt:e[0].fileName},e[0].filePath)]})},n))}):jsx(Placeholder,{children:"There is no snapshots for this story"})})}),g=styled.div(({theme:t,failed:s})=>({display:"flex",alignItems:"center",gap:"0.5rem",paddingBlock:"0.5rem",paddingInline:"0.2rem",backgroundColor:s?t.background.negative:t.background.positive,color:t.barTextColor}));var p="storybook-addon-vis",d=`${p}/vis_panel`;var O="IMAGE_SNAPSHOT_RESULTS_REQUEST",u="IMAGE_SNAPSHOT_RESULTS_RESPONSE";function l({name:t,importPath:s}){return {type:O,name:t,importPath:s}}addons.register(p,t=>{addons.add(d,{type:types.PANEL,title:"Vis",match:({tabId:s,viewMode:r})=>!s&&r==="story",render({active:s}){if(!s)return null;let[r,S]=useState([]),a=t.getCurrentStoryData();return useEffect(()=>{let n=t.on(p,e=>{e.name===a.name&&e.importPath===a.importPath&&e.type===u&&S(e.results);});return t.emit(p,l(a)),n},[a]),jsx(h,{active:s,snapshotResults:r,onRefresh:()=>{t.emit(p,l(a));}})}});});//# sourceMappingURL=manager.js.map
2
2
  //# sourceMappingURL=manager.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/vis_panel.tsx","../src/shared/contants.ts","../src/shared/events.ts","../src/manager.tsx"],"names":["VisPanel","memo","active","snapshotResults","groupedResults","acc","result","key","SNAPSHOT_ROOT_DIR","jsx","AddonPanel","ScrollArea","results","jsxs","Fragment","SnapshotRow","Placeholder","styled","theme","failed","NAME","VIS_PANEL_ID","IMAGE_SNAPSHOT_RESULTS_REQUEST","IMAGE_SNAPSHOT_RESULTS_RESPONSE","requestImageSnapshotResults","name","importPath","addons","api","types","tabId","viewMode","setSnapshotResults","useState","storyData","useEffect","dispose","event"],"mappings":"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","file":"manager.js","sourcesContent":["import { memo } from 'react'\nimport { AddonPanel, Placeholder, ScrollArea } from 'storybook/internal/components'\nimport { styled } from 'storybook/internal/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}\n\nexport const VisPanel = memo(function VisResultsPanel({ active, snapshotResults = [] }: 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>{key}</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\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 { useEffect, useState } from 'react'\nimport { addons, types } from 'storybook/internal/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\taddons.add(VIS_PANEL_ID, {\n\t\ttype: types.PANEL,\n\t\ttitle: 'Vis',\n\t\tmatch: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n\t\trender({ active }) {\n\t\t\tif (!active) return null\n\t\t\tconst [snapshotResults, setSnapshotResults] = useState<ImageSnapshotResults[]>([])\n\n\t\t\tconst storyData = api.getCurrentStoryData()\n\n\t\t\tuseEffect(() => {\n\t\t\t\tconst dispose = api.on(NAME, (event: VisEvent) => {\n\t\t\t\t\tif (event.name !== storyData.name) return\n\t\t\t\t\tif (event.importPath !== storyData.importPath) return\n\n\t\t\t\t\tif (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) {\n\t\t\t\t\t\tsetSnapshotResults(event.results)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\tapi.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\treturn dispose\n\t\t\t}, [storyData])\n\t\t\treturn <VisPanel active={active} snapshotResults={snapshotResults} />\n\t\t},\n\t})\n})\n"]}
1
+ {"version":3,"sources":["../src/components/vis_panel.tsx","../src/shared/contants.ts","../src/shared/events.ts","../src/manager.tsx"],"names":["VisPanel","memo","active","snapshotResults","onRefresh","groupedResults","acc","result","key","SNAPSHOT_ROOT_DIR","jsx","AddonPanel","ScrollArea","results","jsxs","Fragment","SnapshotRow","IconButton","RefreshIcon","Placeholder","styled","theme","failed","NAME","VIS_PANEL_ID","IMAGE_SNAPSHOT_RESULTS_REQUEST","IMAGE_SNAPSHOT_RESULTS_RESPONSE","requestImageSnapshotResults","name","importPath","addons","api","types","tabId","viewMode","setSnapshotResults","useState","storyData","useEffect","dispose","event"],"mappings":"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","file":"manager.js","sourcesContent":["import { RefreshIcon } from '@storybook/icons'\nimport { memo } from 'react'\nimport { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'\nimport { styled } from 'storybook/internal/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 { useEffect, useState } from 'react'\nimport { addons, types } from 'storybook/internal/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\taddons.add(VIS_PANEL_ID, {\n\t\ttype: types.PANEL,\n\t\ttitle: 'Vis',\n\t\tmatch: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n\t\trender({ active }) {\n\t\t\tif (!active) return null\n\t\t\tconst [snapshotResults, setSnapshotResults] = useState<ImageSnapshotResults[]>([])\n\n\t\t\tconst storyData = api.getCurrentStoryData()\n\n\t\t\tuseEffect(() => {\n\t\t\t\tconst dispose = api.on(NAME, (event: VisEvent) => {\n\t\t\t\t\tif (event.name !== storyData.name) return\n\t\t\t\t\tif (event.importPath !== storyData.importPath) return\n\n\t\t\t\t\tif (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) {\n\t\t\t\t\t\tsetSnapshotResults(event.results)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\tapi.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\treturn dispose\n\t\t\t}, [storyData])\n\t\t\treturn (\n\t\t\t\t<VisPanel\n\t\t\t\t\tactive={active}\n\t\t\t\t\tsnapshotResults={snapshotResults}\n\t\t\t\t\tonRefresh={() => {\n\t\t\t\t\t\tapi.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t)\n\t\t},\n\t})\n})\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-vis",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Storybook Vitest visual testing addon",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -61,15 +61,16 @@
61
61
  "!**/*.{spec,test,unit,accept,integrate,system,perf,stress,stories,study}.*"
62
62
  ],
63
63
  "dependencies": {
64
+ "@storybook/icons": "^1.4.0",
64
65
  "glob": "^11.0.2",
65
66
  "is-ci": "^4.1.0",
66
67
  "memoize": "^10.1.0",
67
68
  "pathe": "^2.0.3",
68
69
  "type-plus": "8.0.0-beta.7",
69
- "vitest-plugin-vis": "^3.0.0"
70
+ "vitest-plugin-vis": "^3.0.1"
70
71
  },
71
72
  "devDependencies": {
72
- "@repobuddy/storybook": "^0.12.0",
73
+ "@repobuddy/storybook": "^0.13.0",
73
74
  "@storybook/addon-essentials": "^8.6.14",
74
75
  "@storybook/addon-links": "^8.6.14",
75
76
  "@storybook/addon-storysource": "^8.6.14",
@@ -145,7 +146,7 @@
145
146
  },
146
147
  "scripts": {
147
148
  "build": "tsup --tsconfig tsconfig.tsup.json",
148
- "build:sb": "storybook build",
149
+ "build:sb": "NODE_ENV=production storybook build",
149
150
  "clean": "rimraf coverage dist esm --glob *.tsbuildinfo vitest.*.timestamp*",
150
151
  "clean:vis:local": "rimraf __vis__/local",
151
152
  "cov": "vitest run --coverage",
@@ -1,5 +1,6 @@
1
+ import { RefreshIcon } from '@storybook/icons'
1
2
  import { memo } from 'react'
2
- import { AddonPanel, Placeholder, ScrollArea } from 'storybook/internal/components'
3
+ import { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'
3
4
  import { styled } from 'storybook/internal/theming'
4
5
  import { SNAPSHOT_ROOT_DIR } from 'vitest-plugin-vis/client-api'
5
6
  import type { ImageSnapshotResults } from '../shared/events.ts'
@@ -7,9 +8,10 @@ import type { ImageSnapshotResults } from '../shared/events.ts'
7
8
  interface PanelProps {
8
9
  active: boolean
9
10
  snapshotResults: ImageSnapshotResults[]
11
+ onRefresh: () => void
10
12
  }
11
13
 
12
- export const VisPanel = memo(function VisResultsPanel({ active, snapshotResults = [] }: PanelProps) {
14
+ export const VisPanel = memo(function VisPanel({ active, snapshotResults = [], onRefresh }: PanelProps) {
13
15
  const groupedResults = snapshotResults.reduce(
14
16
  (acc, result) => {
15
17
  const suiteName = result.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length + 1)
@@ -34,7 +36,12 @@ export const VisPanel = memo(function VisResultsPanel({ active, snapshotResults
34
36
  </>
35
37
  ) : (
36
38
  <>
37
- <SnapshotRow>{key}</SnapshotRow>
39
+ <SnapshotRow>
40
+ <span>{key}</span>
41
+ <IconButton onClick={() => onRefresh()}>
42
+ <RefreshIcon />
43
+ </IconButton>
44
+ </SnapshotRow>
38
45
  <img
39
46
  key={results[0].filePath}
40
47
  src={`data:image/png;base64,${results[0].base64}`}
@@ -53,6 +60,9 @@ export const VisPanel = memo(function VisResultsPanel({ active, snapshotResults
53
60
  })
54
61
 
55
62
  const SnapshotRow = styled.div<{ failed?: boolean }>(({ theme, failed }) => ({
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ gap: '0.5rem',
56
66
  paddingBlock: '0.5rem',
57
67
  paddingInline: '0.2rem',
58
68
  backgroundColor: failed ? theme.background.negative : theme.background.positive,
package/src/manager.tsx CHANGED
@@ -34,7 +34,15 @@ addons.register(NAME, (api) => {
34
34
  api.emit(NAME, requestImageSnapshotResults(storyData))
35
35
  return dispose
36
36
  }, [storyData])
37
- return <VisPanel active={active} snapshotResults={snapshotResults} />
37
+ return (
38
+ <VisPanel
39
+ active={active}
40
+ snapshotResults={snapshotResults}
41
+ onRefresh={() => {
42
+ api.emit(NAME, requestImageSnapshotResults(storyData))
43
+ }}
44
+ />
45
+ )
38
46
  },
39
47
  })
40
48
  })