@kaptures/storybook 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +27 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Danggeun Market Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @kaptures/storybook
|
|
2
|
+
|
|
3
|
+
Typed Storybook 10 lifecycle adapter for Kapture visual review.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun add --dev --exact @kaptures/storybook@0.0.3
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Register the adapter in `.storybook/preview.ts` with Storybook's CSF factory API.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { definePreview } from "@storybook/react-vite";
|
|
13
|
+
import kapture from "@kaptures/storybook";
|
|
14
|
+
|
|
15
|
+
export default definePreview({
|
|
16
|
+
addons: [kapture()],
|
|
17
|
+
parameters: {
|
|
18
|
+
kapture: {
|
|
19
|
+
requiredFonts: [{ text: "Visual review" }],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Named `kapture.viewports` are resolved against `parameters.viewport.options`. Kapture does not read Chromatic parameters or Storybook's private preview globals.
|
|
26
|
+
|
|
27
|
+
This preview adapter supports Storybook `^10.5.6` and requires Node.js 24 or newer for installation and Storybook builds.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface KaptureViewport {
|
|
3
|
+
name: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
}
|
|
7
|
+
type KaptureWaitForState = "attached" | "visible" | "hidden" | "detached";
|
|
8
|
+
interface KaptureWaitForOptions {
|
|
9
|
+
selector: string;
|
|
10
|
+
state?: KaptureWaitForState;
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
}
|
|
13
|
+
interface KaptureRequiredFont {
|
|
14
|
+
family?: string;
|
|
15
|
+
text: string;
|
|
16
|
+
style?: string;
|
|
17
|
+
weight?: string | number;
|
|
18
|
+
}
|
|
19
|
+
type KaptureAnimation = "disabled" | "start" | "end" | {
|
|
20
|
+
atMs: number;
|
|
21
|
+
};
|
|
22
|
+
interface KaptureStoryParameters {
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
viewports?: ReadonlyArray<string | KaptureViewport>;
|
|
25
|
+
/** Capture only the configured viewport instead of the full rendered page. */
|
|
26
|
+
cropToViewport?: boolean;
|
|
27
|
+
delayMs?: number;
|
|
28
|
+
waitFor?: string | KaptureWaitForOptions;
|
|
29
|
+
animation?: KaptureAnimation;
|
|
30
|
+
/** Hide matching nodes in the captured base/head images. */
|
|
31
|
+
mask?: readonly string[];
|
|
32
|
+
/** Keep matching nodes visible, but ignore their interior pixels during diff. */
|
|
33
|
+
ignoreSelectors?: readonly string[];
|
|
34
|
+
/** Fail capture when a required family or glyph set is unavailable. */
|
|
35
|
+
requiredFonts?: ReadonlyArray<string | KaptureRequiredFont>;
|
|
36
|
+
diff?: {
|
|
37
|
+
pixel?: number;
|
|
38
|
+
ratio?: number;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
interface KaptureAddonTypes {
|
|
42
|
+
parameters: {
|
|
43
|
+
kapture?: KaptureStoryParameters;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/storybook-10-compat.d.ts
|
|
48
|
+
declare function createKapturePreviewAddon(): import("storybook/internal/csf").PreviewAddon<KaptureAddonTypes>;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/index.d.ts
|
|
51
|
+
declare const kapture: typeof createKapturePreviewAddon;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { type KaptureAddonTypes, type KaptureAnimation, type KaptureRequiredFont, type KaptureStoryParameters, type KaptureViewport, type KaptureWaitForOptions, type KaptureWaitForState, createKapturePreviewAddon as default, kapture };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{PLAY_FUNCTION_THREW_EXCEPTION as e,STORY_FINISHED as t,STORY_RENDER_PHASE_CHANGED as n,UNHANDLED_ERRORS_WHILE_PLAYING as r}from"storybook/internal/core-events";import{definePreviewAddon as i}from"storybook/internal/csf";import{addons as a}from"storybook/preview-api";function o(e){let t=m(e,`parameters`);return w({disabled:v(t.disabled,`disabled`),viewports:s(t.viewports),cropToViewport:v(t.cropToViewport,`cropToViewport`),delayMs:x(t.delayMs,`delayMs`),waitFor:l(t.waitFor),animation:u(t.animation),mask:p(t.mask,`mask`),ignoreSelectors:p(t.ignoreSelectors,`ignoreSelectors`),requiredFonts:t.requiredFonts===void 0?void 0:h(t.requiredFonts,`requiredFonts`).map((e,t)=>d(e,`requiredFonts[${t}]`)),diff:f(t.diff)})}function s(e){if(e===void 0)return;let t=h(e,`viewports`);if(t.length===0)throw Error(`Kapture viewports must contain at least one viewport; use disabled: true to skip`);return t.map((e,t)=>c(e,`viewports[${t}]`))}function c(e,t){let n=m(e,t);return{name:g(n.name,`${t}.name`),width:S(n.width,`${t}.width`),height:S(n.height,`${t}.height`)}}function l(e){if(e===void 0)return;if(typeof e==`string`)return g(e,`waitFor`);let t=m(e,`waitFor`),n=t.state;if(n!==void 0&&n!==`attached`&&n!==`visible`&&n!==`hidden`&&n!==`detached`)throw Error(`Invalid Kapture waitFor state: ${String(n)}`);return w({selector:g(t.selector,`waitFor.selector`),state:n,timeoutMs:x(t.timeoutMs,`waitFor.timeoutMs`)})}function u(e){if(e!==void 0)return e===`disabled`||e===`start`||e===`end`?e:{atMs:b(m(e,`animation`).atMs,`animation.atMs`)}}function d(e,t){if(typeof e==`string`)return g(e,t);let n=m(e,t),r=n.weight;if(r!==void 0&&typeof r!=`string`&&typeof r!=`number`)throw Error(`${t}.weight must be a string or number`);return w({family:_(n.family,`${t}.family`),text:g(n.text,`${t}.text`),style:_(n.style,`${t}.style`),weight:r})}function f(e){if(e===void 0)return;let t=m(e,`diff`);return w({pixel:C(t.pixel,`diff.pixel`),ratio:C(t.ratio,`diff.ratio`)})}function p(e,t){if(e!==void 0)return h(e,t).map((e,n)=>g(e,`${t}[${n}]`))}function m(e,t){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Kapture ${t} must be an object`);return e}function h(e,t){if(!Array.isArray(e))throw Error(`Kapture ${t} must be an array`);return e}function g(e,t){if(typeof e!=`string`||!e.trim())throw Error(`Kapture ${t} must be a non-empty string`);return e}function _(e,t){return e===void 0?void 0:g(e,t)}function v(e,t){if(e!==void 0){if(typeof e!=`boolean`)throw Error(`Kapture ${t} must be a boolean`);return e}}function y(e,t){if(e!==void 0){if(typeof e!=`number`||!Number.isFinite(e))throw Error(`Kapture ${t} must be a finite number`);return e}}function b(e,t){let n=y(e,t);if(n===void 0||n<0)throw Error(`Kapture ${t} must be a non-negative number`);return n}function x(e,t){return e===void 0?void 0:b(e,t)}function S(e,t){let n=y(e,t);if(n===void 0||n<=0)throw Error(`Kapture ${t} must be positive`);return n}function C(e,t){if(e===void 0)return;let n=b(e,t);if(n>1)throw Error(`Kapture ${t} must be between 0 and 1`);return n}function w(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0))}var T=`0.0.3`;const E={set:e=>setTimeout(e,0),clear:e=>clearTimeout(e)};function D(e,t,n=E){let r=0,i,a,o=new Map,s=[],c=()=>{a!==void 0&&n.clear(a),a=void 0},l=()=>{if(!i)return;let{configurationError:n,storybookError:r,...a}=i;t({protocolVersion:1,adapterVersion:e,state:`rendering`,...a})},u=(e,t)=>{let n={storyId:e,generation:++r,renderId:t};return o.set(n.generation,n),i=n,n},d=(r,o)=>{c(),a=n.set(()=>{if(a=void 0,!(!i||i.generation!==r.generation)&&!(r.configurationError||r.storybookError)){if(o===`error`){t({protocolVersion:1,adapterVersion:e,state:`error`,storyId:r.storyId,generation:r.generation,renderId:r.renderId,error:{kind:`storybook`,message:`Storybook failed while rendering, playing, or finishing this story.`}});return}if(r.renderId===void 0||r.parameters===void 0){t({protocolVersion:1,adapterVersion:e,state:`error`,storyId:r.storyId,generation:r.generation,renderId:r.renderId,error:{kind:`configuration`,message:`Kapture did not receive resolved story parameters before Storybook finished.`}});return}t({protocolVersion:1,adapterVersion:e,state:`ready`,storyId:r.storyId,generation:r.generation,renderId:r.renderId,parameters:r.parameters})}})};return{boot(){c(),r=0,i=void 0,o.clear(),s.length=0,t({protocolVersion:1,adapterVersion:e,state:`booting`})},startStory(e,t){return c(),(!i||i.storyId!==e||i.parameters!==void 0||i.configurationError!==void 0||i.storybookError!==void 0)&&u(e),i.parameters=t,l(),i.generation},completeStory(e,t){let n=o.get(t);!n||n.storyId!==e||n.configurationError||n.storybookError||s.includes(t)||s.push(t)},failConfiguration(n,r){c(),(!i||i.storyId!==n||i.parameters!==void 0)&&u(n),i.configurationError=r.message,t({protocolVersion:1,adapterVersion:e,state:`error`,storyId:n,generation:i.generation,renderId:i.renderId,error:{kind:`configuration`,message:r.message}})},failStorybook(n){c(),i&&(i.storybookError=n.message,t({protocolVersion:1,adapterVersion:e,state:`error`,storyId:i.storyId,generation:i.generation,renderId:i.renderId,error:{kind:`storybook`,message:n.message}}))},handlePhase(e){if(e.newPhase===`loading`){c(),u(e.storyId,e.renderId),l();return}i?.storyId===e.storyId&&(i.renderId=e.renderId)},handleFinished(e){let t=s.findIndex(t=>o.get(t)?.storyId===e.storyId),n=t<0?void 0:s.splice(t,1)[0],r=n===void 0?i:o.get(n);!r||r.storyId!==e.storyId||r.configurationError||r.storybookError||(e.status!==`success`||n!==void 0)&&d(r,e.status)},dispose(){c(),i=void 0,o.clear(),s.length=0}}}function O(e,t){try{let e=M(t,`Storybook parameters`),n=e.kapture===void 0?{}:M(e.kapture,`parameters.kapture`),r=n.viewports?.map((t,n)=>typeof t==`string`?k(t,e.viewport):A(t,n));return o({disabled:n.disabled,viewports:r,cropToViewport:n.cropToViewport,delayMs:n.delayMs,waitFor:n.waitFor,animation:n.animation,mask:n.mask,ignoreSelectors:n.ignoreSelectors,requiredFonts:n.requiredFonts,diff:n.diff})}catch(t){let n=t instanceof Error?t.message:String(t);throw Error(`Kapture story ${e}: ${n}`,{cause:t})}}function k(e,t){if(!e.trim())throw Error(`viewports entries must not be empty`);let n=M(M(M(t,`parameters.viewport`).options,`parameters.viewport.options`)[e],`viewport option ${e}`);return{name:e,width:j(n.styles?.width,`${e}.styles.width`),height:j(n.styles?.height,`${e}.styles.height`)}}function A(e,t){if(typeof e!=`object`||!e)throw Error(`viewports[${t}] must be a viewport name or object`);return{name:e.name,width:e.width,height:e.height}}function j(e,t){if(typeof e!=`string`)throw Error(`${t} must be an exact pixel dimension`);let n=/^(\d+)px$/.exec(e.trim());if(!n?.[1])throw Error(`${t} must use an exact pixel dimension such as 360px`);let r=Number(n[1]);if(r<=0)throw Error(`${t} must be positive`);return r}function M(e,t){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`${t} must be an object`);return e}function N(e){globalThis.__KAPTURE_STORYBOOK__=e}function P(){let o=D(T,N),s=new WeakMap;return i({beforeAll(){o.boot();let i=a.getChannel(),s=e=>o.handlePhase(e),c=e=>o.handleFinished(e),l=e=>o.failStorybook(F(e));return i.on(n,s),i.on(t,c),i.on(e,l),i.on(r,l),()=>{i.off(n,s),i.off(t,c),i.off(e,l),i.off(r,l),o.dispose()}},beforeEach(e){try{let t=o.startStory(e.id,O(e.id,e.parameters));s.set(e,t)}catch(t){let n=t instanceof Error?t:Error(String(t));throw o.failConfiguration(e.id,n),n}},afterEach(e){let t=s.get(e);t!==void 0&&o.completeStory(e.id,t)}})}function F(e){let t=Array.isArray(e)?e[0]:e;if(typeof t==`object`&&t&&`message`in t){let e=t.message;if(typeof e==`string`&&e.trim())return Error(`Storybook play function failed: ${e}`)}return Error(`Storybook play function failed.`)}const I=P;var L=P;export{L as default,I as kapture};
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kaptures/storybook",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Typed Storybook lifecycle adapter for Kapture visual review",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Danggeun Market Inc.",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/karrot-emu/kapture.git",
|
|
11
|
+
"directory": "packages/storybook"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=24"
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsdown",
|
|
35
|
+
"prepack": "bun run build"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"storybook": "^10.5.6"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@kapture/protocol": "workspace:*",
|
|
42
|
+
"storybook": "10.5.6"
|
|
43
|
+
}
|
|
44
|
+
}
|