@squide/firefly-rsbuild-storybook 0.0.1 → 1.0.0
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/CHANGELOG.md +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/initializeFireflyForStorybook.d.ts +3 -0
- package/dist/initializeFireflyForStorybook.js +12 -6
- package/dist/initializeFireflyForStorybook.js.map +1 -1
- package/dist/withFeatureFlagsOverrideDecorator.d.ts +3 -0
- package/dist/withFeatureFlagsOverrideDecorator.js +47 -0
- package/dist/withFeatureFlagsOverrideDecorator.js.map +1 -0
- package/package.json +23 -17
- package/src/index.ts +1 -0
- package/src/initializeFireflyForStorybook.ts +24 -7
- package/src/withFeatureFlagsOverrideDecorator.tsx +49 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @squide/firefly-rsbuild-storybook
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#352](https://github.com/workleap/wl-squide/pull/352) [`7bd7af5`](https://github.com/workleap/wl-squide/commit/7bd7af5a757912309704b9e93bf8ecf1388e6787) Thanks [@patricklafrance](https://github.com/patricklafrance)! - Added the `withFeatureFlagOverrideDecorator` hook and first major release.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`7bd7af5`](https://github.com/workleap/wl-squide/commit/7bd7af5a757912309704b9e93bf8ecf1388e6787), [`7bd7af5`](https://github.com/workleap/wl-squide/commit/7bd7af5a757912309704b9e93bf8ecf1388e6787), [`7bd7af5`](https://github.com/workleap/wl-squide/commit/7bd7af5a757912309704b9e93bf8ecf1388e6787)]:
|
|
12
|
+
- @squide/env-vars@1.4.10
|
|
13
|
+
- @squide/msw@4.0.8
|
|
14
|
+
- @squide/launch-darkly@1.0.0
|
|
15
|
+
- @squide/firefly@16.1.0
|
|
16
|
+
|
|
3
17
|
## 0.0.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { initializeFireflyForStorybook, type InitializeFireflyForStorybookOptions } from "./initializeFireflyForStorybook.ts";
|
|
2
2
|
export { StorybookRuntime, StorybookRuntimeScope } from "./StorybookRuntime.ts";
|
|
3
|
+
export { withFeatureFlagsOverrideDecorator } from "./withFeatureFlagsOverrideDecorator.tsx";
|
|
3
4
|
export { FireflyDecorator, withFireflyDecorator, type FireflyDecoratorProps } from "./withFireflyDecorator.tsx";
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { initializeFireflyForStorybook } from "./initializeFireflyForStorybook.js";
|
|
2
2
|
import { StorybookRuntime, StorybookRuntimeScope } from "./StorybookRuntime.js";
|
|
3
|
+
import { withFeatureFlagsOverrideDecorator } from "./withFeatureFlagsOverrideDecorator.js";
|
|
3
4
|
import { FireflyDecorator, withFireflyDecorator } from "./withFireflyDecorator.js";
|
|
4
5
|
|
|
5
6
|
;// CONCATENATED MODULE: external "./initializeFireflyForStorybook.js"
|
|
6
7
|
|
|
7
8
|
;// CONCATENATED MODULE: external "./StorybookRuntime.js"
|
|
8
9
|
|
|
10
|
+
;// CONCATENATED MODULE: external "./withFeatureFlagsOverrideDecorator.js"
|
|
11
|
+
|
|
9
12
|
;// CONCATENATED MODULE: external "./withFireflyDecorator.js"
|
|
10
13
|
|
|
11
14
|
;// CONCATENATED MODULE: ./src/index.ts
|
|
@@ -13,6 +16,7 @@ import { FireflyDecorator, withFireflyDecorator } from "./withFireflyDecorator.j
|
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
|
|
20
|
+
export { FireflyDecorator, StorybookRuntime, StorybookRuntimeScope, initializeFireflyForStorybook, withFeatureFlagsOverrideDecorator, withFireflyDecorator };
|
|
17
21
|
|
|
18
22
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["export { initializeFireflyForStorybook, type InitializeFireflyForStorybookOptions } from \"./initializeFireflyForStorybook.ts\";\nexport { StorybookRuntime, StorybookRuntimeScope } from \"./StorybookRuntime.ts\";\nexport { FireflyDecorator, withFireflyDecorator, type FireflyDecoratorProps } from \"./withFireflyDecorator.tsx\";\n\n"],"names":["initializeFireflyForStorybook","StorybookRuntime","StorybookRuntimeScope","FireflyDecorator","withFireflyDecorator"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["export { initializeFireflyForStorybook, type InitializeFireflyForStorybookOptions } from \"./initializeFireflyForStorybook.ts\";\nexport { StorybookRuntime, StorybookRuntimeScope } from \"./StorybookRuntime.ts\";\nexport { withFeatureFlagsOverrideDecorator } from \"./withFeatureFlagsOverrideDecorator.tsx\";\nexport { FireflyDecorator, withFireflyDecorator, type FireflyDecoratorProps } from \"./withFireflyDecorator.tsx\";\n\n"],"names":["initializeFireflyForStorybook","StorybookRuntime","StorybookRuntimeScope","withFeatureFlagsOverrideDecorator","FireflyDecorator","withFireflyDecorator"],"mappings":";;;;;;;;;;;;;;AAA8H;AAC9C;AACY;AACoB"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { EnvironmentVariables } from "@squide/env-vars";
|
|
2
2
|
import { FireflyRuntime, ModuleRegisterFunction } from "@squide/firefly";
|
|
3
|
+
import { LDClient, LDFlagValue } from "launchdarkly-js-client-sdk";
|
|
3
4
|
import { StorybookRuntime } from "./StorybookRuntime.ts";
|
|
4
5
|
export interface InitializeFireflyForStorybookOptions {
|
|
5
6
|
localModules?: ModuleRegisterFunction<FireflyRuntime>[];
|
|
6
7
|
environmentVariables?: EnvironmentVariables;
|
|
8
|
+
featureFlags?: Map<string, LDFlagValue> | Record<string, LDFlagValue>;
|
|
9
|
+
launchDarklyClient?: LDClient;
|
|
7
10
|
}
|
|
8
11
|
export declare function initializeFireflyForStorybook(options?: InitializeFireflyForStorybookOptions): Promise<StorybookRuntime>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EnvironmentVariablesPlugin } from "@squide/env-vars";
|
|
2
|
-
import { toLocalModuleDefinitions } from "@squide/firefly";
|
|
2
|
+
import { InMemoryLaunchDarklyClient, LaunchDarklyPlugin, toLocalModuleDefinitions } from "@squide/firefly";
|
|
3
3
|
import { MswPlugin } from "@squide/msw";
|
|
4
4
|
import { StorybookRuntime } from "./StorybookRuntime.js";
|
|
5
5
|
|
|
@@ -17,19 +17,25 @@ import { StorybookRuntime } from "./StorybookRuntime.js";
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
async function initializeFireflyForStorybook(options = {}) {
|
|
20
|
-
const { localModules
|
|
20
|
+
const { localModules, environmentVariables, featureFlags = {}, launchDarklyClient } = options;
|
|
21
21
|
const runtime = new StorybookRuntime({
|
|
22
22
|
mode: "development",
|
|
23
23
|
plugins: [
|
|
24
24
|
(x)=>new MswPlugin(x),
|
|
25
25
|
(x)=>new EnvironmentVariablesPlugin(x, {
|
|
26
26
|
variables: environmentVariables
|
|
27
|
-
})
|
|
27
|
+
}),
|
|
28
|
+
(x)=>new LaunchDarklyPlugin(x, // 1- If no client is provided create it.
|
|
29
|
+
// 2- If feature flags are provided and it's an instance of Map, use the argument.
|
|
30
|
+
// 3- If feature flags are provided (or the default value) and it's an object literal, convert the object to a Map instance.
|
|
31
|
+
launchDarklyClient ?? new InMemoryLaunchDarklyClient(featureFlags instanceof Map ? featureFlags : new Map(Object.entries(featureFlags))))
|
|
28
32
|
]
|
|
29
33
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
if (localModules && localModules.length > 0) {
|
|
35
|
+
await runtime.moduleManager.registerModules([
|
|
36
|
+
...toLocalModuleDefinitions(localModules)
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
33
39
|
return runtime;
|
|
34
40
|
}
|
|
35
41
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initializeFireflyForStorybook.js","sources":["../src/initializeFireflyForStorybook.ts"],"sourcesContent":["import { EnvironmentVariables, EnvironmentVariablesPlugin } from \"@squide/env-vars\";\nimport { FireflyRuntime, ModuleRegisterFunction, toLocalModuleDefinitions } from \"@squide/firefly\";\nimport { MswPlugin } from \"@squide/msw\";\nimport { StorybookRuntime } from \"./StorybookRuntime.ts\";\n\nexport interface InitializeFireflyForStorybookOptions {\n localModules?: ModuleRegisterFunction<FireflyRuntime>[];\n environmentVariables?: EnvironmentVariables;\n}\n\nexport async function initializeFireflyForStorybook(options: InitializeFireflyForStorybookOptions = {}) {\n const {\n localModules
|
|
1
|
+
{"version":3,"file":"initializeFireflyForStorybook.js","sources":["../src/initializeFireflyForStorybook.ts"],"sourcesContent":["import { EnvironmentVariables, EnvironmentVariablesPlugin } from \"@squide/env-vars\";\nimport { FireflyRuntime, InMemoryLaunchDarklyClient, LaunchDarklyPlugin, ModuleRegisterFunction, toLocalModuleDefinitions } from \"@squide/firefly\";\nimport { MswPlugin } from \"@squide/msw\";\nimport { LDClient, LDFlagValue } from \"launchdarkly-js-client-sdk\";\nimport { StorybookRuntime } from \"./StorybookRuntime.ts\";\n\nexport interface InitializeFireflyForStorybookOptions {\n localModules?: ModuleRegisterFunction<FireflyRuntime>[];\n environmentVariables?: EnvironmentVariables;\n featureFlags?: Map<string, LDFlagValue> | Record<string, LDFlagValue>;\n launchDarklyClient?: LDClient;\n}\n\nexport async function initializeFireflyForStorybook(options: InitializeFireflyForStorybookOptions = {}) {\n const {\n localModules,\n environmentVariables,\n featureFlags = {},\n launchDarklyClient\n } = options;\n\n const runtime = new StorybookRuntime({\n mode: \"development\",\n plugins: [\n x => new MswPlugin(x),\n x => new EnvironmentVariablesPlugin(x, {\n variables: environmentVariables\n }),\n x => new LaunchDarklyPlugin(\n x,\n // 1- If no client is provided create it.\n // 2- If feature flags are provided and it's an instance of Map, use the argument.\n // 3- If feature flags are provided (or the default value) and it's an object literal, convert the object to a Map instance.\n launchDarklyClient ?? new InMemoryLaunchDarklyClient(featureFlags instanceof Map\n ? featureFlags\n : new Map<string, LDFlagValue>(Object.entries(featureFlags))\n )\n )\n ]\n });\n\n if (localModules && localModules.length > 0) {\n await runtime.moduleManager.registerModules([\n ...toLocalModuleDefinitions(localModules)\n ]);\n }\n\n return runtime;\n}\n"],"names":["EnvironmentVariablesPlugin","InMemoryLaunchDarklyClient","LaunchDarklyPlugin","toLocalModuleDefinitions","MswPlugin","StorybookRuntime","initializeFireflyForStorybook","options","localModules","environmentVariables","featureFlags","launchDarklyClient","runtime","x","Map","Object"],"mappings":";;;;;;;;;;;;;;AAAoF;AAC+D;AAC3G;AAEiB;AASlD,eAAeM,8BAA8BC,UAAgD,CAAC,CAAC;IAClG,MAAM,EACFC,YAAY,EACZC,oBAAoB,EACpBC,eAAe,CAAC,CAAC,EACjBC,kBAAkB,EACrB,GAAGJ;IAEJ,MAAMK,UAAU,IAAIP,gBAAgBA,CAAC;QACjC,MAAM;QACN,SAAS;YACLQ,CAAAA,IAAK,IAAIT,SAASA,CAACS;YACnBA,CAAAA,IAAK,IAAIb,0BAA0BA,CAACa,GAAG;oBACnC,WAAWJ;gBACf;YACAI,CAAAA,IAAK,IAAIX,kBAAkBA,CACvBW,GACA,yCAAyC;gBACzC,kFAAkF;gBAClF,4HAA4H;gBAC5HF,sBAAsB,IAAIV,0BAA0BA,CAACS,wBAAwBI,MACvEJ,eACA,IAAII,IAAyBC,OAAO,OAAO,CAACL;SAGzD;IACL;IAEA,IAAIF,gBAAgBA,aAAa,MAAM,GAAG,GAAG;QACzC,MAAMI,QAAQ,aAAa,CAAC,eAAe,CAAC;eACrCT,wBAAwBA,CAACK;SAC/B;IACL;IAEA,OAAOI;AACX"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { LDFlagValue } from "launchdarkly-js-client-sdk";
|
|
2
|
+
import { Decorator } from "storybook-react-rsbuild";
|
|
3
|
+
export declare function withFeatureFlagsOverrideDecorator<const T extends string>(featureFlags: Map<T, LDFlagValue>, overrides: Partial<Record<T, LDFlagValue>>): Decorator;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect } from "react";
|
|
3
|
+
|
|
4
|
+
;// CONCATENATED MODULE: external "react/jsx-runtime"
|
|
5
|
+
|
|
6
|
+
;// CONCATENATED MODULE: external "react"
|
|
7
|
+
|
|
8
|
+
;// CONCATENATED MODULE: ./src/withFeatureFlagsOverrideDecorator.tsx
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function OverrideFeatureFlags(props) {
|
|
12
|
+
const { featureFlags, overrides, children } = props;
|
|
13
|
+
// Must use a layout effect to override the feature flags before the story renders.
|
|
14
|
+
useLayoutEffect(()=>{
|
|
15
|
+
const originalValues = {};
|
|
16
|
+
Object.entries(overrides).forEach(([key, value])=>{
|
|
17
|
+
originalValues[key] = featureFlags.get(key);
|
|
18
|
+
featureFlags.set(key, value);
|
|
19
|
+
});
|
|
20
|
+
return ()=>{
|
|
21
|
+
// Reset the feature flags to the original values.
|
|
22
|
+
Object.entries(originalValues).forEach(([key, value])=>{
|
|
23
|
+
featureFlags.set(key, value);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
}, [
|
|
27
|
+
featureFlags,
|
|
28
|
+
overrides
|
|
29
|
+
]);
|
|
30
|
+
return children;
|
|
31
|
+
}
|
|
32
|
+
function withFeatureFlagsOverrideDecorator(featureFlags, overrides) {
|
|
33
|
+
if (!(featureFlags instanceof Map)) {
|
|
34
|
+
throw new TypeError("[squide] The \"featureFlags\" argument must be a Map instance.");
|
|
35
|
+
}
|
|
36
|
+
return (story)=>{
|
|
37
|
+
return /*#__PURE__*/ jsx(OverrideFeatureFlags, {
|
|
38
|
+
featureFlags: featureFlags,
|
|
39
|
+
overrides: overrides,
|
|
40
|
+
children: story()
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { withFeatureFlagsOverrideDecorator };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=withFeatureFlagsOverrideDecorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withFeatureFlagsOverrideDecorator.js","sources":["../src/withFeatureFlagsOverrideDecorator.tsx"],"sourcesContent":["import { LDFlagValue } from \"launchdarkly-js-client-sdk\";\nimport { PropsWithChildren, useLayoutEffect } from \"react\";\nimport { Decorator } from \"storybook-react-rsbuild\";\n\ninterface OverrideFeatureFlagsProps extends PropsWithChildren {\n featureFlags: Map<string, LDFlagValue>;\n overrides: Record<string, LDFlagValue>;\n}\n\nfunction OverrideFeatureFlags(props: OverrideFeatureFlagsProps) {\n const {\n featureFlags,\n overrides,\n children\n } = props;\n\n // Must use a layout effect to override the feature flags before the story renders.\n useLayoutEffect(() => {\n const originalValues: Record<string, LDFlagValue> = {};\n\n Object.entries(overrides).forEach(([key, value]) => {\n originalValues[key] = featureFlags.get(key);\n featureFlags.set(key, value);\n });\n\n return () => {\n // Reset the feature flags to the original values.\n Object.entries(originalValues).forEach(([key, value]) => {\n featureFlags.set(key, value);\n });\n };\n }, [featureFlags, overrides]);\n\n return children;\n}\n\nexport function withFeatureFlagsOverrideDecorator<const T extends string>(featureFlags: Map<T, LDFlagValue>, overrides: Partial<Record<T, LDFlagValue>>): Decorator {\n if (!(featureFlags instanceof Map)) {\n throw new TypeError(\"[squide] The \\\"featureFlags\\\" argument must be a Map instance.\");\n }\n\n return story => {\n return (\n <OverrideFeatureFlags featureFlags={featureFlags} overrides={overrides}>\n {story()}\n </OverrideFeatureFlags>\n );\n };\n}\n"],"names":["useLayoutEffect","OverrideFeatureFlags","props","featureFlags","overrides","children","originalValues","Object","key","value","withFeatureFlagsOverrideDecorator","Map","TypeError","story"],"mappings":";;;;;;;;;AAC2D;AAQ3D,SAASC,qBAAqBC,KAAgC;IAC1D,MAAM,EACFC,YAAY,EACZC,SAAS,EACTC,QAAQ,EACX,GAAGH;IAEJ,mFAAmF;IACnFF,eAAeA,CAAC;QACZ,MAAMM,iBAA8C,CAAC;QAErDC,OAAO,OAAO,CAACH,WAAW,OAAO,CAAC,CAAC,CAACI,KAAKC,MAAM;YAC3CH,cAAc,CAACE,IAAI,GAAGL,aAAa,GAAG,CAACK;YACvCL,aAAa,GAAG,CAACK,KAAKC;QAC1B;QAEA,OAAO;YACH,kDAAkD;YAClDF,OAAO,OAAO,CAACD,gBAAgB,OAAO,CAAC,CAAC,CAACE,KAAKC,MAAM;gBAChDN,aAAa,GAAG,CAACK,KAAKC;YAC1B;QACJ;IACJ,GAAG;QAACN;QAAcC;KAAU;IAE5B,OAAOC;AACX;AAEO,SAASK,kCAA0DP,YAAiC,EAAEC,SAA0C;IACnJ,IAAI,CAAED,CAAAA,wBAAwBQ,GAAE,GAAI;QAChC,MAAM,IAAIC,UAAU;IACxB;IAEA,OAAOC,CAAAA;QACH,qBACI,IAACZ;YAAqB,cAAcE;YAAc,WAAWC;sBACxDS;;IAGb;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squide/firefly-rsbuild-storybook",
|
|
3
3
|
"author": "Workleap",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "Squide firefly helpers for Storybook and Rsbuild.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -28,14 +28,15 @@
|
|
|
28
28
|
],
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@opentelemetry/api": "^1.9.0",
|
|
31
|
-
"@rsbuild/core": "^1.6.
|
|
32
|
-
"@tanstack/react-query": "^5.90.
|
|
33
|
-
"
|
|
31
|
+
"@rsbuild/core": "^1.6.14",
|
|
32
|
+
"@tanstack/react-query": "^5.90.12",
|
|
33
|
+
"launchdarkly-js-client-sdk": "^3.9.0",
|
|
34
|
+
"msw": "^2.12.4",
|
|
34
35
|
"react": "^18.0.0 || ^19.0.0",
|
|
35
36
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
36
|
-
"react-router": "^7.
|
|
37
|
-
"storybook": "^10.1.
|
|
38
|
-
"storybook-react-rsbuild": "^3.
|
|
37
|
+
"react-router": "^7.10.1",
|
|
38
|
+
"storybook": "^10.1.6",
|
|
39
|
+
"storybook-react-rsbuild": "^3.1.0"
|
|
39
40
|
},
|
|
40
41
|
"peerDependenciesMeta": {
|
|
41
42
|
"@opentelemetry/api": {
|
|
@@ -43,30 +44,35 @@
|
|
|
43
44
|
}
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@workleap-telemetry/core": "^1.0.
|
|
47
|
+
"@workleap-telemetry/core": "^1.0.5",
|
|
47
48
|
"@workleap/logging": "^1.3.2",
|
|
48
|
-
"@squide/env-vars": "1.4.
|
|
49
|
-
"@squide/firefly": "16.0
|
|
50
|
-
"@squide/
|
|
49
|
+
"@squide/env-vars": "1.4.10",
|
|
50
|
+
"@squide/firefly": "16.1.0",
|
|
51
|
+
"@squide/launch-darkly": "1.0.0",
|
|
52
|
+
"@squide/msw": "4.0.8"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
55
|
"@eslint/js": "9.39.1",
|
|
54
|
-
"@rsbuild/core": "1.6.
|
|
55
|
-
"@rslib/core": "0.18.
|
|
56
|
+
"@rsbuild/core": "1.6.14",
|
|
57
|
+
"@rslib/core": "0.18.4",
|
|
56
58
|
"@types/react": "19.2.7",
|
|
57
59
|
"@types/react-dom": "19.2.3",
|
|
58
|
-
"@typescript-eslint/parser": "8.
|
|
59
|
-
"@
|
|
60
|
+
"@typescript-eslint/parser": "8.49.0",
|
|
61
|
+
"@vitejs/plugin-react": "5.1.2",
|
|
62
|
+
"@workleap/eslint-configs": "1.1.6",
|
|
60
63
|
"@workleap/rslib-configs": "1.1.3",
|
|
61
64
|
"@workleap/typescript-configs": "3.0.7",
|
|
62
65
|
"eslint": "9.39.1",
|
|
66
|
+
"happy-dom": "20.0.11",
|
|
63
67
|
"typescript": "5.9.3",
|
|
64
|
-
"typescript-eslint": "8.
|
|
68
|
+
"typescript-eslint": "8.49.0",
|
|
69
|
+
"vitest": "4.0.15"
|
|
65
70
|
},
|
|
66
71
|
"sideEffects": false,
|
|
67
72
|
"scripts": {
|
|
68
73
|
"build": "rslib build --config ./rslib.build.ts",
|
|
69
74
|
"eslint": "eslint . --max-warnings=0 --cache --cache-location node_modules/.cache/eslint",
|
|
70
|
-
"typecheck": "tsc"
|
|
75
|
+
"typecheck": "tsc",
|
|
76
|
+
"test": "vitest --config vitest.config.ts --no-watch"
|
|
71
77
|
}
|
|
72
78
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { initializeFireflyForStorybook, type InitializeFireflyForStorybookOptions } from "./initializeFireflyForStorybook.ts";
|
|
2
2
|
export { StorybookRuntime, StorybookRuntimeScope } from "./StorybookRuntime.ts";
|
|
3
|
+
export { withFeatureFlagsOverrideDecorator } from "./withFeatureFlagsOverrideDecorator.tsx";
|
|
3
4
|
export { FireflyDecorator, withFireflyDecorator, type FireflyDecoratorProps } from "./withFireflyDecorator.tsx";
|
|
4
5
|
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { EnvironmentVariables, EnvironmentVariablesPlugin } from "@squide/env-vars";
|
|
2
|
-
import { FireflyRuntime, ModuleRegisterFunction, toLocalModuleDefinitions } from "@squide/firefly";
|
|
2
|
+
import { FireflyRuntime, InMemoryLaunchDarklyClient, LaunchDarklyPlugin, ModuleRegisterFunction, toLocalModuleDefinitions } from "@squide/firefly";
|
|
3
3
|
import { MswPlugin } from "@squide/msw";
|
|
4
|
+
import { LDClient, LDFlagValue } from "launchdarkly-js-client-sdk";
|
|
4
5
|
import { StorybookRuntime } from "./StorybookRuntime.ts";
|
|
5
6
|
|
|
6
7
|
export interface InitializeFireflyForStorybookOptions {
|
|
7
8
|
localModules?: ModuleRegisterFunction<FireflyRuntime>[];
|
|
8
9
|
environmentVariables?: EnvironmentVariables;
|
|
10
|
+
featureFlags?: Map<string, LDFlagValue> | Record<string, LDFlagValue>;
|
|
11
|
+
launchDarklyClient?: LDClient;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
export async function initializeFireflyForStorybook(options: InitializeFireflyForStorybookOptions = {}) {
|
|
12
15
|
const {
|
|
13
|
-
localModules
|
|
14
|
-
environmentVariables
|
|
16
|
+
localModules,
|
|
17
|
+
environmentVariables,
|
|
18
|
+
featureFlags = {},
|
|
19
|
+
launchDarklyClient
|
|
15
20
|
} = options;
|
|
16
21
|
|
|
17
22
|
const runtime = new StorybookRuntime({
|
|
@@ -20,13 +25,25 @@ export async function initializeFireflyForStorybook(options: InitializeFireflyFo
|
|
|
20
25
|
x => new MswPlugin(x),
|
|
21
26
|
x => new EnvironmentVariablesPlugin(x, {
|
|
22
27
|
variables: environmentVariables
|
|
23
|
-
})
|
|
28
|
+
}),
|
|
29
|
+
x => new LaunchDarklyPlugin(
|
|
30
|
+
x,
|
|
31
|
+
// 1- If no client is provided create it.
|
|
32
|
+
// 2- If feature flags are provided and it's an instance of Map, use the argument.
|
|
33
|
+
// 3- If feature flags are provided (or the default value) and it's an object literal, convert the object to a Map instance.
|
|
34
|
+
launchDarklyClient ?? new InMemoryLaunchDarklyClient(featureFlags instanceof Map
|
|
35
|
+
? featureFlags
|
|
36
|
+
: new Map<string, LDFlagValue>(Object.entries(featureFlags))
|
|
37
|
+
)
|
|
38
|
+
)
|
|
24
39
|
]
|
|
25
40
|
});
|
|
26
41
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
if (localModules && localModules.length > 0) {
|
|
43
|
+
await runtime.moduleManager.registerModules([
|
|
44
|
+
...toLocalModuleDefinitions(localModules)
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
30
47
|
|
|
31
48
|
return runtime;
|
|
32
49
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { LDFlagValue } from "launchdarkly-js-client-sdk";
|
|
2
|
+
import { PropsWithChildren, useLayoutEffect } from "react";
|
|
3
|
+
import { Decorator } from "storybook-react-rsbuild";
|
|
4
|
+
|
|
5
|
+
interface OverrideFeatureFlagsProps extends PropsWithChildren {
|
|
6
|
+
featureFlags: Map<string, LDFlagValue>;
|
|
7
|
+
overrides: Record<string, LDFlagValue>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function OverrideFeatureFlags(props: OverrideFeatureFlagsProps) {
|
|
11
|
+
const {
|
|
12
|
+
featureFlags,
|
|
13
|
+
overrides,
|
|
14
|
+
children
|
|
15
|
+
} = props;
|
|
16
|
+
|
|
17
|
+
// Must use a layout effect to override the feature flags before the story renders.
|
|
18
|
+
useLayoutEffect(() => {
|
|
19
|
+
const originalValues: Record<string, LDFlagValue> = {};
|
|
20
|
+
|
|
21
|
+
Object.entries(overrides).forEach(([key, value]) => {
|
|
22
|
+
originalValues[key] = featureFlags.get(key);
|
|
23
|
+
featureFlags.set(key, value);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
// Reset the feature flags to the original values.
|
|
28
|
+
Object.entries(originalValues).forEach(([key, value]) => {
|
|
29
|
+
featureFlags.set(key, value);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
}, [featureFlags, overrides]);
|
|
33
|
+
|
|
34
|
+
return children;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function withFeatureFlagsOverrideDecorator<const T extends string>(featureFlags: Map<T, LDFlagValue>, overrides: Partial<Record<T, LDFlagValue>>): Decorator {
|
|
38
|
+
if (!(featureFlags instanceof Map)) {
|
|
39
|
+
throw new TypeError("[squide] The \"featureFlags\" argument must be a Map instance.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return story => {
|
|
43
|
+
return (
|
|
44
|
+
<OverrideFeatureFlags featureFlags={featureFlags} overrides={overrides}>
|
|
45
|
+
{story()}
|
|
46
|
+
</OverrideFeatureFlags>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
}
|