@storybook/react-native 6.5.4-alpha.0 → 6.5.5-alpha.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/dist/hooks.d.ts +3 -1
- package/dist/hooks.js +22 -3
- package/dist/preview/components/Shared/icons.d.ts +3 -0
- package/dist/preview/components/Shared/icons.js +3 -0
- package/dist/preview/components/StoryListView/StoryListView.js +54 -46
- package/dist/preview/components/StoryListView/getNestedStories.d.ts +10 -0
- package/dist/preview/components/StoryListView/getNestedStories.js +95 -0
- package/dist/preview/components/StoryListView/getNestedStories.test.d.ts +1 -0
- package/dist/preview/components/StoryListView/getNestedStories.test.js +237 -0
- package/dist/preview/start.js +1 -1
- package/package.json +6 -2
- package/readme.md +97 -55
package/dist/hooks.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { StoryContext } from '@storybook/csf';
|
|
2
2
|
import type { Theme } from './preview/components/Shared/theme';
|
|
3
3
|
import type { ReactNativeFramework } from './types/types-6.0';
|
|
4
|
+
import { StoryIndexEntry } from '@storybook/client-api';
|
|
4
5
|
/**
|
|
5
6
|
* Hook that returns a function to set the current story context.
|
|
6
7
|
*/
|
|
@@ -18,9 +19,10 @@ export declare function useStoryContextParam<T = any>(name: string, defaultValue
|
|
|
18
19
|
*/
|
|
19
20
|
export declare function useIsStorySelected(storyId: string): boolean;
|
|
20
21
|
/**
|
|
21
|
-
* Hook that indicates if
|
|
22
|
+
* Hook that indicates if story kind (title) is the currently selected story section.
|
|
22
23
|
*/
|
|
23
24
|
export declare function useIsStorySectionSelected(title: string): boolean;
|
|
25
|
+
export declare function useIsChildSelected(entries: StoryIndexEntry[]): boolean;
|
|
24
26
|
/**
|
|
25
27
|
* Hook that causes a re-render when the currently selected story is changed.
|
|
26
28
|
*/
|
package/dist/hooks.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.useSelectedAddon = exports.syncExternalUI = exports.useIsSplitPanelVisible = exports.useIsUIVisible = exports.atomWithToggle = exports.useTheme = exports.useUpdateOnStoryChanged = exports.useIsStorySectionSelected = exports.useIsStorySelected = exports.useStoryContextParam = exports.useStoryContext = exports.useSetStoryContext = void 0;
|
|
26
|
+
exports.useSelectedAddon = exports.syncExternalUI = exports.useIsSplitPanelVisible = exports.useIsUIVisible = exports.atomWithToggle = exports.useTheme = exports.useUpdateOnStoryChanged = exports.useIsChildSelected = exports.useIsStorySectionSelected = exports.useIsStorySelected = exports.useStoryContextParam = exports.useStoryContext = exports.useSetStoryContext = void 0;
|
|
27
27
|
var react_1 = __importStar(require("react"));
|
|
28
28
|
var jotai_1 = require("jotai");
|
|
29
29
|
var emotion_theming_1 = require("emotion-theming");
|
|
@@ -59,12 +59,31 @@ function useIsStorySelected(storyId) {
|
|
|
59
59
|
}
|
|
60
60
|
exports.useIsStorySelected = useIsStorySelected;
|
|
61
61
|
/**
|
|
62
|
-
* Hook that indicates if
|
|
62
|
+
* Hook that indicates if story kind (title) is the currently selected story section.
|
|
63
63
|
*/
|
|
64
64
|
function useIsStorySectionSelected(title) {
|
|
65
|
-
return (0, jotai_1.useAtomValue)((0, react_1.useMemo)(function () {
|
|
65
|
+
return (0, jotai_1.useAtomValue)((0, react_1.useMemo)(function () {
|
|
66
|
+
return (0, jotai_1.atom)(function (get) {
|
|
67
|
+
var _a;
|
|
68
|
+
var contextTitle = (_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.title;
|
|
69
|
+
return contextTitle === title || (contextTitle === null || contextTitle === void 0 ? void 0 : contextTitle.startsWith("".concat(title, "/")));
|
|
70
|
+
});
|
|
71
|
+
}, [title]));
|
|
66
72
|
}
|
|
67
73
|
exports.useIsStorySectionSelected = useIsStorySectionSelected;
|
|
74
|
+
function useIsChildSelected(entries) {
|
|
75
|
+
return (0, jotai_1.useAtomValue)((0, react_1.useMemo)(function () {
|
|
76
|
+
return (0, jotai_1.atom)(function (get) {
|
|
77
|
+
var _a;
|
|
78
|
+
var contextId = (_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.id;
|
|
79
|
+
return !!entries.find(function (_a) {
|
|
80
|
+
var id = _a.id;
|
|
81
|
+
return id === contextId;
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}, [entries]));
|
|
85
|
+
}
|
|
86
|
+
exports.useIsChildSelected = useIsChildSelected;
|
|
68
87
|
/**
|
|
69
88
|
* Hook that causes a re-render when the currently selected story is changed.
|
|
70
89
|
*/
|
|
@@ -54,6 +54,9 @@ var iconSources = {
|
|
|
54
54
|
'layout-split-inverse': {
|
|
55
55
|
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAEaSURBVHgB7ZntDYJADIaLcQBGYARHgAl0I0YQJ8BNdAPZ4BzBDWov8ENrkYuJtJA+SUO4D/K+1yaQAuA4jmMaRCwpjhQB5+NG0VIU8Cu0OR+EaxM15GM6szHxdLlQ7MAGHUWVZdmDT2xGNtRgR3wkaqmliY8MYF93AWwSs3B9HZAyUINdDnxAMmCpdDh7PiCVEIJhqITeNG9g4bgBbdyANm5AGzegzeINbKcW8Ff33Ex92ngJaeMGtHED2rgBbdZv4FtbzwKSgTu7V2uz0OHxPlCXsqlhzdWgkQXsm8uBaWlTNpZChzgIp/EXBuElyu38IvUhDdqjkbSus70+LKwoTqBP1CCKT4KyUVCcsf/tMxcB+zIuwXEcxzRPpfGo9y3IYogAAAAASUVORK5CYII=',
|
|
56
56
|
},
|
|
57
|
+
folder: {
|
|
58
|
+
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAuIwAALiMBeKU/dgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHTSURBVGiB7Zk7LwRRGIbf7wwRRIJGlDSEpdmI6Fw6lRWZXiJ0lkZUsn8A2dD5B0MhkS1UepGIXZu4hsKlJASxyZyjoJAx4uzutztjc57yXN58T+Z8M5kZoEKg2R4nSpL6IdCQ72YlhQLh3LLc/dUj+7YUBepC8ciWYshxidSy+1a/tHYx+s6QlzeCKcdSihZEzWtqfsCpZcrMCy6RTwgj8knsBCHDKwIEJsPVI36cKOCGK4ygnkHYbcpkNxJISO98lc+eR4Au9eJVG4DmXyY7CejUrvRPCFCIPUQifTjG1I9ZnyuynTyeiOlEx3udDkixB6CVo1RdXCHb19P21fexonokmbZPIeQQgPuiKssTS1K3d6zoZg9Choh+tATLXSuZtk8tSwyC1B1HXiH4NXtBrByNn8V7nWFIMcmVCVJzAGp0lrKJAF/HDFjkyotHtmagKcL/QAwIIxI2jEjYMCJhw4iEDSMSNoxI2DAiYcOIhI2KEfF71W2c7XGiZa/EDwVLd6mfyCApccBYTlmomKNlRAJFymvv0P8TIRzediHjHRYAMgBK9Y+EkxygUpBybHPTdr2TBADT0Z06K/ek9UUvKFpk9Usia+eCrsNgMBgMBkM5+ADkCHptw04GlAAAAABJRU5ErkJggg==',
|
|
59
|
+
},
|
|
57
60
|
};
|
|
58
61
|
var StyledImage = (0, native_1.default)(react_native_1.Image)();
|
|
59
62
|
var StyledImageBackground = (0, native_1.default)(react_native_1.ImageBackground)();
|
|
@@ -42,15 +42,17 @@ var addons_1 = require("@storybook/addons");
|
|
|
42
42
|
var core_events_1 = __importDefault(require("@storybook/core-events"));
|
|
43
43
|
var react_1 = __importStar(require("react"));
|
|
44
44
|
var react_native_1 = require("react-native");
|
|
45
|
+
var hooks_1 = require("../../../hooks");
|
|
45
46
|
var icons_1 = require("../Shared/icons");
|
|
46
47
|
var layout_1 = require("../Shared/layout");
|
|
47
|
-
var
|
|
48
|
+
var getNestedStories_1 = require("./getNestedStories");
|
|
48
49
|
var SectionHeaderText = native_1.default.Text(function (_a) {
|
|
49
50
|
var theme = _a.theme;
|
|
50
51
|
return ({
|
|
51
52
|
fontSize: theme.storyList.fontSize,
|
|
52
53
|
color: theme.storyList.headerTextColor,
|
|
53
54
|
fontWeight: theme.storyList.headerFontWeight,
|
|
55
|
+
flexShrink: 1,
|
|
54
56
|
});
|
|
55
57
|
});
|
|
56
58
|
var StoryNameText = native_1.default.Text(function (_a) {
|
|
@@ -94,7 +96,7 @@ var HeaderContainer = native_1.default.TouchableOpacity({
|
|
|
94
96
|
flexDirection: 'row',
|
|
95
97
|
alignItems: 'center',
|
|
96
98
|
}, function (_a) {
|
|
97
|
-
var selected = _a.selected, theme = _a.theme;
|
|
99
|
+
var selected = _a.selected, theme = _a.theme, childSelected = _a.childSelected;
|
|
98
100
|
return ({
|
|
99
101
|
marginTop: theme.storyList.sectionSpacing,
|
|
100
102
|
paddingHorizontal: theme.storyList.headerPaddingHorizontal,
|
|
@@ -102,14 +104,23 @@ var HeaderContainer = native_1.default.TouchableOpacity({
|
|
|
102
104
|
backgroundColor: selected ? theme.storyList.sectionActiveBackgroundColor : undefined,
|
|
103
105
|
borderTopLeftRadius: theme.storyList.sectionBorderRadius,
|
|
104
106
|
borderTopRightRadius: theme.storyList.sectionBorderRadius,
|
|
107
|
+
borderBottomLeftRadius: selected && !childSelected ? theme.storyList.sectionBorderRadius : undefined,
|
|
108
|
+
borderBottomRightRadius: selected && !childSelected ? theme.storyList.sectionBorderRadius : undefined,
|
|
105
109
|
});
|
|
106
110
|
});
|
|
107
111
|
var SectionHeader = react_1.default.memo(function (_a) {
|
|
108
|
-
var
|
|
109
|
-
var selected = (0, hooks_1.useIsStorySectionSelected)(
|
|
110
|
-
return (react_1.default.createElement(HeaderContainer, { key:
|
|
111
|
-
react_1.default.createElement(
|
|
112
|
-
|
|
112
|
+
var name = _a.name, onPress = _a.onPress, isChildSelected = _a.isChildSelected, _b = _a.icon, icon = _b === void 0 ? 'grid' : _b, expanded = _a.expanded;
|
|
113
|
+
var selected = (0, hooks_1.useIsStorySectionSelected)(name) || isChildSelected;
|
|
114
|
+
return (react_1.default.createElement(HeaderContainer, { key: name, selected: selected, childSelected: isChildSelected, onPress: onPress, activeOpacity: 0.8 },
|
|
115
|
+
react_1.default.createElement(react_native_1.View, { style: {
|
|
116
|
+
transform: [{ rotate: expanded ? '90deg' : '0deg' }],
|
|
117
|
+
marginRight: 6,
|
|
118
|
+
alignItems: 'center',
|
|
119
|
+
justifyContent: 'center',
|
|
120
|
+
} },
|
|
121
|
+
react_1.default.createElement(react_native_1.Text, { style: { fontSize: 8, color: 'grey', lineHeight: 8 } }, '➤')),
|
|
122
|
+
react_1.default.createElement(icons_1.Icon, { name: icon, width: 12, height: 12, marginRight: 6 }),
|
|
123
|
+
react_1.default.createElement(SectionHeaderText, { numberOfLines: 2, selected: selected }, name)));
|
|
113
124
|
});
|
|
114
125
|
var ItemTouchable = native_1.default.TouchableOpacity({
|
|
115
126
|
flexDirection: 'row',
|
|
@@ -128,38 +139,50 @@ var ItemTouchable = native_1.default.TouchableOpacity({
|
|
|
128
139
|
borderBottomRightRadius: isLastItem ? theme.storyList.sectionBorderRadius : undefined,
|
|
129
140
|
});
|
|
130
141
|
});
|
|
131
|
-
var ListItem =
|
|
132
|
-
var storyId = _a.storyId, kind = _a.kind, title = _a.title, isLastItem = _a.isLastItem, onPress = _a.onPress;
|
|
142
|
+
var ListItem = function (_a) {
|
|
143
|
+
var storyId = _a.storyId, kind = _a.kind, title = _a.title, isLastItem = _a.isLastItem, onPress = _a.onPress, isSiblingSelected = _a.isSiblingSelected;
|
|
133
144
|
var selected = (0, hooks_1.useIsStorySelected)(storyId);
|
|
134
|
-
var sectionSelected = (0, hooks_1.useIsStorySectionSelected)(kind);
|
|
145
|
+
var sectionSelected = (0, hooks_1.useIsStorySectionSelected)(kind) || isSiblingSelected;
|
|
135
146
|
return (react_1.default.createElement(ItemTouchable, { key: title, onPress: onPress, activeOpacity: 0.8, testID: "Storybook.ListItem.".concat(kind, ".").concat(title), accessibilityLabel: "Storybook.ListItem.".concat(title), selected: selected, sectionSelected: sectionSelected, isLastItem: isLastItem },
|
|
136
147
|
react_1.default.createElement(icons_1.Icon, { width: 14, height: 14, name: selected ? 'story-white' : 'story-blue', marginRight: 6 }),
|
|
137
148
|
react_1.default.createElement(StoryNameText, { selected: selected }, title)));
|
|
138
|
-
}, function (prevProps, nextProps) { return prevProps.storyId === nextProps.storyId; });
|
|
139
|
-
var getStories = function (storyIndex) {
|
|
140
|
-
if (!storyIndex) {
|
|
141
|
-
return [];
|
|
142
|
-
}
|
|
143
|
-
var groupedStories = Object.values(storyIndex.stories).reduce(function (acc, story) {
|
|
144
|
-
var _a, _b;
|
|
145
|
-
acc[story.title] = {
|
|
146
|
-
title: story.title,
|
|
147
|
-
data: ((_b = (_a = acc[story.title]) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : []).concat(story),
|
|
148
|
-
};
|
|
149
|
-
return acc;
|
|
150
|
-
}, {});
|
|
151
|
-
return Object.values(groupedStories);
|
|
152
149
|
};
|
|
153
150
|
var styles = react_native_1.StyleSheet.create({
|
|
154
151
|
sectionList: { flex: 1 },
|
|
155
152
|
sectionListContentContainer: { paddingBottom: 6 },
|
|
156
153
|
});
|
|
157
154
|
function keyExtractor(item, index) {
|
|
158
|
-
return item.
|
|
155
|
+
return item.name + index;
|
|
159
156
|
}
|
|
157
|
+
var RenderItem = function (_a) {
|
|
158
|
+
var _b, _c;
|
|
159
|
+
var item = _a.item, changeStory = _a.changeStory;
|
|
160
|
+
var isChildSelected = (0, hooks_1.useIsChildSelected)(item.stories);
|
|
161
|
+
var firstChild = (0, getNestedStories_1.findFirstChildStory)(item);
|
|
162
|
+
var firstChildSelected = (0, hooks_1.useIsStorySelected)(firstChild === null || firstChild === void 0 ? void 0 : firstChild.id);
|
|
163
|
+
var _d = (0, react_1.useState)(false), showChildren = _d[0], setShowChildren = _d[1];
|
|
164
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
165
|
+
react_1.default.createElement(SectionHeader, { name: item.name, isChildSelected: isChildSelected, onPress: function () {
|
|
166
|
+
if (firstChildSelected && showChildren) {
|
|
167
|
+
setShowChildren(false);
|
|
168
|
+
}
|
|
169
|
+
else if (!showChildren && firstChild) {
|
|
170
|
+
setShowChildren(true);
|
|
171
|
+
changeStory(firstChild.id);
|
|
172
|
+
}
|
|
173
|
+
else if (showChildren && !firstChildSelected && firstChild) {
|
|
174
|
+
changeStory(firstChild.id);
|
|
175
|
+
}
|
|
176
|
+
}, icon: item.children.length ? 'folder' : 'grid', expanded: showChildren }),
|
|
177
|
+
showChildren &&
|
|
178
|
+
((_b = item.stories) === null || _b === void 0 ? void 0 : _b.map(function (story, idx) { return (react_1.default.createElement(ListItem, { key: story.id, storyId: story.id, title: story.name, kind: item.name, isSiblingSelected: isChildSelected, isLastItem: idx === item.stories.length - 1, onPress: function () { return changeStory(story.id); } })); })),
|
|
179
|
+
showChildren &&
|
|
180
|
+
((_c = item.children) === null || _c === void 0 ? void 0 : _c.map(function (child, idx) { return (react_1.default.createElement(react_native_1.View, { key: "".concat(child.title, "-").concat(idx), style: { marginLeft: 16 } },
|
|
181
|
+
react_1.default.createElement(RenderItem, { item: child, changeStory: changeStory }))); }))));
|
|
182
|
+
};
|
|
160
183
|
var StoryListView = function (_a) {
|
|
161
184
|
var storyIndex = _a.storyIndex;
|
|
162
|
-
var originalData = (0, react_1.useMemo)(function () { return
|
|
185
|
+
var originalData = (0, react_1.useMemo)(function () { return (0, getNestedStories_1.getNestedStories)(storyIndex); }, [storyIndex]);
|
|
163
186
|
var _b = (0, react_1.useState)(originalData), data = _b[0], setData = _b[1];
|
|
164
187
|
var theme = (0, hooks_1.useTheme)();
|
|
165
188
|
var handleChangeSearchText = function (text) {
|
|
@@ -168,39 +191,24 @@ var StoryListView = function (_a) {
|
|
|
168
191
|
setData(originalData);
|
|
169
192
|
return;
|
|
170
193
|
}
|
|
171
|
-
|
|
172
|
-
var filteredData = originalData.reduce(function (acc, story) {
|
|
173
|
-
var hasTitle = checkValue(story.title);
|
|
174
|
-
var hasKind = story.data.some(function (ref) { return checkValue(ref.name); });
|
|
175
|
-
if (hasTitle || hasKind) {
|
|
176
|
-
acc.push(__assign(__assign({}, story), {
|
|
177
|
-
// in case the query matches component's title, all of its stories will be shown
|
|
178
|
-
data: !hasTitle ? story.data.filter(function (ref) { return checkValue(ref.name); }) : story.data }));
|
|
179
|
-
}
|
|
180
|
-
return acc;
|
|
181
|
-
}, []);
|
|
182
|
-
setData(filteredData);
|
|
194
|
+
setData((0, getNestedStories_1.filterNestedStories)(originalData, query));
|
|
183
195
|
};
|
|
184
196
|
var changeStory = function (storyId) {
|
|
185
197
|
var channel = addons_1.addons.getChannel();
|
|
186
198
|
channel.emit(core_events_1.default.SET_CURRENT_STORY, { storyId: storyId });
|
|
187
199
|
};
|
|
188
200
|
var renderItem = react_1.default.useCallback(function (_a) {
|
|
189
|
-
var item = _a.item
|
|
190
|
-
return
|
|
191
|
-
}, []);
|
|
192
|
-
var renderSectionHeader = react_1.default.useCallback(function (_a) {
|
|
193
|
-
var _b = _a.section, title = _b.title, sectionData = _b.data;
|
|
194
|
-
return (react_1.default.createElement(SectionHeader, { title: title, onPress: function () { return changeStory(sectionData[0].id); } }));
|
|
201
|
+
var item = _a.item;
|
|
202
|
+
return react_1.default.createElement(RenderItem, { item: item, changeStory: changeStory });
|
|
195
203
|
}, []);
|
|
196
204
|
return (react_1.default.createElement(layout_1.Box, { flex: true },
|
|
197
205
|
react_1.default.createElement(SearchBar, { testID: "Storybook.ListView.SearchBar", onChangeText: handleChangeSearchText, placeholder: "Find by name" }),
|
|
198
|
-
react_1.default.createElement(react_native_1.
|
|
206
|
+
react_1.default.createElement(react_native_1.FlatList, { style: styles.sectionList, contentContainerStyle: [
|
|
199
207
|
styles.sectionListContentContainer,
|
|
200
208
|
{
|
|
201
209
|
paddingVertical: theme.panel.paddingVertical,
|
|
202
210
|
paddingHorizontal: theme.panel.paddingHorizontal,
|
|
203
211
|
},
|
|
204
|
-
], testID: "Storybook.ListView", renderItem: renderItem,
|
|
212
|
+
], testID: "Storybook.ListView", renderItem: renderItem, keyExtractor: keyExtractor, data: data })));
|
|
205
213
|
};
|
|
206
214
|
exports.default = react_1.default.memo(StoryListView);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StoryIndex, StoryIndexEntry } from '@storybook/client-api';
|
|
2
|
+
export interface StoryGroup {
|
|
3
|
+
name: string;
|
|
4
|
+
title: string;
|
|
5
|
+
children: StoryGroup[];
|
|
6
|
+
stories: StoryIndexEntry[];
|
|
7
|
+
}
|
|
8
|
+
export declare function getNestedStories(storyIndex: StoryIndex): StoryGroup[];
|
|
9
|
+
export declare const filterNestedStories: (stories: StoryGroup[], filter: string) => StoryGroup[];
|
|
10
|
+
export declare const findFirstChildStory: (story: StoryGroup) => StoryIndexEntry | undefined;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.findFirstChildStory = exports.filterNestedStories = exports.getNestedStories = void 0;
|
|
15
|
+
// recursive funciton that transforms storyIndex to be StoryGroup[]
|
|
16
|
+
function getNestedStories(storyIndex) {
|
|
17
|
+
var stories = Object.values(storyIndex.stories);
|
|
18
|
+
var group = [];
|
|
19
|
+
stories.forEach(function (story) {
|
|
20
|
+
var nameParts = story.title.split('/');
|
|
21
|
+
formGroup(nameParts, story, group);
|
|
22
|
+
});
|
|
23
|
+
return group;
|
|
24
|
+
}
|
|
25
|
+
exports.getNestedStories = getNestedStories;
|
|
26
|
+
function formGroup(nameParts, story, group) {
|
|
27
|
+
if (nameParts.length === 1) {
|
|
28
|
+
var current = group.find(function (_a) {
|
|
29
|
+
var name = _a.name;
|
|
30
|
+
return name === nameParts[0];
|
|
31
|
+
});
|
|
32
|
+
if (current) {
|
|
33
|
+
current.stories.push(story);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
group.push({
|
|
37
|
+
title: story.title,
|
|
38
|
+
name: nameParts[0],
|
|
39
|
+
children: [],
|
|
40
|
+
stories: [story],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
var newParts = nameParts.slice(1);
|
|
46
|
+
var currentListPart = group.find(function (_a) {
|
|
47
|
+
var name = _a.name;
|
|
48
|
+
return name === nameParts[0];
|
|
49
|
+
});
|
|
50
|
+
if (!currentListPart) {
|
|
51
|
+
var toPush = {
|
|
52
|
+
name: nameParts[0],
|
|
53
|
+
title: story.title,
|
|
54
|
+
children: [],
|
|
55
|
+
stories: [],
|
|
56
|
+
};
|
|
57
|
+
group.push(toPush);
|
|
58
|
+
return formGroup(newParts, story, toPush.children);
|
|
59
|
+
}
|
|
60
|
+
else if (!currentListPart.children) {
|
|
61
|
+
currentListPart.children = [];
|
|
62
|
+
}
|
|
63
|
+
var newGroup = currentListPart.children;
|
|
64
|
+
return formGroup(newParts, story, newGroup);
|
|
65
|
+
}
|
|
66
|
+
var filterNestedStories = function (stories, filter) {
|
|
67
|
+
var filteredStories = [];
|
|
68
|
+
stories.forEach(function (story) {
|
|
69
|
+
var filtered = filterStoryGroup(story, filter);
|
|
70
|
+
if (filtered) {
|
|
71
|
+
filteredStories.push(filtered);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return filteredStories;
|
|
75
|
+
};
|
|
76
|
+
exports.filterNestedStories = filterNestedStories;
|
|
77
|
+
var filterStoryGroup = function (story, filter) {
|
|
78
|
+
var filteredStories = story.stories.filter(function (item) {
|
|
79
|
+
return item.title.toLowerCase().includes(filter.toLowerCase()) ||
|
|
80
|
+
item.name.toLowerCase().includes(filter.toLowerCase());
|
|
81
|
+
});
|
|
82
|
+
var filteredChildren = (0, exports.filterNestedStories)(story.children, filter);
|
|
83
|
+
if (filteredStories.length || filteredChildren.length) {
|
|
84
|
+
return __assign(__assign({}, story), { children: filteredChildren, stories: filteredStories });
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var findFirstChildStory = function (story) {
|
|
88
|
+
if (story.stories.length) {
|
|
89
|
+
return story.stories[0];
|
|
90
|
+
}
|
|
91
|
+
if (story.children.length) {
|
|
92
|
+
return (0, exports.findFirstChildStory)(story.children[0]);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
exports.findFirstChildStory = findFirstChildStory;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var getNestedStories_1 = require("./getNestedStories");
|
|
4
|
+
var storyIndex = {
|
|
5
|
+
stories: {
|
|
6
|
+
'chat-message--message-first': {
|
|
7
|
+
id: 'chat-message--message-first',
|
|
8
|
+
importPath: './components/NestingExample/ChatMessage.stories.tsx',
|
|
9
|
+
name: 'Message First',
|
|
10
|
+
title: 'Chat/Message',
|
|
11
|
+
},
|
|
12
|
+
'chat-message--message-second': {
|
|
13
|
+
id: 'chat-message--message-second',
|
|
14
|
+
importPath: './components/NestingExample/ChatMessage.stories.tsx',
|
|
15
|
+
name: 'Message Second',
|
|
16
|
+
title: 'Chat/Message',
|
|
17
|
+
},
|
|
18
|
+
'chat-message-bubble--first': {
|
|
19
|
+
id: 'chat-message-bubble--first',
|
|
20
|
+
importPath: './components/NestingExample/ChatMessageBubble.stories.tsx',
|
|
21
|
+
name: 'First',
|
|
22
|
+
title: 'Chat/Message/bubble',
|
|
23
|
+
},
|
|
24
|
+
'chat-message-bubble--second': {
|
|
25
|
+
id: 'chat-message-bubble--second',
|
|
26
|
+
importPath: './components/NestingExample/ChatMessageBubble.stories.tsx',
|
|
27
|
+
name: 'Second Story',
|
|
28
|
+
title: 'Chat/Message/bubble',
|
|
29
|
+
},
|
|
30
|
+
'chat-message-reactions--message-one': {
|
|
31
|
+
id: 'chat-message-reactions--message-one',
|
|
32
|
+
importPath: './components/NestingExample/ChatMessageReactions.stories.tsx',
|
|
33
|
+
name: 'Message One',
|
|
34
|
+
title: 'Chat/Message/Reactions',
|
|
35
|
+
},
|
|
36
|
+
'chat-message-reactions--message-two': {
|
|
37
|
+
id: 'chat-message-reactions--message-two',
|
|
38
|
+
importPath: './components/NestingExample/ChatMessageReactions.stories.tsx',
|
|
39
|
+
name: 'Message Two',
|
|
40
|
+
title: 'Chat/Message/Reactions',
|
|
41
|
+
},
|
|
42
|
+
'chat-messageinput--basic': {
|
|
43
|
+
id: 'chat-messageinput--basic',
|
|
44
|
+
importPath: './components/NestingExample/ChatMessageMessageInput.stories.tsx',
|
|
45
|
+
name: 'Basic',
|
|
46
|
+
title: 'Chat/MessageInput',
|
|
47
|
+
},
|
|
48
|
+
'storylistview--basic': {
|
|
49
|
+
id: 'storylistview--basic',
|
|
50
|
+
importPath: './components/NestingExample/StoryList.stories.tsx',
|
|
51
|
+
name: 'Basic',
|
|
52
|
+
title: 'StoryListView',
|
|
53
|
+
},
|
|
54
|
+
'text-control--basic': {
|
|
55
|
+
id: 'text-control--basic',
|
|
56
|
+
importPath: './components/ControlExamples/Text/Text.stories.tsx',
|
|
57
|
+
name: 'Basic',
|
|
58
|
+
title: 'Text control',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
v: 3,
|
|
62
|
+
};
|
|
63
|
+
var output = [
|
|
64
|
+
{
|
|
65
|
+
name: 'Chat',
|
|
66
|
+
title: 'Chat/Message',
|
|
67
|
+
stories: [],
|
|
68
|
+
children: [
|
|
69
|
+
{
|
|
70
|
+
name: 'Message',
|
|
71
|
+
title: 'Chat/Message',
|
|
72
|
+
stories: [
|
|
73
|
+
{
|
|
74
|
+
name: 'Message First',
|
|
75
|
+
title: 'Chat/Message',
|
|
76
|
+
id: 'chat-message--message-first',
|
|
77
|
+
importPath: './components/NestingExample/ChatMessage.stories.tsx',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'Message Second',
|
|
81
|
+
title: 'Chat/Message',
|
|
82
|
+
id: 'chat-message--message-second',
|
|
83
|
+
importPath: './components/NestingExample/ChatMessage.stories.tsx',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
children: [
|
|
87
|
+
{
|
|
88
|
+
name: 'bubble',
|
|
89
|
+
children: [],
|
|
90
|
+
title: 'Chat/Message/bubble',
|
|
91
|
+
stories: [
|
|
92
|
+
{
|
|
93
|
+
name: 'First',
|
|
94
|
+
title: 'Chat/Message/bubble',
|
|
95
|
+
id: 'chat-message-bubble--first',
|
|
96
|
+
importPath: './components/NestingExample/ChatMessageBubble.stories.tsx',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Second Story',
|
|
100
|
+
title: 'Chat/Message/bubble',
|
|
101
|
+
id: 'chat-message-bubble--second',
|
|
102
|
+
importPath: './components/NestingExample/ChatMessageBubble.stories.tsx',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'Reactions',
|
|
108
|
+
title: 'Chat/Message/Reactions',
|
|
109
|
+
children: [],
|
|
110
|
+
stories: [
|
|
111
|
+
{
|
|
112
|
+
name: 'Message One',
|
|
113
|
+
title: 'Chat/Message/Reactions',
|
|
114
|
+
id: 'chat-message-reactions--message-one',
|
|
115
|
+
importPath: './components/NestingExample/ChatMessageReactions.stories.tsx',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'Message Two',
|
|
119
|
+
title: 'Chat/Message/Reactions',
|
|
120
|
+
id: 'chat-message-reactions--message-two',
|
|
121
|
+
importPath: './components/NestingExample/ChatMessageReactions.stories.tsx',
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'MessageInput',
|
|
129
|
+
title: 'Chat/MessageInput',
|
|
130
|
+
children: [],
|
|
131
|
+
stories: [
|
|
132
|
+
{
|
|
133
|
+
name: 'Basic',
|
|
134
|
+
title: 'Chat/MessageInput',
|
|
135
|
+
id: 'chat-messageinput--basic',
|
|
136
|
+
importPath: './components/NestingExample/ChatMessageMessageInput.stories.tsx',
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'StoryListView',
|
|
144
|
+
title: 'StoryListView',
|
|
145
|
+
stories: [
|
|
146
|
+
{
|
|
147
|
+
name: 'Basic',
|
|
148
|
+
title: 'StoryListView',
|
|
149
|
+
id: 'storylistview--basic',
|
|
150
|
+
importPath: './components/NestingExample/StoryList.stories.tsx',
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
children: [],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
title: 'Text control',
|
|
157
|
+
name: 'Text control',
|
|
158
|
+
stories: [
|
|
159
|
+
{
|
|
160
|
+
name: 'Basic',
|
|
161
|
+
title: 'Text control',
|
|
162
|
+
id: 'text-control--basic',
|
|
163
|
+
importPath: './components/ControlExamples/Text/Text.stories.tsx',
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
children: [],
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
test('story index to grouped list', function () {
|
|
170
|
+
expect((0, getNestedStories_1.getNestedStories)(storyIndex)).toEqual(output);
|
|
171
|
+
});
|
|
172
|
+
test('filter nested stories', function () {
|
|
173
|
+
expect((0, getNestedStories_1.filterNestedStories)(output, 'bubble')).toEqual([
|
|
174
|
+
{
|
|
175
|
+
title: 'Chat/Message',
|
|
176
|
+
name: 'Chat',
|
|
177
|
+
stories: [],
|
|
178
|
+
children: [
|
|
179
|
+
{
|
|
180
|
+
title: 'Chat/Message',
|
|
181
|
+
name: 'Message',
|
|
182
|
+
stories: [],
|
|
183
|
+
children: [
|
|
184
|
+
{
|
|
185
|
+
title: 'Chat/Message/bubble',
|
|
186
|
+
name: 'bubble',
|
|
187
|
+
children: [],
|
|
188
|
+
stories: [
|
|
189
|
+
{
|
|
190
|
+
name: 'First',
|
|
191
|
+
title: 'Chat/Message/bubble',
|
|
192
|
+
id: 'chat-message-bubble--first',
|
|
193
|
+
importPath: './components/NestingExample/ChatMessageBubble.stories.tsx',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: 'Second Story',
|
|
197
|
+
title: 'Chat/Message/bubble',
|
|
198
|
+
id: 'chat-message-bubble--second',
|
|
199
|
+
importPath: './components/NestingExample/ChatMessageBubble.stories.tsx',
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
]);
|
|
208
|
+
expect((0, getNestedStories_1.filterNestedStories)(output, 'one')).toEqual([
|
|
209
|
+
{
|
|
210
|
+
name: 'Chat',
|
|
211
|
+
title: 'Chat/Message',
|
|
212
|
+
stories: [],
|
|
213
|
+
children: [
|
|
214
|
+
{
|
|
215
|
+
title: 'Chat/Message',
|
|
216
|
+
name: 'Message',
|
|
217
|
+
stories: [],
|
|
218
|
+
children: [
|
|
219
|
+
{
|
|
220
|
+
name: 'Reactions',
|
|
221
|
+
title: 'Chat/Message/Reactions',
|
|
222
|
+
children: [],
|
|
223
|
+
stories: [
|
|
224
|
+
{
|
|
225
|
+
name: 'Message One',
|
|
226
|
+
title: 'Chat/Message/Reactions',
|
|
227
|
+
id: 'chat-message-reactions--message-one',
|
|
228
|
+
importPath: './components/NestingExample/ChatMessageReactions.stories.tsx',
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
]);
|
|
237
|
+
});
|
package/dist/preview/start.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/react-native",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.5-alpha.0",
|
|
4
4
|
"description": "A better way to develop React Native Components for your app",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"test": "jest"
|
|
39
39
|
},
|
|
40
40
|
"jest": {
|
|
41
|
+
"modulePathIgnorePatterns": [
|
|
42
|
+
"dist/"
|
|
43
|
+
],
|
|
41
44
|
"moduleFileExtensions": [
|
|
42
45
|
"ts",
|
|
43
46
|
"tsx",
|
|
@@ -71,6 +74,7 @@
|
|
|
71
74
|
"util": "^0.12.4"
|
|
72
75
|
},
|
|
73
76
|
"devDependencies": {
|
|
77
|
+
"@types/jest": "^29.4.3",
|
|
74
78
|
"@types/react": "~18.0.27",
|
|
75
79
|
"babel-jest": "^29.4.3",
|
|
76
80
|
"jest": "^29.4.3",
|
|
@@ -88,5 +92,5 @@
|
|
|
88
92
|
"publishConfig": {
|
|
89
93
|
"access": "public"
|
|
90
94
|
},
|
|
91
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "b6ca000322c9993cd35158957a7cbc1c5207481a"
|
|
92
96
|
}
|
package/readme.md
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
With Storybook for React Native you can design and develop individual React Native components without running your app.
|
|
4
4
|
|
|
5
|
-
This readme is for the 6.5 version [find the 5.3 readme here](https://github.com/storybookjs/react-native/tree/v5.3.25#readme)
|
|
5
|
+
This readme is for the 6.5 version, [find the 5.3 readme here](https://github.com/storybookjs/react-native/tree/v5.3.25#readme)
|
|
6
6
|
|
|
7
7
|
For more information about storybook visit: [storybook.js.org](https://storybook.js.org)
|
|
8
8
|
|
|
9
9
|
> NOTE: `@storybook/react-native` requires atleast 6.5.14, please set other storybook packages (like @storybook/addons) to `^6.5.14` or newer
|
|
10
10
|
|
|
11
|
-
If you want to help out or are just curious then check out the [project board](https://github.com/orgs/storybookjs/projects/12)
|
|
11
|
+
If you want to help out or are just curious then check out the [project board](https://github.com/orgs/storybookjs/projects/12) to see the open issues related to v6+.
|
|
12
12
|
|
|
13
13
|

|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
_Pictured is from the template mentioned in [getting started](#getting-started)_
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Table of contents
|
|
18
18
|
|
|
19
19
|
- 🚀 [Getting Started](#getting-started)
|
|
20
20
|
- 📒 [Writing stories](#writing-stories)
|
|
@@ -24,11 +24,11 @@ Pictured is from the template mentioned in [getting started](#getting-started)
|
|
|
24
24
|
- 🤝 [Contributing](#contributing)
|
|
25
25
|
- ✨ [Examples](#examples)
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
## Getting Started
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
### New project
|
|
30
30
|
|
|
31
|
-
There is some project boilerplate with
|
|
31
|
+
There is some project boilerplate with `@storybook/react-native` and `@storybook/addons-react-native-web` both already configured with a simple example.
|
|
32
32
|
|
|
33
33
|
For expo you can use this [template](https://github.com/dannyhw/expo-template-storybook) with the following command
|
|
34
34
|
|
|
@@ -49,61 +49,96 @@ For react native cli you can use this [template](https://github.com/dannyhw/reac
|
|
|
49
49
|
npx react-native init MyApp --template react-native-template-storybook
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
### Existing project
|
|
53
53
|
|
|
54
|
-
Run init to setup your project with all the dependencies and configuration files:
|
|
55
|
-
|
|
56
|
-
`npx sb@next init --type react_native`
|
|
54
|
+
Run init to setup your project with all the dependencies and configuration files:
|
|
57
55
|
|
|
56
|
+
```sh
|
|
57
|
+
npx sb init --type react_native
|
|
58
|
+
```
|
|
58
59
|
|
|
59
60
|
The only thing left to do is return Storybook's UI in your app entry point (such as `App.js`) like this:
|
|
60
61
|
|
|
61
62
|
```jsx
|
|
62
|
-
export {default} from './.storybook'
|
|
63
|
+
export { default } from './.storybook';
|
|
63
64
|
```
|
|
64
65
|
|
|
65
66
|
If you want to be able to swap easily between storybook and your app, have a look at this [blog post](https://dev.to/dannyhw/how-to-swap-between-react-native-storybook-and-your-app-p3o)
|
|
66
67
|
|
|
67
|
-
If you want to add everything yourself check out the the manual guide [here](MANUAL_SETUP.md).
|
|
68
|
+
If you want to add everything yourself check out the the manual guide [here](https://github.com/storybookjs/react-native/blob/next/MANUAL_SETUP.md).
|
|
69
|
+
|
|
70
|
+
### Additional steps: Update your metro config
|
|
71
|
+
|
|
72
|
+
We use the sbmodern resolver field in order to resolve the modern version of storybook packages. Doing this removes the polyfills that ship in commonjs modules and fixes multiple long standing issues such as the promises never resolving bug and more (caused by corejs promises polyfill).
|
|
73
|
+
|
|
74
|
+
**Expo**
|
|
75
|
+
|
|
76
|
+
First create metro config file if you don't have it yet.
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npx expo customize metro.config.js
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then add sbmodern to the start of the `resolver.resolverMainFields` list.
|
|
83
|
+
|
|
84
|
+
```diff
|
|
85
|
+
// metro.config.js
|
|
86
|
+
|
|
87
|
+
const { getDefaultConfig } = require('expo/metro-config');
|
|
88
|
+
|
|
89
|
+
--module.exports = getDefaultConfig(__dirname);
|
|
90
|
+
++const defaultConfig = getDefaultConfig(__dirname);
|
|
91
|
+
|
|
92
|
+
++defaultConfig.resolver.resolverMainFields.unshift('sbmodern');
|
|
93
|
+
|
|
94
|
+
++module.exports = defaultConfig;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**React native**
|
|
68
98
|
|
|
99
|
+
```js
|
|
100
|
+
module.exports = {
|
|
101
|
+
/* existing config */
|
|
102
|
+
resolver: {
|
|
103
|
+
resolverMainFields: ['sbmodern', 'react-native', 'browser', 'main'],
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
```
|
|
69
107
|
|
|
70
|
-
|
|
108
|
+
## Writing stories
|
|
71
109
|
|
|
72
110
|
In v6 you can use the CSF syntax that looks like this:
|
|
73
111
|
|
|
74
112
|
```jsx
|
|
75
|
-
import {MyButton} from './Button';
|
|
113
|
+
import { MyButton } from './Button';
|
|
76
114
|
|
|
77
115
|
export default {
|
|
78
116
|
title: 'components/MyButton',
|
|
79
117
|
component: MyButton,
|
|
80
118
|
};
|
|
81
119
|
|
|
82
|
-
export const Basic = args =>
|
|
83
|
-
<MyButton {...args} />
|
|
84
|
-
);
|
|
120
|
+
export const Basic = (args) => <MyButton {...args} />;
|
|
85
121
|
|
|
86
122
|
Basic.args = {
|
|
87
123
|
text: 'Hello World',
|
|
88
124
|
color: 'purple',
|
|
89
125
|
};
|
|
90
|
-
|
|
91
126
|
```
|
|
92
127
|
|
|
93
|
-
You should configure the path to your story files in the main.js config file from the
|
|
128
|
+
You should configure the path to your story files in the `main.js` config file from the `.storybook` folder.
|
|
94
129
|
|
|
95
130
|
```js
|
|
131
|
+
// .storybook/main.js
|
|
132
|
+
|
|
96
133
|
module.exports = {
|
|
97
|
-
stories: [
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
addons: []
|
|
101
|
-
}
|
|
134
|
+
stories: ['../components/**/*.stories.?(ts|tsx|js|jsx)'],
|
|
135
|
+
addons: [],
|
|
136
|
+
};
|
|
102
137
|
```
|
|
103
138
|
|
|
104
|
-
|
|
139
|
+
### Decorators and Parameters
|
|
105
140
|
|
|
106
|
-
For stories you can add decorators and parameters on the default export or on a specifc story
|
|
141
|
+
For stories you can add decorators and parameters on the default export or on a specifc story.
|
|
107
142
|
|
|
108
143
|
```jsx
|
|
109
144
|
export default {
|
|
@@ -111,7 +146,7 @@ export default {
|
|
|
111
146
|
component: Button,
|
|
112
147
|
decorators: [
|
|
113
148
|
(Story) => (
|
|
114
|
-
<View style={{ alignItems:
|
|
149
|
+
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>
|
|
115
150
|
<Story />
|
|
116
151
|
</View>
|
|
117
152
|
),
|
|
@@ -128,39 +163,49 @@ export default {
|
|
|
128
163
|
};
|
|
129
164
|
```
|
|
130
165
|
|
|
131
|
-
For global decorators and parameters you can add them to preview.js inside your
|
|
166
|
+
For global decorators and parameters, you can add them to `preview.js` inside your `.storybook` folder.
|
|
132
167
|
|
|
133
168
|
```jsx
|
|
134
|
-
|
|
135
|
-
|
|
169
|
+
// .storybook/preview.js
|
|
170
|
+
|
|
171
|
+
import { withBackgrounds } from '@storybook/addon-ondevice-backgrounds';
|
|
172
|
+
export const decorators = [
|
|
173
|
+
withBackgrounds,
|
|
174
|
+
(Story) => (
|
|
175
|
+
<View style={{ flex: 1, color: 'blue' }}>
|
|
176
|
+
<Story />
|
|
177
|
+
</View>
|
|
178
|
+
),
|
|
179
|
+
];
|
|
136
180
|
export const parameters = {
|
|
137
181
|
backgrounds: {
|
|
138
182
|
default: 'plain',
|
|
139
183
|
values: [
|
|
140
|
-
{name: 'plain', value: 'white'},
|
|
141
|
-
{name: 'warm', value: 'hotpink'},
|
|
142
|
-
{name: 'cool', value: 'deepskyblue'},
|
|
143
|
-
]
|
|
184
|
+
{ name: 'plain', value: 'white' },
|
|
185
|
+
{ name: 'warm', value: 'hotpink' },
|
|
186
|
+
{ name: 'cool', value: 'deepskyblue' },
|
|
187
|
+
],
|
|
144
188
|
},
|
|
145
189
|
};
|
|
146
|
-
|
|
147
190
|
```
|
|
148
191
|
|
|
149
|
-
|
|
192
|
+
## Addons
|
|
150
193
|
|
|
151
194
|
The cli will install some basic addons for you such as controls and actions.
|
|
152
195
|
Ondevice addons are addons that can render with the device ui that you see on the phone.
|
|
153
196
|
|
|
154
197
|
Currently the addons available are:
|
|
155
198
|
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
199
|
+
- [`@storybook/addon-ondevice-controls`](https://storybook.js.org/addons/@storybook/addon-ondevice-controls): adjust your components props in realtime
|
|
200
|
+
- [`@storybook/addon-ondevice-actions`](https://storybook.js.org/addons/@storybook/addon-ondevice-actions): mock onPress calls with actions that will log information in the actions tab
|
|
201
|
+
- [`@storybook/addon-ondevice-notes`](https://storybook.js.org/addons/@storybook/addon-ondevice-notes): Add some markdown to your stories to help document their usage
|
|
202
|
+
- [`@storybook/addon-ondevice-backgrounds`](https://storybook.js.org/addons/@storybook/addon-ondevice-backgrounds): change the background of storybook to compare the look of your component against different backgrounds
|
|
160
203
|
|
|
161
|
-
Install each one you want to use and add them to the main.js addons list as follows:
|
|
204
|
+
Install each one you want to use and add them to the `main.js` addons list as follows:
|
|
162
205
|
|
|
163
206
|
```js
|
|
207
|
+
// .storybook/main.js
|
|
208
|
+
|
|
164
209
|
addons: [
|
|
165
210
|
'@storybook/addon-ondevice-notes',
|
|
166
211
|
'@storybook/addon-ondevice-controls',
|
|
@@ -169,17 +214,16 @@ addons: [
|
|
|
169
214
|
],
|
|
170
215
|
```
|
|
171
216
|
|
|
172
|
-
|
|
173
217
|
### Using the addons in your story
|
|
174
218
|
|
|
175
219
|
For details of each ondevice addon you can see the readme:
|
|
176
220
|
|
|
177
|
-
- [actions](
|
|
178
|
-
- [backgrounds](
|
|
179
|
-
- [controls](
|
|
180
|
-
- [notes](
|
|
221
|
+
- [actions](https://github.com/storybookjs/react-native/tree/next/packages/ondevice-actions#readme)
|
|
222
|
+
- [backgrounds](https://github.com/storybookjs/react-native/tree/next/packages/ondevice-backgrounds#readme)
|
|
223
|
+
- [controls](https://github.com/storybookjs/react-native/tree/next/packages/ondevice-controls#readme)
|
|
224
|
+
- [notes](https://github.com/storybookjs/react-native/tree/next/packages/ondevice-notes#readme)
|
|
181
225
|
|
|
182
|
-
|
|
226
|
+
## Hide/Show storybook
|
|
183
227
|
|
|
184
228
|
Storybook on react native is a normal React Native component that can be used or hidden anywhere in your RN application based on your own logic.
|
|
185
229
|
|
|
@@ -189,17 +233,14 @@ Some have opted to toggle the storybook component by using a custom option in th
|
|
|
189
233
|
- [Heres an approach for react native cli](https://dev.to/dannyhw/multiple-entry-points-for-react-native-storybook-4dkp)
|
|
190
234
|
- [Heres an article about how you can do it in expo](https://dev.to/dannyhw/how-to-swap-between-react-native-storybook-and-your-app-p3o)
|
|
191
235
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
# getStorybookUI options
|
|
195
|
-
|
|
236
|
+
## getStorybookUI options
|
|
196
237
|
|
|
197
238
|
You can pass these parameters to getStorybookUI call in your storybook entry point:
|
|
198
239
|
|
|
199
240
|
```
|
|
200
241
|
{
|
|
201
242
|
tabOpen: Number (0)
|
|
202
|
-
-- which tab should be open. -1
|
|
243
|
+
-- which tab should be open. -1 Sidebar, 0 Canvas, 1 Addons
|
|
203
244
|
initialSelection: string | Object (undefined)
|
|
204
245
|
-- initialize storybook with a specific story. eg: `mybutton--largebutton` or `{ kind: 'MyButton', name: 'LargeButton' }`
|
|
205
246
|
shouldDisableKeyboardAvoidingView: Boolean (false)
|
|
@@ -209,7 +250,7 @@ You can pass these parameters to getStorybookUI call in your storybook entry poi
|
|
|
209
250
|
}
|
|
210
251
|
```
|
|
211
252
|
|
|
212
|
-
|
|
253
|
+
## Contributing
|
|
213
254
|
|
|
214
255
|
We welcome contributions to Storybook!
|
|
215
256
|
|
|
@@ -222,11 +263,12 @@ Looking for a first issue to tackle?
|
|
|
222
263
|
- We tag issues with [Good First Issue](https://github.com/storybookjs/react-native/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) when we think they are well suited for people who are new to the codebase or OSS in general.
|
|
223
264
|
- [Talk to us](https://discord.gg/sMFvFsG), we'll find something to suits your skills and learning interest.
|
|
224
265
|
|
|
225
|
-
|
|
266
|
+
## Examples
|
|
226
267
|
|
|
227
268
|
Here are some example projects to help you get started
|
|
228
269
|
|
|
229
270
|
- A mono repo setup by @axeldelafosse https://github.com/axeldelafosse/storybook-rnw-monorepo
|
|
230
271
|
- Expo setup https://github.com/dannyhw/expo-storybook-starter
|
|
231
272
|
- React native cli setup https://github.com/dannyhw/react-native-storybook-starter
|
|
273
|
+
- Adding a separate entry point and dev menu item in native files for RN CLI project: https://github.com/zubko/react-native-storybook-with-dev-menu
|
|
232
274
|
- Want to showcase your own project? open a PR and add it to the list!
|