@canonical/storybook-addon-relay 0.29.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/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # @canonical/storybook-addon-relay
2
+
3
+ Mock Relay environment integration for Storybook. This addon lets React stories that use Relay hooks (`useLazyLoadQuery`, `useFragment`, `usePaginationFragment`, ...) render against a `relay-test-utils` mock environment, so components with GraphQL data requirements work in Storybook without a running GraphQL server.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add -D @canonical/storybook-addon-relay
9
+ ```
10
+
11
+ `react-relay` and `relay-runtime` (18.x) are peer dependencies — your app already has them if it uses Relay.
12
+
13
+ ## Setup
14
+
15
+ Register the addon in your `.storybook/main.ts`:
16
+
17
+ ```typescript
18
+ const config: StorybookConfig = {
19
+ addons: [
20
+ "@canonical/storybook-addon-relay",
21
+ ],
22
+ };
23
+
24
+ export default config;
25
+ ```
26
+
27
+ If your Storybook config is built with `@canonical/storybook-config`, pass it through `extraAddons`:
28
+
29
+ ```typescript
30
+ import { createConfig } from "@canonical/storybook-config";
31
+
32
+ export default createConfig("react", {
33
+ extraAddons: ["@canonical/storybook-addon-relay"],
34
+ });
35
+ ```
36
+
37
+ Registering the addon does two things:
38
+
39
+ - its `preview` entry adds the `withRelayEnvironment` decorator globally;
40
+ - its `preset` entry adds `relay-test-utils` (a CJS-only package) to Vite's `optimizeDeps.include`, so its named exports resolve in the browser ESM context.
41
+
42
+ ## Usage in Stories
43
+
44
+ Declare a `relay` key in your story parameters. The decorator wraps the story in a `RelayEnvironmentProvider` carrying a fresh mock environment, and every GraphQL operation the story issues resolves automatically with data from `MockPayloadGenerator`:
45
+
46
+ ```typescript
47
+ import type { Meta, StoryObj } from "@storybook/react-vite";
48
+ import type { RelayParameters } from "@canonical/storybook-addon-relay";
49
+ import { UserProfile } from "./UserProfile.js";
50
+
51
+ const meta: Meta<typeof UserProfile> = {
52
+ title: "Components/UserProfile",
53
+ component: UserProfile,
54
+ };
55
+
56
+ export default meta;
57
+ type Story = StoryObj<typeof meta>;
58
+
59
+ export const Default: Story = {
60
+ parameters: {
61
+ relay: {
62
+ mockResolvers: {
63
+ User: () => ({
64
+ name: "Ada Lovelace",
65
+ email: "ada@example.com",
66
+ }),
67
+ },
68
+ } satisfies RelayParameters,
69
+ },
70
+ };
71
+ ```
72
+
73
+ Stories without a `relay` parameter pass through unchanged — the decorator is a no-op for them.
74
+
75
+ ### Full payload control
76
+
77
+ For error states or hand-crafted payloads, provide `generateFunction` — it replaces `MockPayloadGenerator.generate()` entirely:
78
+
79
+ ```typescript
80
+ export const CustomPayload: Story = {
81
+ parameters: {
82
+ relay: {
83
+ generateFunction: (operation, mockResolvers) => ({
84
+ data: { user: { id: "1", name: "Custom Name" } },
85
+ }),
86
+ } satisfies RelayParameters,
87
+ },
88
+ };
89
+ ```
90
+
91
+ ## API
92
+
93
+ ### `parameters.relay: RelayParameters`
94
+
95
+ | Property | Type | Required | Description |
96
+ |----------|------|----------|-------------|
97
+ | `mockResolvers` | `MockResolvers` | | Mock resolvers passed to `MockPayloadGenerator.generate()`. Keys are GraphQL type names, values are factories returning field values. Fields without a resolver receive deterministic placeholder values |
98
+ | `generateFunction` | `(operation, mockResolvers?) => GraphQLSingularResponse` | | Full override for payload generation. When provided, `MockPayloadGenerator.generate()` is not called |
99
+
100
+ ### `withRelayEnvironment`
101
+
102
+ The decorator itself, exported from the package root for manual composition (e.g. applying it to a single story file instead of globally). It is registered globally by the addon's `preview` entry, so most consumers never import it.
103
+
104
+ ## How operations resolve
105
+
106
+ React components issue their Relay requests while rendering — after the decorator has returned — so the decorator queues an operation resolver on the mock environment rather than resolving up front. `relay-test-utils` consumes a queued resolver after a single operation, so the resolver re-arms itself after each one: initial queries, refetches, pagination, and mutations (including those triggered from play functions) all resolve with the same story configuration, no matter how many operations the story issues.
107
+
108
+ The mock environment is created once per story mount. Re-renders (e.g. changing args via controls) keep the environment and its store; switching stories or pressing the remount toolbar button starts from a fresh environment.
109
+
110
+ The environment is not exposed to the story context: operations resolve automatically, so stories and play functions do not need to drive the mock network by hand, and the `parameters.relay` contract stays minimal.
111
+
112
+ ## Peer Dependencies
113
+
114
+ | Package | Version |
115
+ |---------|---------|
116
+ | `react` | ^18.0.0 \|\| ^19.0.0 |
117
+ | `react-dom` | ^18.0.0 \|\| ^19.0.0 |
118
+ | `react-relay` | >=18.0.0 <19.0.0 |
119
+ | `relay-runtime` | >=18.0.0 <19.0.0 |
120
+ | `storybook` | ^10.3.1 |
121
+
122
+ ## Troubleshooting
123
+
124
+ ### `does not provide an export named 'createMockEnvironment'`
125
+
126
+ `relay-test-utils` and `relay-runtime` are CJS-only. The addon's `preset` adds `relay-test-utils` to `optimizeDeps.include` automatically — make sure the addon is registered in `.storybook/main.ts` (not only imported in `preview.ts`), otherwise the preset does not run.
127
+
128
+ ### A refetch or mutation never resolves
129
+
130
+ Operations only resolve for stories that declare a `relay` parameter (even an empty object enables the mock environment):
131
+
132
+ ```typescript
133
+ export const Default: Story = {
134
+ parameters: {
135
+ relay: {},
136
+ },
137
+ };
138
+ ```
139
+
140
+ ### Deterministic data
141
+
142
+ `MockPayloadGenerator` generates placeholder values for any field not covered by `mockResolvers`. If a story must render exact values (e.g. for visual regression tests), resolve every displayed field in `mockResolvers`, or use `generateFunction` for full control.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Key under which stories declare their Relay configuration in Storybook
3
+ * `parameters` (i.e. `parameters.relay`).
4
+ */
5
+ export const PARAM_KEY = "relay";
6
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @canonical/storybook-addon-relay — renders React stories that use Relay
3
+ * hooks against a `relay-test-utils` mock environment, configured per story
4
+ * via `parameters.relay` (`mockResolvers`, `generateFunction`).
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export * from "./lib/index.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { withRelayEnvironment } from "./withRelayEnvironment.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,72 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ // `react-relay`, `relay-runtime`, and `relay-test-utils` are CJS packages
4
+ // with member-expression exports that Node's `cjs-module-lexer` cannot
5
+ // detect, so these named imports fail under bare Node ESM. That is fine for
6
+ // this package: a Storybook addon is consumed through Storybook + Vite, and
7
+ // the `./preset` `viteFinal` pre-bundles `relay-test-utils` so the names
8
+ // resolve in the preview iframe.
9
+ import { RelayEnvironmentProvider } from "react-relay";
10
+ import { createMockEnvironment, MockPayloadGenerator, } from "relay-test-utils";
11
+ import { PARAM_KEY } from "../constants.js";
12
+ /**
13
+ * Creates a mock Relay environment whose network resolves every operation
14
+ * with the payload described by the story's `parameters.relay`.
15
+ *
16
+ * React components issue their Relay requests while rendering (e.g.
17
+ * `useLazyLoadQuery` fetches when the hook runs), which happens only after
18
+ * the decorator has returned its element tree — so the decorator cannot call
19
+ * `resolveMostRecentOperation` up front; it must queue a resolver instead.
20
+ * `relay-test-utils` consumes a queued resolver after a single operation, so
21
+ * a resolver queued once would only cover the story's first query and leave
22
+ * refetches, pagination, and mutations (e.g. from play functions) pending
23
+ * forever. The queued resolver therefore re-arms itself after every
24
+ * operation, resolving however many operations the story issues.
25
+ */
26
+ const createStoryEnvironment = (parameters) => {
27
+ const environment = createMockEnvironment();
28
+ const { mockResolvers, generateFunction } = parameters;
29
+ const resolveOperation = (operation) => generateFunction
30
+ ? generateFunction(operation, mockResolvers)
31
+ : MockPayloadGenerator.generate(operation, mockResolvers);
32
+ const armOperationResolver = () => {
33
+ environment.mock.queueOperationResolver((operation) => {
34
+ armOperationResolver();
35
+ return resolveOperation(operation);
36
+ });
37
+ };
38
+ armOperationResolver();
39
+ return environment;
40
+ };
41
+ /**
42
+ * Internal wrapper component that owns the mock environment's lifecycle.
43
+ *
44
+ * The environment is created lazily on mount and kept for the lifetime of
45
+ * the mounted story: re-renders (e.g. Storybook controls changing args) keep
46
+ * the same environment and store, while remounts (story switch, the remount
47
+ * toolbar button) start from a fresh one. `parameters.relay` is read when the
48
+ * environment is created; Storybook parameters are static per story.
49
+ */
50
+ const MockRelayEnvironmentProvider = ({ parameters, children, }) => {
51
+ const [environment] = useState(() => createStoryEnvironment(parameters));
52
+ return (_jsx(RelayEnvironmentProvider, { environment: environment, children: children }));
53
+ };
54
+ /**
55
+ * Storybook decorator that lets React stories using Relay hooks
56
+ * (`useLazyLoadQuery`, `useFragment`, `usePaginationFragment`, ...) render
57
+ * against a mock Relay environment.
58
+ *
59
+ * Reads `parameters.relay` from the story context. If absent, the story
60
+ * passes through unchanged. If present, the story is wrapped in a
61
+ * `RelayEnvironmentProvider` carrying a `relay-test-utils` mock environment
62
+ * that automatically resolves every operation the story issues, using the
63
+ * story's `mockResolvers` and/or `generateFunction`.
64
+ */
65
+ export const withRelayEnvironment = (storyFn, context) => {
66
+ const relayParameters = context.parameters?.[PARAM_KEY];
67
+ if (!relayParameters) {
68
+ return storyFn();
69
+ }
70
+ return (_jsx(MockRelayEnvironmentProvider, { parameters: relayParameters, children: storyFn() }));
71
+ };
72
+ //# sourceMappingURL=withRelayEnvironment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withRelayEnvironment.js","sourceRoot":"","sources":["../../../src/lib/withRelayEnvironment.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAqC,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpE,0EAA0E;AAC1E,uEAAuE;AACvE,4EAA4E;AAC5E,4EAA4E;AAC5E,yEAAyE;AACzE,iCAAiC;AACjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAKvD,OAAO,EACL,qBAAqB,EAErB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;GAaG;AACH,MAAM,sBAAsB,GAAG,CAC7B,UAA2B,EACV,EAAE;IACnB,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAAC;IAEvD,MAAM,gBAAgB,GAAG,CACvB,SAA8B,EACL,EAAE,CAC3B,gBAAgB;QACd,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC;QAC5C,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAE9D,MAAM,oBAAoB,GAAG,GAAS,EAAE;QACtC,WAAW,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,SAAS,EAAE,EAAE;YACpD,oBAAoB,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,oBAAoB,EAAE,CAAC;IAEvB,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,4BAA4B,GAAG,CAAC,EACpC,UAAU,EACV,QAAQ,GAIT,EAAgB,EAAE;IACjB,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;IAEzE,OAAO,CACL,KAAC,wBAAwB,IAAC,WAAW,EAAE,WAAW,YAC/C,QAAQ,GACgB,CAC5B,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,OAAgC,EAChC,OAA+B,EACM,EAAE;IACvC,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,SAAS,CAEzC,CAAC;IAEd,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,OAAO,CACL,KAAC,4BAA4B,IAAC,UAAU,EAAE,eAAe,YACtD,OAAO,EAAe,GACM,CACO,CAAC;AAC3C,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Storybook addon preset — configures Vite so that `relay-test-utils`
3
+ * (a CJS-only package) is pre-bundled, allowing its named exports
4
+ * (`createMockEnvironment`, `MockPayloadGenerator`) to work in
5
+ * the browser ESM context.
6
+ *
7
+ * @note Named `viteFinal` per Storybook preset API convention — not a
8
+ * verb-first function name by design.
9
+ */
10
+ export const viteFinal = (config) => {
11
+ const optimizeDeps = (config.optimizeDeps ?? {});
12
+ const include = (optimizeDeps.include ?? []);
13
+ if (!include.includes("relay-test-utils")) {
14
+ include.push("relay-test-utils");
15
+ }
16
+ optimizeDeps.include = include;
17
+ config.optimizeDeps = optimizeDeps;
18
+ return config;
19
+ };
20
+ //# sourceMappingURL=preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.js","sourceRoot":"","sources":["../../src/preset.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,MAA+B,EACN,EAAE;IAC3B,MAAM,YAAY,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAA4B,CAAC;IAC5E,MAAM,OAAO,GAAG,CAAC,YAAY,CAAC,OAAO,IAAI,EAAE,CAAa,CAAC;IAEzD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACnC,CAAC;IAED,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;IAEnC,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { withRelayEnvironment } from "./lib/withRelayEnvironment.js";
2
+ /**
3
+ * Storybook preview annotations — registers the `withRelayEnvironment`
4
+ * decorator globally, so adding this addon to the Storybook config is the
5
+ * only setup consumers need.
6
+ */
7
+ const preview = {
8
+ decorators: [withRelayEnvironment],
9
+ };
10
+ export default preview;
11
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/preview.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE;;;;GAIG;AACH,MAAM,OAAO,GAAiC;IAC5C,UAAU,EAAE,CAAC,oBAAoB,CAAC;CACnC,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Key under which stories declare their Relay configuration in Storybook
3
+ * `parameters` (i.e. `parameters.relay`).
4
+ */
5
+ export declare const PARAM_KEY = "relay";
6
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,SAAS,UAAU,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @canonical/storybook-addon-relay — renders React stories that use Relay
3
+ * hooks against a `relay-test-utils` mock environment, configured per story
4
+ * via `parameters.relay` (`mockResolvers`, `generateFunction`).
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export * from "./lib/index.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { RelayParameters } from "./types.js";
2
+ export { withRelayEnvironment } from "./withRelayEnvironment.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { GraphQLSingularResponse, OperationDescriptor } from "relay-runtime";
2
+ import type { MockResolvers } from "relay-test-utils";
3
+ /**
4
+ * Shape of the `relay` key in a story's Storybook `parameters`.
5
+ *
6
+ * When present, the `withRelayEnvironment` decorator wraps the story in a
7
+ * mock Relay environment and resolves every GraphQL operation the story
8
+ * issues (initial queries, refetches, pagination, mutations) with the
9
+ * configuration declared here. When absent, the decorator is a no-op.
10
+ *
11
+ * The created mock environment is deliberately not exposed back to the story
12
+ * context: operations resolve automatically through the queued resolver, so
13
+ * stories and play functions have no need to drive the mock network by hand.
14
+ * Keeping the environment private keeps the `parameters.relay` contract to
15
+ * the two options below.
16
+ */
17
+ export interface RelayParameters<TResolvers extends MockResolvers = MockResolvers> {
18
+ /**
19
+ * Mock resolvers passed to `MockPayloadGenerator.generate()`. Keys are
20
+ * GraphQL type names, values are factories returning field values for that
21
+ * type. Fields without a resolver receive deterministic placeholder values.
22
+ */
23
+ mockResolvers?: TResolvers;
24
+ /**
25
+ * Full override for payload generation. When provided, it is called instead
26
+ * of `MockPayloadGenerator.generate()` for every operation the story
27
+ * issues, receiving the operation and the configured `mockResolvers`.
28
+ */
29
+ generateFunction?: (operation: OperationDescriptor, mockResolvers?: TResolvers | null) => GraphQLSingularResponse;
30
+ }
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe,CAC9B,UAAU,SAAS,aAAa,GAAG,aAAa;IAEhD;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CACjB,SAAS,EAAE,mBAAmB,EAC9B,aAAa,CAAC,EAAE,UAAU,GAAG,IAAI,KAC9B,uBAAuB,CAAC;CAC9B"}
@@ -0,0 +1,14 @@
1
+ import type { Renderer, StoryContext, PartialStoryFn as StoryFunction } from "storybook/internal/types";
2
+ /**
3
+ * Storybook decorator that lets React stories using Relay hooks
4
+ * (`useLazyLoadQuery`, `useFragment`, `usePaginationFragment`, ...) render
5
+ * against a mock Relay environment.
6
+ *
7
+ * Reads `parameters.relay` from the story context. If absent, the story
8
+ * passes through unchanged. If present, the story is wrapped in a
9
+ * `RelayEnvironmentProvider` carrying a `relay-test-utils` mock environment
10
+ * that automatically resolves every operation the story issues, using the
11
+ * story's `mockResolvers` and/or `generateFunction`.
12
+ */
13
+ export declare const withRelayEnvironment: (storyFn: StoryFunction<Renderer>, context: StoryContext<Renderer>) => ReturnType<StoryFunction<Renderer>>;
14
+ //# sourceMappingURL=withRelayEnvironment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withRelayEnvironment.d.ts","sourceRoot":"","sources":["../../../src/lib/withRelayEnvironment.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,IAAI,aAAa,EAChC,MAAM,0BAA0B,CAAC;AAmElC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,aAAa,CAAC,QAAQ,CAAC,EAChC,SAAS,YAAY,CAAC,QAAQ,CAAC,KAC9B,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,CAcpC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Storybook addon preset — configures Vite so that `relay-test-utils`
3
+ * (a CJS-only package) is pre-bundled, allowing its named exports
4
+ * (`createMockEnvironment`, `MockPayloadGenerator`) to work in
5
+ * the browser ESM context.
6
+ *
7
+ * @note Named `viteFinal` per Storybook preset API convention — not a
8
+ * verb-first function name by design.
9
+ */
10
+ export declare const viteFinal: (config: Record<string, unknown>) => Record<string, unknown>;
11
+ //# sourceMappingURL=preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GACpB,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAYxB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ProjectAnnotations, Renderer } from "storybook/internal/types";
2
+ /**
3
+ * Storybook preview annotations — registers the `withRelayEnvironment`
4
+ * decorator globally, so adding this addon to the Storybook config is the
5
+ * only setup consumers need.
6
+ */
7
+ declare const preview: ProjectAnnotations<Renderer>;
8
+ export default preview;
9
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAG7E;;;;GAIG;AACH,QAAA,MAAM,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAEzC,CAAC;AAEF,eAAe,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@canonical/storybook-addon-relay",
3
+ "version": "0.29.1",
4
+ "type": "module",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "module": "dist/esm/index.js",
9
+ "types": "dist/types/index.d.ts",
10
+ "author": {
11
+ "email": "webteam@canonical.com",
12
+ "name": "Canonical Webteam"
13
+ },
14
+ "description": "Renders React stories that use Relay hooks against a mock Relay environment",
15
+ "keywords": [
16
+ "storybook-addons",
17
+ "relay",
18
+ "react-relay",
19
+ "graphql"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/canonical/pragma"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/canonical/pragma/issues"
27
+ },
28
+ "license": "LGPL-3.0",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/types/index.d.ts",
32
+ "default": "./dist/esm/index.js"
33
+ },
34
+ "./preview": {
35
+ "types": "./dist/types/preview.d.ts",
36
+ "default": "./dist/esm/preview.js"
37
+ },
38
+ "./preset": {
39
+ "types": "./dist/types/preset.d.ts",
40
+ "default": "./dist/esm/preset.js"
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "build": "bun run build:package",
49
+ "build:all": "bun run build:package",
50
+ "build:package": "bun run build:package:tsc",
51
+ "build:package:tsc": "tsc -p tsconfig.build.json",
52
+ "check": "bun run check:biome && bun run check:ts && bun run check:webarchitect",
53
+ "check:fix": "bun run check:biome:fix && bun run check:ts",
54
+ "check:biome": "biome check",
55
+ "check:biome:fix": "biome check --write",
56
+ "check:ts": "tsc --noEmit",
57
+ "check:webarchitect": "webarchitect library",
58
+ "test": "vitest run",
59
+ "test:watch": "vitest",
60
+ "test:coverage": "vitest run --coverage"
61
+ },
62
+ "dependencies": {
63
+ "relay-test-utils": "^18.2.0"
64
+ },
65
+ "devDependencies": {
66
+ "@biomejs/biome": "2.4.9",
67
+ "@canonical/biome-config": "^0.29.0",
68
+ "@canonical/typescript-config-react": "^0.29.0",
69
+ "@canonical/webarchitect": "^0.29.0",
70
+ "@testing-library/react": "^16.3.2",
71
+ "@types/node": "^24.12.0",
72
+ "@types/react": "^19.2.14",
73
+ "@types/react-dom": "^19.2.3",
74
+ "@types/react-relay": "^18.2.1",
75
+ "@types/relay-runtime": "^19.0.3",
76
+ "@types/relay-test-utils": "^18.0.0",
77
+ "@vitejs/plugin-react": "^6.0.0",
78
+ "@vitest/coverage-v8": "^4.0.18",
79
+ "jsdom": "^28.1.0",
80
+ "react": "^19.2.4",
81
+ "react-dom": "^19.2.4",
82
+ "react-relay": "^18.2.0",
83
+ "relay-runtime": "^18.2.0",
84
+ "storybook": "^10.3.1",
85
+ "typescript": "^5.9.3",
86
+ "vite": "^8.0.1",
87
+ "vitest": "^4.0.18"
88
+ },
89
+ "peerDependencies": {
90
+ "react": "^18.0.0 || ^19.0.0",
91
+ "react-dom": "^18.0.0 || ^19.0.0",
92
+ "react-relay": ">=18.0.0 <19.0.0",
93
+ "relay-runtime": ">=18.0.0 <19.0.0",
94
+ "storybook": "^10.3.1"
95
+ },
96
+ "storybook": {
97
+ "displayName": "Relay",
98
+ "supportedFrameworks": [
99
+ "react"
100
+ ],
101
+ "icon": "https://relay.dev/img/relay.svg"
102
+ }
103
+ }