@storybook/react-native-ui-lite 9.0.0-beta.11
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/dist/index.d.ts +94 -0
- package/dist/index.js +5437 -0
- package/package.json +80 -0
- package/src/Button.stories.tsx +134 -0
- package/src/Button.tsx +172 -0
- package/src/Explorer.stories.tsx +40 -0
- package/src/Explorer.tsx +38 -0
- package/src/IconButton.tsx +10 -0
- package/src/Layout.stories.tsx +70 -0
- package/src/Layout.tsx +310 -0
- package/src/LayoutProvider.tsx +32 -0
- package/src/MobileAddonsPanel.tsx +195 -0
- package/src/MobileMenuDrawer.tsx +90 -0
- package/src/Refs.tsx +82 -0
- package/src/Search.tsx +234 -0
- package/src/SearchResults.stories.tsx +102 -0
- package/src/SearchResults.tsx +254 -0
- package/src/SelectedNodeProvider.tsx +58 -0
- package/src/Sidebar.stories.tsx +188 -0
- package/src/Sidebar.tsx +131 -0
- package/src/StorageProvider.tsx +21 -0
- package/src/StorybookLogo.stories.tsx +76 -0
- package/src/StorybookLogo.tsx +108 -0
- package/src/Tree.stories.tsx +177 -0
- package/src/Tree.tsx +390 -0
- package/src/TreeNode.stories.tsx +117 -0
- package/src/TreeNode.tsx +154 -0
- package/src/assets/react-native-logo.png +0 -0
- package/src/constants.ts +4 -0
- package/src/hooks/useExpanded.ts +64 -0
- package/src/hooks/useLastViewed.ts +48 -0
- package/src/hooks/useStoreState.ts +27 -0
- package/src/icon/iconDataUris.tsx +365 -0
- package/src/index.tsx +11 -0
- package/src/mockdata.large.ts +25217 -0
- package/src/mockdata.ts +287 -0
- package/src/types.ts +66 -0
- package/src/util/StoryHash.ts +249 -0
- package/src/util/status.tsx +87 -0
- package/src/util/tree.ts +93 -0
- package/src/util/useStyle.ts +28 -0
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@storybook/react-native-ui-lite",
|
|
3
|
+
"version": "9.0.0-beta.11",
|
|
4
|
+
"description": "lightweight ui components for react native storybook",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"react-native",
|
|
8
|
+
"storybook"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://storybook.js.org/",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/storybookjs/react-native/issues"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/storybookjs/react-native.git",
|
|
17
|
+
"directory": "packages/react-native-ui-lite"
|
|
18
|
+
},
|
|
19
|
+
"react-native": "src/index.tsx",
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"types": "src/index.tsx",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist/**/*",
|
|
25
|
+
"README.md",
|
|
26
|
+
"*.js",
|
|
27
|
+
"*.d.ts",
|
|
28
|
+
"src/**/*"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"dev": "tsup --watch",
|
|
32
|
+
"prepare": "tsup",
|
|
33
|
+
"test": "jest --passWithNoTests",
|
|
34
|
+
"test:ci": "jest"
|
|
35
|
+
},
|
|
36
|
+
"jest": {
|
|
37
|
+
"modulePathIgnorePatterns": [
|
|
38
|
+
"dist/"
|
|
39
|
+
],
|
|
40
|
+
"moduleFileExtensions": [
|
|
41
|
+
"ts",
|
|
42
|
+
"tsx",
|
|
43
|
+
"js",
|
|
44
|
+
"jsx",
|
|
45
|
+
"json",
|
|
46
|
+
"node"
|
|
47
|
+
],
|
|
48
|
+
"preset": "react-native"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/jest": "^29.4.3",
|
|
52
|
+
"@types/react": "~19.0.10",
|
|
53
|
+
"babel-jest": "^29.7.0",
|
|
54
|
+
"jest": "^29.7.0",
|
|
55
|
+
"react-test-renderer": "^19.1.0",
|
|
56
|
+
"ts-dedent": "^2.2.0",
|
|
57
|
+
"tsup": "^7.2.0",
|
|
58
|
+
"typescript": "~5.8.3"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@storybook/react": "9.0.0-beta.10",
|
|
62
|
+
"@storybook/react-native-theming": "^9.0.0-beta.11",
|
|
63
|
+
"fuse.js": "^7.0.0",
|
|
64
|
+
"memoizerific": "^1.11.3",
|
|
65
|
+
"polished": "^4.3.1",
|
|
66
|
+
"store2": "^2.14.3"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"react": "*",
|
|
70
|
+
"react-native": ">=0.57.0",
|
|
71
|
+
"storybook": "9.0.0-beta.10"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=18.0.0"
|
|
75
|
+
},
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public"
|
|
78
|
+
},
|
|
79
|
+
"gitHead": "531ed8a758adc98bb436d0ccb32efcb369572ffe"
|
|
80
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { View } from 'react-native';
|
|
5
|
+
|
|
6
|
+
import { Button } from './Button';
|
|
7
|
+
import { FaceHappyIcon } from './icon/iconDataUris';
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'UI/Button',
|
|
11
|
+
component: Button,
|
|
12
|
+
args: {},
|
|
13
|
+
} satisfies Meta<typeof Button>;
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
type Story = StoryObj<typeof meta>;
|
|
17
|
+
|
|
18
|
+
const Stack = ({ children }: { children: ReactNode }) => (
|
|
19
|
+
<View style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>{children}</View>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const Row = ({ children }: { children: ReactNode }) => (
|
|
23
|
+
<View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 16 }}>
|
|
24
|
+
{children}
|
|
25
|
+
</View>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const Base: Story = {};
|
|
29
|
+
|
|
30
|
+
export const Variants: Story = {
|
|
31
|
+
render: (args) => (
|
|
32
|
+
<Stack>
|
|
33
|
+
<Row>
|
|
34
|
+
<Button variant="solid" text="Solid" {...args} />
|
|
35
|
+
<Button variant="outline" text="Outline" {...args} />
|
|
36
|
+
<Button variant="ghost" text="Ghost" {...args} />
|
|
37
|
+
</Row>
|
|
38
|
+
<Row>
|
|
39
|
+
<Button variant="solid" {...args} Icon={FaceHappyIcon} text="Solid" />
|
|
40
|
+
<Button variant="outline" Icon={FaceHappyIcon} text="Outline" {...args} />
|
|
41
|
+
<Button variant="ghost" Icon={FaceHappyIcon} text="Ghost" {...args} />
|
|
42
|
+
</Row>
|
|
43
|
+
<Row>
|
|
44
|
+
<Button variant="solid" padding="small" Icon={FaceHappyIcon} {...args} />
|
|
45
|
+
<Button variant="outline" padding="small" Icon={FaceHappyIcon} {...args} />
|
|
46
|
+
<Button variant="ghost" padding="small" Icon={FaceHappyIcon} {...args} />
|
|
47
|
+
</Row>
|
|
48
|
+
</Stack>
|
|
49
|
+
),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const Active: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
active: true,
|
|
55
|
+
text: 'Button',
|
|
56
|
+
Icon: FaceHappyIcon,
|
|
57
|
+
},
|
|
58
|
+
render: (args) => (
|
|
59
|
+
<Row>
|
|
60
|
+
<Button variant="solid" {...args} />
|
|
61
|
+
<Button variant="outline" {...args} />
|
|
62
|
+
<Button variant="ghost" {...args} />
|
|
63
|
+
</Row>
|
|
64
|
+
),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const WithIcon: Story = {
|
|
68
|
+
args: {
|
|
69
|
+
Icon: FaceHappyIcon,
|
|
70
|
+
text: 'Button',
|
|
71
|
+
},
|
|
72
|
+
render: (args) => (
|
|
73
|
+
<Row>
|
|
74
|
+
<Button variant="solid" {...args} />
|
|
75
|
+
<Button variant="outline" {...args} />
|
|
76
|
+
<Button variant="ghost" {...args} />
|
|
77
|
+
</Row>
|
|
78
|
+
),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const IconOnly: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
padding: 'small',
|
|
84
|
+
Icon: FaceHappyIcon,
|
|
85
|
+
},
|
|
86
|
+
render: (args) => (
|
|
87
|
+
<Row>
|
|
88
|
+
<Button variant="solid" {...args} />
|
|
89
|
+
<Button variant="outline" {...args} />
|
|
90
|
+
<Button variant="ghost" {...args} />
|
|
91
|
+
</Row>
|
|
92
|
+
),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const Sizes: Story = {
|
|
96
|
+
render: () => (
|
|
97
|
+
<Row>
|
|
98
|
+
<Button size="small" text="Small Button" />
|
|
99
|
+
<Button size="medium" text="Medium Button" />
|
|
100
|
+
</Row>
|
|
101
|
+
),
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const Disabled: Story = {
|
|
105
|
+
args: {
|
|
106
|
+
disabled: true,
|
|
107
|
+
text: 'Disabled Button',
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const Animated: Story = {
|
|
112
|
+
args: {
|
|
113
|
+
variant: 'outline',
|
|
114
|
+
},
|
|
115
|
+
render: (args) => (
|
|
116
|
+
<Stack>
|
|
117
|
+
<Row>
|
|
118
|
+
<Button animation="glow" text="Button" {...args} />
|
|
119
|
+
<Button animation="jiggle" text="Button" {...args} />
|
|
120
|
+
<Button animation="rotate360" text="Button" {...args} />
|
|
121
|
+
</Row>
|
|
122
|
+
<Row>
|
|
123
|
+
<Button animation="glow" text="Button" Icon={FaceHappyIcon} {...args} />
|
|
124
|
+
<Button animation="jiggle" text="Button" Icon={FaceHappyIcon} {...args} />
|
|
125
|
+
<Button animation="rotate360" Icon={FaceHappyIcon} text="Button" {...args} />
|
|
126
|
+
</Row>
|
|
127
|
+
<Row>
|
|
128
|
+
<Button animation="glow" padding="small" Icon={FaceHappyIcon} {...args} />
|
|
129
|
+
<Button animation="jiggle" padding="small" Icon={FaceHappyIcon} {...args} />
|
|
130
|
+
<Button animation="rotate360" padding="small" Icon={FaceHappyIcon} {...args} />
|
|
131
|
+
</Row>
|
|
132
|
+
</Stack>
|
|
133
|
+
),
|
|
134
|
+
};
|
package/src/Button.tsx
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { styled, useTheme } from '@storybook/react-native-theming';
|
|
2
|
+
import { ReactElement, forwardRef, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import type { TouchableOpacityProps } from 'react-native';
|
|
4
|
+
import { SvgProps } from 'react-native-svg';
|
|
5
|
+
|
|
6
|
+
export interface ButtonProps extends TouchableOpacityProps {
|
|
7
|
+
asChild?: boolean;
|
|
8
|
+
size?: 'small' | 'medium';
|
|
9
|
+
padding?: 'small' | 'medium';
|
|
10
|
+
variant?: 'outline' | 'solid' | 'ghost';
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
active?: boolean;
|
|
13
|
+
animation?: 'none' | 'rotate360' | 'glow' | 'jiggle';
|
|
14
|
+
text?: string;
|
|
15
|
+
Icon?: (props: SvgProps) => ReactElement;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// TODO fix this type
|
|
19
|
+
export const Button = forwardRef<any, ButtonProps>(
|
|
20
|
+
(
|
|
21
|
+
{
|
|
22
|
+
Icon,
|
|
23
|
+
animation = 'none',
|
|
24
|
+
size = 'small',
|
|
25
|
+
variant = 'outline',
|
|
26
|
+
padding = 'medium',
|
|
27
|
+
disabled = false,
|
|
28
|
+
active = false,
|
|
29
|
+
onPress,
|
|
30
|
+
children,
|
|
31
|
+
text,
|
|
32
|
+
...props
|
|
33
|
+
}: ButtonProps,
|
|
34
|
+
ref
|
|
35
|
+
) => {
|
|
36
|
+
// let Comp: 'button' | 'a' | typeof Slot = 'button';
|
|
37
|
+
// if (props.isLink) Comp = 'a';
|
|
38
|
+
// if (asChild) Comp = Slot;
|
|
39
|
+
// let localVariant = variant;
|
|
40
|
+
// let localSize = size;
|
|
41
|
+
|
|
42
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
43
|
+
|
|
44
|
+
const handleClick = (event) => {
|
|
45
|
+
if (onPress) onPress(event);
|
|
46
|
+
if (animation === 'none') return;
|
|
47
|
+
setIsAnimating(true);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const timer = setTimeout(() => {
|
|
52
|
+
if (isAnimating) setIsAnimating(false);
|
|
53
|
+
}, 1000);
|
|
54
|
+
return () => clearTimeout(timer);
|
|
55
|
+
}, [isAnimating]);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<StyledButton
|
|
59
|
+
ref={ref}
|
|
60
|
+
variant={variant}
|
|
61
|
+
size={size}
|
|
62
|
+
padding={padding}
|
|
63
|
+
disabled={disabled}
|
|
64
|
+
active={active}
|
|
65
|
+
animating={isAnimating}
|
|
66
|
+
animation={animation}
|
|
67
|
+
onPress={handleClick}
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
{Icon && <ButtonIcon Icon={Icon} variant={variant} active={active} />}
|
|
71
|
+
{text && (
|
|
72
|
+
<ButtonText variant={variant} active={active}>
|
|
73
|
+
{text}
|
|
74
|
+
</ButtonText>
|
|
75
|
+
)}
|
|
76
|
+
{children}
|
|
77
|
+
</StyledButton>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
Button.displayName = 'Button';
|
|
83
|
+
|
|
84
|
+
const StyledButton = styled.TouchableOpacity<
|
|
85
|
+
ButtonProps & { animating: boolean; animation: ButtonProps['animation'] }
|
|
86
|
+
>(({ theme, variant, size, disabled, active, padding }) => ({
|
|
87
|
+
border: 0,
|
|
88
|
+
// cursor: disabled ? 'not-allowed' : 'pointer',
|
|
89
|
+
display: 'flex',
|
|
90
|
+
flexDirection: 'row',
|
|
91
|
+
gap: 6,
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
justifyContent: 'center',
|
|
94
|
+
overflow: 'hidden',
|
|
95
|
+
paddingHorizontal: (() => {
|
|
96
|
+
if (padding === 'small' && size === 'small') return 7;
|
|
97
|
+
if (padding === 'small' && size === 'medium') return 9;
|
|
98
|
+
if (size === 'small') return 10;
|
|
99
|
+
if (size === 'medium') return 12;
|
|
100
|
+
return 0;
|
|
101
|
+
})(),
|
|
102
|
+
paddingVertical: 0,
|
|
103
|
+
height: size === 'small' ? 28 : 32,
|
|
104
|
+
position: 'relative',
|
|
105
|
+
transitionProperty: 'background, box-shadow',
|
|
106
|
+
transitionDuration: '150ms',
|
|
107
|
+
transitionTimingFunction: 'ease-out',
|
|
108
|
+
whiteSpace: 'nowrap',
|
|
109
|
+
userSelect: 'none',
|
|
110
|
+
opacity: disabled ? 0.5 : 1,
|
|
111
|
+
margin: 0,
|
|
112
|
+
|
|
113
|
+
backgroundColor: (() => {
|
|
114
|
+
if (variant === 'solid') return theme.color.secondary;
|
|
115
|
+
if (variant === 'outline') return theme.button.background;
|
|
116
|
+
if (variant === 'ghost' && active) return theme.background.hoverable;
|
|
117
|
+
|
|
118
|
+
return 'transparent';
|
|
119
|
+
})(),
|
|
120
|
+
|
|
121
|
+
boxShadow: variant === 'outline' ? `${theme.button.border} 0 0 0 1px inset` : 'none',
|
|
122
|
+
borderRadius: theme.input.borderRadius,
|
|
123
|
+
// Making sure that the button never shrinks below its minimum size
|
|
124
|
+
flexShrink: 0,
|
|
125
|
+
}));
|
|
126
|
+
|
|
127
|
+
export const ButtonText = styled.Text<{
|
|
128
|
+
variant: ButtonProps['variant'];
|
|
129
|
+
active: ButtonProps['active'];
|
|
130
|
+
}>(({ theme, variant, active }) => ({
|
|
131
|
+
color: (() => {
|
|
132
|
+
if (variant === 'solid') return theme.color.lightest;
|
|
133
|
+
if (variant === 'outline') return theme.input.color;
|
|
134
|
+
if (variant === 'ghost' && active) return theme.color.secondary;
|
|
135
|
+
if (variant === 'ghost') return theme.color.mediumdark;
|
|
136
|
+
return theme.input.color;
|
|
137
|
+
})(),
|
|
138
|
+
flexDirection: 'row',
|
|
139
|
+
gap: 6,
|
|
140
|
+
textAlign: 'center',
|
|
141
|
+
fontSize: theme.typography.size.s1,
|
|
142
|
+
fontWeight: theme.typography.weight.bold,
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
export const ButtonIcon = ({
|
|
146
|
+
Icon,
|
|
147
|
+
active,
|
|
148
|
+
variant,
|
|
149
|
+
}: {
|
|
150
|
+
Icon: (props: SvgProps) => ReactElement;
|
|
151
|
+
variant: ButtonProps['variant'];
|
|
152
|
+
active: ButtonProps['active'];
|
|
153
|
+
}) => {
|
|
154
|
+
const theme = useTheme();
|
|
155
|
+
|
|
156
|
+
const color = useMemo(() => {
|
|
157
|
+
if (variant === 'solid') return theme.color.lightest;
|
|
158
|
+
if (variant === 'outline') return theme.input.color;
|
|
159
|
+
if (variant === 'ghost' && active) return theme.color.secondary;
|
|
160
|
+
if (variant === 'ghost') return theme.color.mediumdark;
|
|
161
|
+
return theme.input.color;
|
|
162
|
+
}, [
|
|
163
|
+
active,
|
|
164
|
+
theme.color.lightest,
|
|
165
|
+
theme.color.mediumdark,
|
|
166
|
+
theme.color.secondary,
|
|
167
|
+
theme.input.color,
|
|
168
|
+
variant,
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
return <Icon color={color} />;
|
|
172
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Explorer } from './Explorer';
|
|
2
|
+
import { mockDataset } from './mockdata';
|
|
3
|
+
import type { RefType } from './types';
|
|
4
|
+
import { View } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
component: Explorer,
|
|
8
|
+
title: 'UI/Sidebar/Explorer',
|
|
9
|
+
parameters: { layout: 'fullscreen', theme: 'side-by-side' },
|
|
10
|
+
decorators: [
|
|
11
|
+
(storyFn: any) => <View style={{ paddingHorizontal: 20 }}>{storyFn()}</View>,
|
|
12
|
+
(storyFn: any) => <View style={{ paddingHorizontal: 20 }}>{storyFn()}</View>,
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const selected = {
|
|
17
|
+
refId: 'storybook_internal',
|
|
18
|
+
storyId: 'root-1-child-a2--grandchild-a1-1',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const simple: Record<string, RefType> = {
|
|
22
|
+
storybook_internal: {
|
|
23
|
+
title: undefined,
|
|
24
|
+
id: 'storybook_internal',
|
|
25
|
+
url: 'iframe.html',
|
|
26
|
+
previewInitialized: true,
|
|
27
|
+
// @ts-expect-error (invalid input)
|
|
28
|
+
index: mockDataset.withRoot,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Simple = () => (
|
|
33
|
+
<Explorer
|
|
34
|
+
dataset={{ hash: simple, entries: Object.entries(simple) }}
|
|
35
|
+
selected={selected}
|
|
36
|
+
isLoading={false}
|
|
37
|
+
isBrowsing
|
|
38
|
+
setSelection={() => {}}
|
|
39
|
+
/>
|
|
40
|
+
);
|
package/src/Explorer.tsx
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import React, { useRef } from 'react';
|
|
3
|
+
import { Ref } from './Refs';
|
|
4
|
+
import type { CombinedDataset, Selection } from './types';
|
|
5
|
+
import { View } from 'react-native';
|
|
6
|
+
|
|
7
|
+
export interface ExplorerProps {
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
isBrowsing: boolean;
|
|
10
|
+
dataset: CombinedDataset;
|
|
11
|
+
selected: Selection;
|
|
12
|
+
setSelection: (selection: Selection) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const Explorer: FC<ExplorerProps> = React.memo(function Explorer({
|
|
16
|
+
isLoading,
|
|
17
|
+
isBrowsing,
|
|
18
|
+
dataset,
|
|
19
|
+
selected,
|
|
20
|
+
setSelection,
|
|
21
|
+
}) {
|
|
22
|
+
const containerRef = useRef<View>(null);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<View ref={containerRef} id="storybook-explorer-tree">
|
|
26
|
+
{dataset.entries.map(([refId, ref]) => (
|
|
27
|
+
<Ref
|
|
28
|
+
{...ref}
|
|
29
|
+
key={refId}
|
|
30
|
+
isLoading={isLoading}
|
|
31
|
+
isBrowsing={isBrowsing}
|
|
32
|
+
selectedStoryId={selected?.refId === ref.id ? selected.storyId : null}
|
|
33
|
+
setSelection={setSelection}
|
|
34
|
+
/>
|
|
35
|
+
))}
|
|
36
|
+
</View>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Button, ButtonProps } from './Button';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
|
|
4
|
+
export const IconButton = forwardRef(
|
|
5
|
+
({ padding = 'small', variant = 'ghost', ...props }: ButtonProps, ref) => {
|
|
6
|
+
return <Button padding={padding} variant={variant} ref={ref} {...props} />;
|
|
7
|
+
}
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
IconButton.displayName = 'IconButton';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
// import { Layout } from './Layout';
|
|
3
|
+
// import { mockDataset } from './mockdata';
|
|
4
|
+
// import { Text, View } from 'react-native';
|
|
5
|
+
// import { LayoutProvider } from './LayoutProvider';
|
|
6
|
+
|
|
7
|
+
// const meta = {
|
|
8
|
+
// component: Layout,
|
|
9
|
+
// decorators: [
|
|
10
|
+
// (Story) => (
|
|
11
|
+
// <LayoutProvider>
|
|
12
|
+
// <Story />
|
|
13
|
+
// </LayoutProvider>
|
|
14
|
+
// ),
|
|
15
|
+
// ],
|
|
16
|
+
// } satisfies Meta<typeof Layout>;
|
|
17
|
+
|
|
18
|
+
// export default meta;
|
|
19
|
+
|
|
20
|
+
// type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
// export const Basic: Story = {
|
|
23
|
+
// args: {
|
|
24
|
+
// children: <Text>Testing</Text>,
|
|
25
|
+
// //@ts-ignore
|
|
26
|
+
// storyHash: mockDataset.withRoot,
|
|
27
|
+
// storyId: 'emails-buildnotification--with-changes',
|
|
28
|
+
// },
|
|
29
|
+
// };
|
|
30
|
+
|
|
31
|
+
// export const OverflowSidebarExample: Story = {
|
|
32
|
+
// args: {
|
|
33
|
+
// children: (
|
|
34
|
+
// <View
|
|
35
|
+
// style={{
|
|
36
|
+
// width: '100%',
|
|
37
|
+
// backgroundColor: 'lightgreen',
|
|
38
|
+
// alignItems: 'flex-end',
|
|
39
|
+
// left: '-50%',
|
|
40
|
+
// }}
|
|
41
|
+
// >
|
|
42
|
+
// <Text style={{ width: '50%', textAlign: 'right' }}>
|
|
43
|
+
// This box should not overflow the side navigation in desktop mode
|
|
44
|
+
// </Text>
|
|
45
|
+
// </View>
|
|
46
|
+
// ),
|
|
47
|
+
// //@ts-ignore
|
|
48
|
+
// storyHash: mockDataset.withRoot,
|
|
49
|
+
// storyId: 'emails-buildnotification--with-changes',
|
|
50
|
+
// },
|
|
51
|
+
// };
|
|
52
|
+
|
|
53
|
+
// export const OverflowAddonsExample: Story = {
|
|
54
|
+
// args: {
|
|
55
|
+
// children: (
|
|
56
|
+
// <View
|
|
57
|
+
// style={{
|
|
58
|
+
// height: '100%',
|
|
59
|
+
// backgroundColor: 'lightgreen',
|
|
60
|
+
// bottom: '-50%',
|
|
61
|
+
// }}
|
|
62
|
+
// >
|
|
63
|
+
// <Text style={{ height: '50%' }}>This box should not overflow the addons panel</Text>
|
|
64
|
+
// </View>
|
|
65
|
+
// ),
|
|
66
|
+
// //@ts-ignore
|
|
67
|
+
// storyHash: mockDataset.withRoot,
|
|
68
|
+
// storyId: 'emails-buildnotification--with-changes',
|
|
69
|
+
// },
|
|
70
|
+
// };
|