@fluentui-react-native/storybook-desktop-runtime 0.2.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/.cache/tsconfig.tsbuildinfo +1 -0
- package/CHANGELOG.md +25 -0
- package/README.md +21 -0
- package/config/metro.cjs +125 -0
- package/config/react-native-safe-area-context.cjs +22 -0
- package/lib/DesktopDriverBridge.d.ts +7 -0
- package/lib/DesktopDriverBridge.d.ts.map +1 -0
- package/lib/DesktopDriverBridge.js +52 -0
- package/lib/DesktopDriverBridge.js.map +1 -0
- package/lib/DesktopStoryRoot.d.ts +8 -0
- package/lib/DesktopStoryRoot.d.ts.map +1 -0
- package/lib/DesktopStoryRoot.js +57 -0
- package/lib/DesktopStoryRoot.js.map +1 -0
- package/lib/DesktopStorybookConfig.d.ts +28 -0
- package/lib/DesktopStorybookConfig.d.ts.map +1 -0
- package/lib/DesktopStorybookConfig.js +23 -0
- package/lib/DesktopStorybookConfig.js.map +1 -0
- package/lib/StorybookTheme.d.ts +4 -0
- package/lib/StorybookTheme.d.ts.map +1 -0
- package/lib/StorybookTheme.js +79 -0
- package/lib/StorybookTheme.js.map +1 -0
- package/lib/StorybookUI.d.ts +2 -0
- package/lib/StorybookUI.d.ts.map +1 -0
- package/lib/StorybookUI.js +2 -0
- package/lib/StorybookUI.js.map +1 -0
- package/lib/StorybookUI.win32.d.ts +3 -0
- package/lib/StorybookUI.win32.d.ts.map +1 -0
- package/lib/StorybookUI.win32.js +171 -0
- package/lib/StorybookUI.win32.js.map +1 -0
- package/lib/Win32AddonsPanel.d.ts +9 -0
- package/lib/Win32AddonsPanel.d.ts.map +1 -0
- package/lib/Win32AddonsPanel.js +72 -0
- package/lib/Win32AddonsPanel.js.map +1 -0
- package/lib/Win32CalloutPortal.d.ts +16 -0
- package/lib/Win32CalloutPortal.d.ts.map +1 -0
- package/lib/Win32CalloutPortal.js +17 -0
- package/lib/Win32CalloutPortal.js.map +1 -0
- package/lib/Win32ResizeHandle.d.ts +8 -0
- package/lib/Win32ResizeHandle.d.ts.map +1 -0
- package/lib/Win32ResizeHandle.js +46 -0
- package/lib/Win32ResizeHandle.js.map +1 -0
- package/lib/createDesktopStorybookApp.d.ts +9 -0
- package/lib/createDesktopStorybookApp.d.ts.map +1 -0
- package/lib/createDesktopStorybookApp.js +38 -0
- package/lib/createDesktopStorybookApp.js.map +1 -0
- package/lib/createDesktopStorybookPreview.d.ts +3 -0
- package/lib/createDesktopStorybookPreview.d.ts.map +1 -0
- package/lib/createDesktopStorybookPreview.js +21 -0
- package/lib/createDesktopStorybookPreview.js.map +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -0
- package/package.json +106 -0
- package/src/DesktopDriverBridge.tsx +66 -0
- package/src/DesktopStoryRoot.tsx +88 -0
- package/src/DesktopStorybookConfig.tsx +58 -0
- package/src/StorybookTheme.tsx +114 -0
- package/src/StorybookUI.ts +1 -0
- package/src/StorybookUI.win32.tsx +330 -0
- package/src/Win32AddonsPanel.tsx +135 -0
- package/src/Win32CalloutPortal.tsx +73 -0
- package/src/Win32ResizeHandle.tsx +67 -0
- package/src/createDesktopStorybookApp.tsx +72 -0
- package/src/createDesktopStorybookPreview.tsx +31 -0
- package/src/index.ts +12 -0
- package/tsconfig.json +24 -0
package/package.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluentui-react-native/storybook-desktop-runtime",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "React Native runtime and Metro services for desktop Storybook applications",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/microsoft/fluentui-react-native.git",
|
|
10
|
+
"directory": "packages/agentic/storybook-desktop-runtime"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "lib/index.js",
|
|
14
|
+
"module": "lib/index.js",
|
|
15
|
+
"types": "lib/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/index.d.ts",
|
|
19
|
+
"react-native": "./src/index.ts",
|
|
20
|
+
"import": "./lib/index.js",
|
|
21
|
+
"default": "./src/index.ts"
|
|
22
|
+
},
|
|
23
|
+
"./metro": "./config/metro.cjs",
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -b",
|
|
28
|
+
"clean": "fluentui-scripts clean",
|
|
29
|
+
"format": "fluentui-scripts format",
|
|
30
|
+
"lint": "fluentui-scripts lint"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@fluentui-react-native/callout": "0.29.4",
|
|
34
|
+
"@fluentui-react-native/default-theme": "0.27.11",
|
|
35
|
+
"@fluentui-react-native/design": "0.4.0",
|
|
36
|
+
"@rnx-kit/metro-config": "^2.2.4",
|
|
37
|
+
"@rnx-kit/metro-resolver-symlinks": "^0.3.1",
|
|
38
|
+
"@storybook/react-native": "^10.4.7",
|
|
39
|
+
"@storybook/react-native-theming": "^10.4.7",
|
|
40
|
+
"@storybook/react-native-ui-common": "^10.4.7",
|
|
41
|
+
"@storybook/react-native-ui-lite": "^10.4.7",
|
|
42
|
+
"oxc-resolver": "^11.24.0",
|
|
43
|
+
"storybook": "^10.4.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@babel/core": "^7.20.0",
|
|
47
|
+
"@fluentui-react-native/scripts": "0.1.0",
|
|
48
|
+
"@office-iss/react-native-win32": "^0.81.0",
|
|
49
|
+
"@react-native/babel-preset": "^0.81.0",
|
|
50
|
+
"@types/react": "~19.1.4",
|
|
51
|
+
"react": "19.1.4",
|
|
52
|
+
"react-native": "^0.81.6",
|
|
53
|
+
"react-native-macos": "^0.81.0",
|
|
54
|
+
"react-native-windows": "^0.81.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@office-iss/react-native-win32": "^0.81.0",
|
|
58
|
+
"@types/react": "~19.1.4",
|
|
59
|
+
"react": "19.1.4",
|
|
60
|
+
"react-native": "^0.81.6",
|
|
61
|
+
"react-native-macos": "^0.81.0",
|
|
62
|
+
"react-native-windows": "^0.81.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@office-iss/react-native-win32": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"@types/react": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"react-native-macos": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"react-native-windows": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"furn": {
|
|
79
|
+
"knip": {
|
|
80
|
+
"ignoreDependencies": [
|
|
81
|
+
"@fluentui-react-native/callout"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"rnx-kit": {
|
|
86
|
+
"kitType": "library",
|
|
87
|
+
"alignDeps": {
|
|
88
|
+
"requirements": {
|
|
89
|
+
"development": [
|
|
90
|
+
"react-native@0.81"
|
|
91
|
+
],
|
|
92
|
+
"production": [
|
|
93
|
+
"react-native@0.81"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"capabilities": [
|
|
97
|
+
"babel-preset-react-native",
|
|
98
|
+
"core",
|
|
99
|
+
"core-macos",
|
|
100
|
+
"core-win32",
|
|
101
|
+
"core-windows"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
"extends": "@fluentui-react-native/scripts/kit-config"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { addons } from 'storybook/preview-api';
|
|
3
|
+
|
|
4
|
+
import { useDesktopStorybookConfig } from './DesktopStorybookConfig';
|
|
5
|
+
|
|
6
|
+
export const desktopPrepareStoryEvent = 'furn:desktop:prepare-story';
|
|
7
|
+
export const desktopRequestHelloEvent = 'furn:desktop:request-hello';
|
|
8
|
+
export const desktopRuntimeHelloEvent = 'furn:desktop:hello';
|
|
9
|
+
export const desktopStoryErrorEvent = 'furn:desktop:story-error';
|
|
10
|
+
export const desktopStoryReadyEvent = 'furn:desktop:story-ready';
|
|
11
|
+
|
|
12
|
+
type PrepareStoryPayload = {
|
|
13
|
+
requestId: string;
|
|
14
|
+
runId: string;
|
|
15
|
+
storyId: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function DesktopDriverBridge(): null {
|
|
19
|
+
const { prepareStory, runtimeInstance } = useDesktopStorybookConfig();
|
|
20
|
+
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
if (
|
|
23
|
+
!runtimeInstance?.bridgeNonce ||
|
|
24
|
+
!runtimeInstance.endpoint ||
|
|
25
|
+
!runtimeInstance.instanceId ||
|
|
26
|
+
!runtimeInstance.platformManifestDigest ||
|
|
27
|
+
!runtimeInstance.targetId
|
|
28
|
+
) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const channel = addons.getChannel();
|
|
32
|
+
const emitHello = () => {
|
|
33
|
+
channel.emit(desktopRuntimeHelloEvent, {
|
|
34
|
+
endpoint: runtimeInstance.endpoint,
|
|
35
|
+
instanceId: runtimeInstance.instanceId,
|
|
36
|
+
nonce: runtimeInstance.bridgeNonce,
|
|
37
|
+
platformManifestDigest: runtimeInstance.platformManifestDigest,
|
|
38
|
+
targetId: runtimeInstance.targetId,
|
|
39
|
+
version: 1,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const onPrepare = (payload: PrepareStoryPayload) => {
|
|
43
|
+
if (isPrepareStoryPayload(payload)) {
|
|
44
|
+
prepareStory(payload);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
channel.on(desktopPrepareStoryEvent, onPrepare);
|
|
49
|
+
channel.on(desktopRequestHelloEvent, emitHello);
|
|
50
|
+
emitHello();
|
|
51
|
+
return () => {
|
|
52
|
+
channel.off(desktopPrepareStoryEvent, onPrepare);
|
|
53
|
+
channel.off(desktopRequestHelloEvent, emitHello);
|
|
54
|
+
};
|
|
55
|
+
}, [prepareStory, runtimeInstance]);
|
|
56
|
+
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isPrepareStoryPayload(value: unknown): value is PrepareStoryPayload {
|
|
61
|
+
if (!value || typeof value !== 'object') {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const payload = value as Record<string, unknown>;
|
|
65
|
+
return typeof payload.requestId === 'string' && typeof payload.runId === 'string' && typeof payload.storyId === 'string';
|
|
66
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import { addons } from 'storybook/preview-api';
|
|
4
|
+
|
|
5
|
+
import { desktopStoryErrorEvent, desktopStoryReadyEvent } from './DesktopDriverBridge';
|
|
6
|
+
import { useDesktopStorybookConfig, useDesktopStorybookTestID } from './DesktopStorybookConfig';
|
|
7
|
+
|
|
8
|
+
type DesktopStoryRootProps = {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
storyId: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function DesktopStoryRoot({ children, storyId }: DesktopStoryRootProps) {
|
|
14
|
+
const { runtimeInstance, selection } = useDesktopStorybookConfig();
|
|
15
|
+
const testID = useDesktopStorybookTestID('story-root');
|
|
16
|
+
const activeSelection = selection?.storyId === storyId ? selection : undefined;
|
|
17
|
+
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
if (!activeSelection || !runtimeInstance?.portablePlanDigest) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
addons.getChannel().emit(desktopStoryReadyEvent, {
|
|
23
|
+
portablePlanDigest: runtimeInstance.portablePlanDigest,
|
|
24
|
+
previewGeneration: activeSelection.previewGeneration,
|
|
25
|
+
requestId: activeSelection.requestId,
|
|
26
|
+
runId: activeSelection.runId,
|
|
27
|
+
storyId,
|
|
28
|
+
});
|
|
29
|
+
}, [activeSelection, runtimeInstance?.portablePlanDigest, storyId]);
|
|
30
|
+
|
|
31
|
+
const marker = JSON.stringify({
|
|
32
|
+
previewGeneration: activeSelection?.previewGeneration ?? 0,
|
|
33
|
+
runId: activeSelection?.runId,
|
|
34
|
+
storyId,
|
|
35
|
+
});
|
|
36
|
+
const key = activeSelection ? `${activeSelection.runId}:${activeSelection.previewGeneration}` : storyId;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<StoryRenderErrorBoundary
|
|
40
|
+
key={key}
|
|
41
|
+
onError={(message) => {
|
|
42
|
+
if (activeSelection) {
|
|
43
|
+
addons.getChannel().emit(desktopStoryErrorEvent, {
|
|
44
|
+
message,
|
|
45
|
+
requestId: activeSelection.requestId,
|
|
46
|
+
runId: activeSelection.runId,
|
|
47
|
+
storyId,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<View accessibilityLabel={marker} style={styles.root} testID={testID}>
|
|
53
|
+
{children}
|
|
54
|
+
</View>
|
|
55
|
+
</StoryRenderErrorBoundary>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type StoryRenderErrorBoundaryProps = {
|
|
60
|
+
children: React.ReactNode;
|
|
61
|
+
onError(message: string): void;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type StoryRenderErrorBoundaryState = {
|
|
65
|
+
error?: Error;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
class StoryRenderErrorBoundary extends React.Component<StoryRenderErrorBoundaryProps, StoryRenderErrorBoundaryState> {
|
|
69
|
+
override state: StoryRenderErrorBoundaryState = {};
|
|
70
|
+
|
|
71
|
+
static getDerivedStateFromError(error: Error): StoryRenderErrorBoundaryState {
|
|
72
|
+
return { error };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override componentDidCatch(error: Error): void {
|
|
76
|
+
this.props.onError(error.message);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
override render(): React.ReactNode {
|
|
80
|
+
return this.state.error ? null : this.props.children;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const styles = StyleSheet.create({
|
|
85
|
+
root: {
|
|
86
|
+
flex: 1,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export type DesktopRuntimeSelection = {
|
|
4
|
+
previewGeneration: number;
|
|
5
|
+
requestId: string;
|
|
6
|
+
runId: string;
|
|
7
|
+
storyId: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type DesktopStorybookRuntimeInstance = {
|
|
11
|
+
bridgeNonce?: string;
|
|
12
|
+
endpoint?: 'macos' | 'windows' | 'win32';
|
|
13
|
+
instanceId?: string;
|
|
14
|
+
platformManifestDigest?: string;
|
|
15
|
+
portablePlanDigest?: string;
|
|
16
|
+
storybookPort?: number;
|
|
17
|
+
targetId?: string;
|
|
18
|
+
testIDPrefix?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type DesktopStorybookConfig = {
|
|
22
|
+
prepareStory(selection: Omit<DesktopRuntimeSelection, 'previewGeneration'>): void;
|
|
23
|
+
runtimeInstance?: DesktopStorybookRuntimeInstance;
|
|
24
|
+
selection?: DesktopRuntimeSelection;
|
|
25
|
+
testIDPrefix: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const defaultConfig: DesktopStorybookConfig = {
|
|
29
|
+
prepareStory: () => undefined,
|
|
30
|
+
testIDPrefix: 'storybook-desktop',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DesktopStorybookConfigContext = React.createContext<DesktopStorybookConfig>(defaultConfig);
|
|
34
|
+
|
|
35
|
+
export function DesktopStorybookConfigProvider({
|
|
36
|
+
children,
|
|
37
|
+
runtimeInstance,
|
|
38
|
+
testIDPrefix,
|
|
39
|
+
}: React.PropsWithChildren<Pick<DesktopStorybookConfig, 'runtimeInstance' | 'testIDPrefix'>>) {
|
|
40
|
+
const [selection, setSelection] = React.useState<DesktopRuntimeSelection>();
|
|
41
|
+
const prepareStory = React.useCallback((next: Omit<DesktopRuntimeSelection, 'previewGeneration'>) => {
|
|
42
|
+
setSelection((current) => ({ ...next, previewGeneration: (current?.previewGeneration ?? 0) + 1 }));
|
|
43
|
+
}, []);
|
|
44
|
+
const value = React.useMemo(
|
|
45
|
+
() => ({ prepareStory, runtimeInstance, selection, testIDPrefix }),
|
|
46
|
+
[prepareStory, runtimeInstance, selection, testIDPrefix],
|
|
47
|
+
);
|
|
48
|
+
return <DesktopStorybookConfigContext.Provider value={value}>{children}</DesktopStorybookConfigContext.Provider>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function useDesktopStorybookConfig(): DesktopStorybookConfig {
|
|
52
|
+
return React.useContext(DesktopStorybookConfigContext);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function useDesktopStorybookTestID(suffix: string): string {
|
|
56
|
+
const { testIDPrefix } = useDesktopStorybookConfig();
|
|
57
|
+
return `${testIDPrefix}-${suffix}`;
|
|
58
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { createDefaultTheme } from '@fluentui-react-native/default-theme';
|
|
5
|
+
import { ThemeProvider } from '@fluentui-react-native/design/theming';
|
|
6
|
+
import type { ThemeReference } from '@fluentui-react-native/design/theming';
|
|
7
|
+
|
|
8
|
+
import { useDesktopStorybookTestID } from './DesktopStorybookConfig';
|
|
9
|
+
|
|
10
|
+
type ThemeChoice = {
|
|
11
|
+
label: string;
|
|
12
|
+
theme?: ThemeReference;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const themeChoiceNames = ['none', 'light', 'dark', 'highContrast'] as const;
|
|
16
|
+
type ThemeChoiceName = (typeof themeChoiceNames)[number];
|
|
17
|
+
|
|
18
|
+
const themeChoices: Record<ThemeChoiceName, ThemeChoice> = {
|
|
19
|
+
none: { label: 'No theme' },
|
|
20
|
+
light: { label: 'Light', theme: createDefaultTheme({ appearance: 'light' }) },
|
|
21
|
+
dark: { label: 'Dark', theme: createDefaultTheme({ appearance: 'dark' }) },
|
|
22
|
+
highContrast: { label: 'High contrast', theme: createDefaultTheme({ appearance: 'highContrast' }) },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const StorybookThemeContext = React.createContext<ThemeReference | undefined>(undefined);
|
|
26
|
+
|
|
27
|
+
export function StorybookThemeHost({ children }: React.PropsWithChildren) {
|
|
28
|
+
const [selectedName, setSelectedName] = React.useState<ThemeChoiceName>('none');
|
|
29
|
+
const selectedTheme = themeChoices[selectedName].theme;
|
|
30
|
+
const toolbarTestID = useDesktopStorybookTestID('theme-toolbar');
|
|
31
|
+
const optionTestID = useDesktopStorybookTestID('theme');
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<StorybookThemeContext.Provider value={selectedTheme}>
|
|
35
|
+
<View style={styles.root}>
|
|
36
|
+
<View accessibilityRole="toolbar" style={styles.header} testID={toolbarTestID}>
|
|
37
|
+
<Text style={styles.label}>Theme</Text>
|
|
38
|
+
{themeChoiceNames.map((name) => {
|
|
39
|
+
const choice = themeChoices[name];
|
|
40
|
+
const selected = name === selectedName;
|
|
41
|
+
return (
|
|
42
|
+
<Pressable
|
|
43
|
+
accessibilityRole="button"
|
|
44
|
+
accessibilityState={{ selected }}
|
|
45
|
+
key={name}
|
|
46
|
+
onPress={() => setSelectedName(name)}
|
|
47
|
+
style={({ pressed }) => [styles.option, selected && styles.selectedOption, pressed && styles.pressedOption]}
|
|
48
|
+
testID={`${optionTestID}-${name}`}
|
|
49
|
+
>
|
|
50
|
+
<Text style={[styles.optionText, selected && styles.selectedOptionText]}>{choice.label}</Text>
|
|
51
|
+
</Pressable>
|
|
52
|
+
);
|
|
53
|
+
})}
|
|
54
|
+
</View>
|
|
55
|
+
<View style={styles.storybook}>{children}</View>
|
|
56
|
+
</View>
|
|
57
|
+
</StorybookThemeContext.Provider>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function StorybookThemeProvider({ children }: React.PropsWithChildren) {
|
|
62
|
+
const theme = React.useContext(StorybookThemeContext);
|
|
63
|
+
return theme ? <ThemeProvider theme={theme}>{children}</ThemeProvider> : children;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const styles = StyleSheet.create({
|
|
67
|
+
root: {
|
|
68
|
+
flex: 1,
|
|
69
|
+
},
|
|
70
|
+
header: {
|
|
71
|
+
alignItems: 'center',
|
|
72
|
+
backgroundColor: '#f5f5f5',
|
|
73
|
+
borderBottomColor: '#d1d1d1',
|
|
74
|
+
borderBottomWidth: 1,
|
|
75
|
+
flexDirection: 'row',
|
|
76
|
+
flexWrap: 'wrap',
|
|
77
|
+
gap: 8,
|
|
78
|
+
minHeight: 44,
|
|
79
|
+
paddingHorizontal: 12,
|
|
80
|
+
paddingVertical: 6,
|
|
81
|
+
},
|
|
82
|
+
label: {
|
|
83
|
+
color: '#242424',
|
|
84
|
+
fontSize: 14,
|
|
85
|
+
fontWeight: '600',
|
|
86
|
+
marginEnd: 4,
|
|
87
|
+
},
|
|
88
|
+
option: {
|
|
89
|
+
backgroundColor: '#ffffff',
|
|
90
|
+
borderColor: '#b3b3b3',
|
|
91
|
+
borderRadius: 4,
|
|
92
|
+
borderWidth: 1,
|
|
93
|
+
paddingHorizontal: 10,
|
|
94
|
+
paddingVertical: 5,
|
|
95
|
+
},
|
|
96
|
+
selectedOption: {
|
|
97
|
+
backgroundColor: '#0f6cbd',
|
|
98
|
+
borderColor: '#0f6cbd',
|
|
99
|
+
},
|
|
100
|
+
pressedOption: {
|
|
101
|
+
opacity: 0.75,
|
|
102
|
+
},
|
|
103
|
+
optionText: {
|
|
104
|
+
color: '#242424',
|
|
105
|
+
fontSize: 12,
|
|
106
|
+
},
|
|
107
|
+
selectedOptionText: {
|
|
108
|
+
color: '#ffffff',
|
|
109
|
+
fontWeight: '600',
|
|
110
|
+
},
|
|
111
|
+
storybook: {
|
|
112
|
+
flex: 1,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LiteUI as StorybookUIComponent } from '@storybook/react-native-ui-lite';
|