@storybook/react-native 6.5.0-rc.2 → 6.5.0-rc.3

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.
Files changed (29) hide show
  1. package/dist/hooks.d.ts +5 -0
  2. package/dist/hooks.js +10 -3
  3. package/dist/preview/View.d.ts +5 -3
  4. package/dist/preview/View.js +3 -1
  5. package/dist/preview/components/OnDeviceUI/OnDeviceUI.js +16 -11
  6. package/dist/preview/components/OnDeviceUI/Panel.d.ts +7 -5
  7. package/dist/preview/components/OnDeviceUI/Panel.js +9 -4
  8. package/dist/preview/components/OnDeviceUI/addons/Addons.d.ts +3 -2
  9. package/dist/preview/components/OnDeviceUI/addons/Addons.js +7 -22
  10. package/dist/preview/components/OnDeviceUI/addons/List.js +6 -15
  11. package/dist/preview/components/OnDeviceUI/addons/Wrapper.js +10 -14
  12. package/dist/preview/components/OnDeviceUI/navigation/Navigation.js +3 -3
  13. package/dist/preview/components/OnDeviceUI/navigation/NavigationBar.d.ts +8 -0
  14. package/dist/preview/components/OnDeviceUI/navigation/NavigationBar.js +14 -0
  15. package/dist/preview/components/OnDeviceUI/navigation/VisibilityButton.js +10 -10
  16. package/dist/preview/components/Shared/layout.d.ts +12 -0
  17. package/dist/preview/components/Shared/layout.js +27 -0
  18. package/dist/preview/components/Shared/tabs.d.ts +20 -0
  19. package/dist/preview/components/Shared/tabs.js +35 -0
  20. package/dist/preview/components/Shared/theme.d.ts +183 -13
  21. package/dist/preview/components/Shared/theme.js +177 -13
  22. package/dist/preview/components/StoryListView/StoryListView.js +55 -47
  23. package/package.json +3 -2
  24. package/dist/preview/components/OnDeviceUI/navigation/Bar.d.ts +0 -9
  25. package/dist/preview/components/OnDeviceUI/navigation/Bar.js +0 -17
  26. package/dist/preview/components/OnDeviceUI/navigation/Button.d.ts +0 -10
  27. package/dist/preview/components/OnDeviceUI/navigation/Button.js +0 -17
  28. package/dist/preview/components/Shared/text.d.ts +0 -3
  29. package/dist/preview/components/Shared/text.js +0 -18
package/dist/hooks.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { StoryContext } from '@storybook/csf';
2
+ import type { Theme } from './preview/components/Shared/theme';
2
3
  import type { ReactNativeFramework } from './types/types-6.0';
3
4
  /**
4
5
  * Hook that returns a function to set the current story context.
@@ -20,3 +21,7 @@ export declare function useIsStorySelected(storyId: string): boolean;
20
21
  * Hook that indicates if `title` is the currently selected story section.
21
22
  */
22
23
  export declare function useIsStorySectionSelected(title: string): boolean;
24
+ /**
25
+ * Hook that gets the current theme values.
26
+ */
27
+ export declare function useTheme(): Theme;
package/dist/hooks.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { useMemo } from 'react';
2
2
  import { atom, useAtomValue, useSetAtom } from 'jotai';
3
+ import { useTheme as useEmotionTheme } from 'emotion-theming';
3
4
  const storyContextAtom = atom(null);
4
5
  /**
5
6
  * Hook that returns a function to set the current story context.
@@ -18,18 +19,24 @@ export function useStoryContext() {
18
19
  */
19
20
  export function useStoryContextParam(name, defaultValue) {
20
21
  var _a;
21
- const paramAtom = useMemo(() => atom(get => { var _a, _b; return (_b = (_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.parameters) === null || _b === void 0 ? void 0 : _b[name]; }), [name]);
22
+ const paramAtom = useMemo(() => atom((get) => { var _a, _b; return (_b = (_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.parameters) === null || _b === void 0 ? void 0 : _b[name]; }), [name]);
22
23
  return (_a = useAtomValue(paramAtom)) !== null && _a !== void 0 ? _a : defaultValue;
23
24
  }
24
25
  /**
25
26
  * Hook that indicates if `storyId` is the currently selected story.
26
27
  */
27
28
  export function useIsStorySelected(storyId) {
28
- return useAtomValue(useMemo(() => atom(get => { var _a; return ((_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.id) === storyId; }), [storyId]));
29
+ return useAtomValue(useMemo(() => atom((get) => { var _a; return ((_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.id) === storyId; }), [storyId]));
29
30
  }
30
31
  /**
31
32
  * Hook that indicates if `title` is the currently selected story section.
32
33
  */
33
34
  export function useIsStorySectionSelected(title) {
34
- return useAtomValue(useMemo(() => atom(get => { var _a; return ((_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.title) === title; }), [title]));
35
+ return useAtomValue(useMemo(() => atom((get) => { var _a; return ((_a = get(storyContextAtom)) === null || _a === void 0 ? void 0 : _a.title) === title; }), [title]));
36
+ }
37
+ /**
38
+ * Hook that gets the current theme values.
39
+ */
40
+ export function useTheme() {
41
+ return useEmotionTheme();
35
42
  }
@@ -1,7 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import { StoryIndex, SelectionSpecifier } from '@storybook/store';
3
3
  import { StoryContext } from '@storybook/csf';
4
- import { theme } from './components/Shared/theme';
4
+ import { Theme } from './components/Shared/theme';
5
5
  import type { ReactNativeFramework } from '../types/types-6.0';
6
6
  import { PreviewWeb } from '@storybook/preview-web';
7
7
  type StoryKind = string;
@@ -16,6 +16,9 @@ type InitialSelection = `${StoryKind}--${StoryName}` | {
16
16
  */
17
17
  name: StoryName;
18
18
  };
19
+ type DeepPartial<T> = T extends object ? {
20
+ [P in keyof T]?: DeepPartial<T[P]>;
21
+ } : T;
19
22
  export type Params = {
20
23
  onDeviceUI?: boolean;
21
24
  enableWebsockets?: boolean;
@@ -29,8 +32,7 @@ export type Params = {
29
32
  isUIHidden?: boolean;
30
33
  shouldDisableKeyboardAvoidingView?: boolean;
31
34
  keyboardAvoidingViewVerticalOffset?: number;
32
- } & {
33
- theme?: typeof theme;
35
+ theme: DeepPartial<Theme>;
34
36
  };
35
37
  export declare class View {
36
38
  _storyIndex: StoryIndex;
@@ -20,6 +20,7 @@ import StoryView from './components/StoryView';
20
20
  import createChannel from '@storybook/channel-websocket';
21
21
  import getHost from './rn-host-detect';
22
22
  import events from '@storybook/core-events';
23
+ import deepmerge from 'deepmerge';
23
24
  const STORAGE_KEY = 'lastOpenedStory';
24
25
  export class View {
25
26
  constructor(preview) {
@@ -65,6 +66,7 @@ export class View {
65
66
  });
66
67
  };
67
68
  this.getStorybookUI = (params = {}) => {
69
+ var _a;
68
70
  const { shouldPersistSelection = true, onDeviceUI = true, enableWebsockets = false } = params;
69
71
  const initialStory = this._getInitialStory(params);
70
72
  if (enableWebsockets) {
@@ -87,7 +89,7 @@ export class View {
87
89
  });
88
90
  // eslint-disable-next-line consistent-this
89
91
  const self = this;
90
- const appliedTheme = Object.assign(Object.assign({}, theme), params.theme);
92
+ const appliedTheme = deepmerge(theme, (_a = params.theme) !== null && _a !== void 0 ? _a : {});
91
93
  return () => {
92
94
  const setContext = useSetStoryContext();
93
95
  const [, forceUpdate] = useReducer((x) => x + 1, 0);
@@ -1,8 +1,7 @@
1
1
  import styled from '@emotion/native';
2
- import { useTheme } from 'emotion-theming';
3
2
  import React, { useState, useRef } from 'react';
4
3
  import { Animated, Dimensions, Easing, Keyboard, KeyboardAvoidingView, Platform, TouchableOpacity, StatusBar, StyleSheet, View, } from 'react-native';
5
- import { useStoryContextParam } from '../../../hooks';
4
+ import { useStoryContextParam, useTheme } from '../../../hooks';
6
5
  import StoryListView from '../StoryListView';
7
6
  import StoryView from '../StoryView';
8
7
  import AbsolutePositionedKeyboardAwareView from './absolute-positioned-keyboard-aware-view';
@@ -26,14 +25,14 @@ const flex = { flex: 1 };
26
25
  */
27
26
  function Preview({ animatedValue, style, children }) {
28
27
  const theme = useTheme();
29
- const containerStyle = Object.assign({ backgroundColor: theme.backgroundColor }, getPreviewShadowStyle(animatedValue));
28
+ const containerStyle = Object.assign({ backgroundColor: theme.preview.backgroundColor }, getPreviewShadowStyle(animatedValue));
30
29
  return (React.createElement(Animated.View, { style: [flex, containerStyle] },
31
30
  React.createElement(View, { style: [flex, style] }, children)));
32
31
  }
33
32
  const styles = StyleSheet.create({
34
33
  expoAndroidContainer: { paddingTop: StatusBar.currentHeight },
35
34
  });
36
- const Container = styled.View(({ theme }) => (Object.assign({ flex: 1, backgroundColor: theme.backgroundColor }, (IS_ANDROID && IS_EXPO ? styles.expoAndroidContainer : undefined))));
35
+ const Container = styled.View(({ theme }) => (Object.assign(Object.assign({ flex: 1, backgroundColor: theme.preview.containerBackgroundColor }, (IS_ANDROID && IS_EXPO ? styles.expoAndroidContainer : undefined)), Platform.select({ web: { overflow: 'hidden' } }))));
37
36
  const OnDeviceUI = ({ storyIndex, isUIHidden, shouldDisableKeyboardAvoidingView, keyboardAvoidingViewVerticalOffset, tabOpen: initialTabOpen, }) => {
38
37
  const [tabOpen, setTabOpen] = useState(initialTabOpen || PREVIEW);
39
38
  const lastTabOpen = React.useRef(tabOpen);
@@ -44,7 +43,6 @@ const OnDeviceUI = ({ storyIndex, isUIHidden, shouldDisableKeyboardAvoidingView,
44
43
  const animatedValue = useRef(new Animated.Value(tabOpen));
45
44
  const wide = useWindowDimensions().width >= BREAKPOINT;
46
45
  const insets = useSafeAreaInsets();
47
- const theme = useTheme();
48
46
  const [isUIVisible, setIsUIVisible] = useState(isUIHidden !== undefined ? !isUIHidden : true);
49
47
  const handleToggleTab = React.useCallback((newTabOpen) => {
50
48
  if (newTabOpen === tabOpen) {
@@ -96,23 +94,30 @@ const OnDeviceUI = ({ storyIndex, isUIHidden, shouldDisableKeyboardAvoidingView,
96
94
  paddingBottom: isUIVisible ? insets.bottom + navBarHeight : noSafeArea ? 0 : insets.bottom,
97
95
  paddingTop: !noSafeArea ? insets.top : 0,
98
96
  };
97
+ // The panels always apply the safe area, regardless of the story parameters.
98
+ const panelSafeAreaMargins = {
99
+ paddingBottom: insets.bottom + navBarHeight,
100
+ paddingTop: insets.top,
101
+ };
102
+ // Adjust the keyboard offset (possibly in a negative direction) to account
103
+ // for the safe area and navigation bar.
104
+ const keyboardVerticalOffset = -panelSafeAreaMargins.paddingBottom + (keyboardAvoidingViewVerticalOffset !== null && keyboardAvoidingViewVerticalOffset !== void 0 ? keyboardAvoidingViewVerticalOffset : 0);
99
105
  return (React.createElement(React.Fragment, null,
100
106
  React.createElement(Container, null,
101
- React.createElement(KeyboardAvoidingView, { enabled: !shouldDisableKeyboardAvoidingView || tabOpen !== PREVIEW, behavior: IS_IOS ? 'padding' : null, keyboardVerticalOffset: keyboardAvoidingViewVerticalOffset, style: flex },
107
+ React.createElement(KeyboardAvoidingView, { enabled: !shouldDisableKeyboardAvoidingView || tabOpen !== PREVIEW, behavior: IS_IOS ? 'padding' : null, keyboardVerticalOffset: keyboardVerticalOffset, style: flex },
102
108
  React.createElement(AbsolutePositionedKeyboardAwareView, { onLayout: setPreviewDimensions, previewDimensions: previewDimensions },
103
109
  React.createElement(Animated.View, { style: previewWrapperStyles },
104
110
  React.createElement(Preview, { style: safeAreaMargins, animatedValue: animatedValue.current },
105
111
  React.createElement(StoryView, null)),
106
112
  tabOpen !== PREVIEW ? (React.createElement(TouchableOpacity, { style: StyleSheet.absoluteFillObject, onPress: () => handleToggleTab(PREVIEW) })) : null),
107
- React.createElement(Panel, { style: [
113
+ React.createElement(Panel, { edge: "right", style: [
108
114
  getNavigatorPanelPosition(animatedValue.current, previewDimensions.width, wide),
109
- safeAreaMargins,
110
- { backgroundColor: theme.storyListBackgroundColor },
115
+ panelSafeAreaMargins,
111
116
  ] },
112
117
  React.createElement(StoryListView, { storyIndex: storyIndex })),
113
- React.createElement(Panel, { style: [
118
+ React.createElement(Panel, { edge: "left", style: [
114
119
  getAddonPanelPosition(animatedValue.current, previewDimensions.width, wide),
115
- safeAreaMargins,
120
+ panelSafeAreaMargins,
116
121
  ] },
117
122
  React.createElement(Addons, { active: tabOpen === ADDONS })))),
118
123
  React.createElement(Navigation, { onLayout: measureNavigation, tabOpen: tabOpen, onChangeTab: handleToggleTab, isUIVisible: isUIVisible, setIsUIVisible: setIsUIVisible }))));
@@ -1,7 +1,9 @@
1
- import React, { ReactNode } from 'react';
2
- interface Props {
3
- style: any[];
4
- children: ReactNode;
1
+ import React from 'react';
2
+ import { Animated, StyleProp, ViewStyle } from 'react-native';
3
+ interface PanelProps {
4
+ edge: 'left' | 'right';
5
+ style: StyleProp<Animated.AnimatedProps<ViewStyle>>;
6
+ children: React.ReactNode;
5
7
  }
6
- declare const _default: React.MemoExoticComponent<({ children, style }: Props) => JSX.Element>;
8
+ declare const _default: React.MemoExoticComponent<({ edge, children, style }: PanelProps) => JSX.Element>;
7
9
  export default _default;
@@ -1,9 +1,14 @@
1
1
  import React from 'react';
2
2
  import { StyleSheet, Animated } from 'react-native';
3
3
  import styled from '@emotion/native';
4
- // @ts-ignore styled is being weird ;(
5
- const Container = styled(Animated.View)(({ theme }) => ({
6
- backgroundColor: theme.backgroundColor || 'white',
4
+ const Container = styled(Animated.View)(({ theme, edge }) => ({
5
+ backgroundColor: theme.panel.backgroundColor,
6
+ borderStartWidth: edge === 'left' ? theme.panel.borderWidth : undefined,
7
+ borderEndWidth: edge === 'right' ? theme.panel.borderWidth : undefined,
8
+ borderColor: theme.panel.borderColor,
7
9
  }));
8
- const Panel = ({ children, style }) => (React.createElement(Container, { style: [StyleSheet.absoluteFillObject, ...style] }, children));
10
+ const Panel = ({ edge, children, style }) => {
11
+ const containerStyle = StyleSheet.flatten([StyleSheet.absoluteFillObject, style]);
12
+ return (React.createElement(Container, { edge: edge, style: containerStyle }, children));
13
+ };
9
14
  export default React.memo(Panel);
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- declare const _default: React.MemoExoticComponent<({ active }: {
2
+ interface AddonsProps {
3
3
  active: boolean;
4
- }) => JSX.Element>;
4
+ }
5
+ declare const _default: React.MemoExoticComponent<({ active }: AddonsProps) => JSX.Element>;
5
6
  export default _default;
@@ -1,33 +1,18 @@
1
1
  import React, { useState } from 'react';
2
- import { SafeAreaView, StyleSheet } from 'react-native';
3
- import styled from '@emotion/native';
2
+ import { Text } from 'react-native';
4
3
  import { addons } from '@storybook/addons';
5
4
  import AddonsList from './List';
6
5
  import AddonWrapper from './Wrapper';
7
- import { Label } from '../../Shared/text';
8
- const NoAddonContainer = styled.View({
9
- flex: 1,
10
- alignItems: 'center',
11
- justifyContent: 'center',
12
- });
13
- const Container = styled.View(({ theme }) => ({
14
- flex: 1,
15
- backgroundColor: theme.backgroundColor,
16
- }));
6
+ import { Box } from '../../Shared/layout';
17
7
  const Addons = ({ active }) => {
18
8
  const panels = addons.getElements('panel');
19
9
  const [addonSelected, setAddonSelected] = useState(Object.keys(panels)[0] || null);
20
10
  if (Object.keys(panels).length === 0) {
21
- return (React.createElement(SafeAreaView, { style: styles.container },
22
- React.createElement(NoAddonContainer, null,
23
- React.createElement(Label, null, "No addons loaded."))));
11
+ return (React.createElement(Box, { alignItems: "center", justifyContent: "center" },
12
+ React.createElement(Text, null, "No addons loaded.")));
24
13
  }
25
- return (React.createElement(Container, null,
26
- React.createElement(SafeAreaView, { style: styles.container },
27
- React.createElement(AddonsList, { onPressAddon: setAddonSelected, panels: panels, addonSelected: active ? addonSelected : null }),
28
- React.createElement(AddonWrapper, { addonSelected: active ? addonSelected : null, panels: panels }))));
14
+ return (React.createElement(Box, { flex: true },
15
+ React.createElement(AddonsList, { onPressAddon: setAddonSelected, panels: panels, addonSelected: active ? addonSelected : null }),
16
+ React.createElement(AddonWrapper, { addonSelected: active ? addonSelected : null, panels: panels })));
29
17
  };
30
- const styles = StyleSheet.create({
31
- container: { flex: 1 },
32
- });
33
18
  export default React.memo(Addons);
@@ -1,20 +1,11 @@
1
1
  import React from 'react';
2
- import { ScrollView } from 'react-native';
3
- import styled from '@emotion/native';
4
- import Button from '../navigation/Button';
5
- const Container = styled.View(({ theme }) => ({
6
- flexDirection: 'row',
7
- borderBottomWidth: 1,
8
- borderBottomColor: theme.borderColor || '#e6e6e6',
9
- }));
2
+ import { TabBar, TabButton } from '../../Shared/tabs';
10
3
  const AddonList = ({ panels, addonSelected, onPressAddon }) => {
11
4
  const addonKeys = Object.keys(panels);
12
- const renderTab = (id, title) => (React.createElement(Button, { active: id === addonSelected, key: id, id: id, onPress: () => onPressAddon(id) }, title.toUpperCase()));
13
- return (React.createElement(Container, null,
14
- React.createElement(ScrollView, { showsHorizontalScrollIndicator: false, horizontal: true }, addonKeys.map((id) => {
15
- const { title } = panels[id];
16
- const resolvedTitle = typeof title === 'function' ? title() : title;
17
- return renderTab(id, resolvedTitle);
18
- }))));
5
+ return (React.createElement(TabBar, { scrollable: true }, addonKeys.map((id) => {
6
+ const { title } = panels[id];
7
+ const resolvedTitle = typeof title === 'function' ? title() : title;
8
+ return (React.createElement(TabButton, { active: id === addonSelected, key: id, id: id, onPress: () => onPressAddon(id) }, resolvedTitle.toUpperCase()));
9
+ })));
19
10
  };
20
11
  export default React.memo(AddonList);
@@ -1,22 +1,18 @@
1
1
  import React from 'react';
2
- import { View, ScrollView, StyleSheet } from 'react-native';
3
- const style = StyleSheet.create({
4
- invisible: {
5
- height: 0,
6
- width: 0,
7
- opacity: 0,
8
- position: 'absolute',
9
- },
10
- flex: {
11
- flex: 1,
12
- },
13
- });
2
+ import { ScrollView } from 'react-native';
3
+ import styled from '@emotion/native';
4
+ import { useTheme } from '../../../../hooks';
5
+ const Container = styled.View(({ selected }) => ({
6
+ display: selected ? 'flex' : 'none',
7
+ flex: 1,
8
+ }));
14
9
  const Wrapper = ({ panels, addonSelected }) => {
10
+ const theme = useTheme();
15
11
  const addonKeys = Object.keys(panels);
16
12
  const content = addonKeys.map((id) => {
17
13
  const selected = addonSelected === id;
18
- return (React.createElement(View, { key: id, style: selected ? style.flex : style.invisible },
19
- React.createElement(ScrollView, null, panels[id].render({ active: selected, key: id }))));
14
+ return (React.createElement(Container, { key: id, selected: selected },
15
+ React.createElement(ScrollView, { contentContainerStyle: { padding: theme.panel.paddingHorizontal } }, panels[id].render({ active: selected, key: id }))));
20
16
  });
21
17
  return React.createElement(React.Fragment, null, content);
22
18
  };
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { View } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
  import GestureRecognizer from 'react-native-swipe-gestures';
5
- import Bar from './Bar';
5
+ import { NavigationBar } from './NavigationBar';
6
6
  import VisibilityButton from './VisibilityButton';
7
7
  const SWIPE_CONFIG = {
8
8
  velocityThreshold: 0.2,
@@ -31,7 +31,7 @@ const Navigation = ({ tabOpen, onChangeTab, isUIVisible, setIsUIVisible, onLayou
31
31
  };
32
32
  return (React.createElement(View, { style: navStyle, onLayout: onLayout },
33
33
  isUIVisible && (React.createElement(GestureRecognizer, { onSwipeLeft: handleSwipeLeft, onSwipeRight: handleSwipeRight, config: SWIPE_CONFIG },
34
- React.createElement(Bar, { index: tabOpen, onPress: onChangeTab, style: { paddingBottom: insets.bottom } }))),
35
- React.createElement(VisibilityButton, { onPress: handleToggleUI, style: { marginBottom: insets.bottom } })));
34
+ React.createElement(NavigationBar, { index: tabOpen, onPress: onChangeTab, style: { paddingBottom: insets.bottom } }))),
35
+ React.createElement(VisibilityButton, { onPress: handleToggleUI, style: { paddingBottom: insets.bottom } })));
36
36
  };
37
37
  export default React.memo(Navigation);
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ export interface NavigationBarProps {
4
+ index: number;
5
+ onPress: (id: number) => void;
6
+ style?: StyleProp<ViewStyle>;
7
+ }
8
+ export declare const NavigationBar: React.MemoExoticComponent<({ index, onPress, style }: NavigationBarProps) => JSX.Element>;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/native';
3
+ import { NAVIGATOR, PREVIEW, ADDONS } from './constants';
4
+ import { TabBar, TabButton } from '../../Shared/tabs';
5
+ const NavigationTabBar = styled(TabBar)(({ theme }) => ({
6
+ paddingHorizontal: theme.tokens.spacing2,
7
+ backgroundColor: theme.navigation.backgroundColor,
8
+ borderColor: theme.navigation.borderColor,
9
+ borderTopWidth: theme.navigation.borderWidth,
10
+ }));
11
+ export const NavigationBar = React.memo(({ index, onPress, style }) => (React.createElement(NavigationTabBar, { style: style },
12
+ React.createElement(TabButton, { onPress: onPress, testID: "BottomMenu.Navigator", id: NAVIGATOR, active: index === NAVIGATOR }, "NAVIGATOR"),
13
+ React.createElement(TabButton, { onPress: onPress, testID: "BottomMenu.Preview", id: PREVIEW, active: index === PREVIEW }, "PREVIEW"),
14
+ React.createElement(TabButton, { onPress: onPress, testID: "BottomMenu.Addons", id: ADDONS, active: index === ADDONS }, "ADDONS"))));
@@ -1,13 +1,13 @@
1
1
  import React from 'react';
2
2
  import styled from '@emotion/native';
3
3
  import { View } from 'react-native';
4
- const Touchable = styled.TouchableOpacity({
4
+ const Touchable = styled.TouchableOpacity(({ theme }) => ({
5
5
  backgroundColor: 'transparent',
6
6
  position: 'absolute',
7
- right: 8,
8
- bottom: 12,
7
+ right: theme.tokens.spacing2,
8
+ bottom: theme.tokens.spacing4,
9
9
  zIndex: 100,
10
- });
10
+ }));
11
11
  const HIDE_ICON_SIZE = 14;
12
12
  const HIDE_ICON_BORDER_WIDTH = 1;
13
13
  const Inner = styled.View(({ theme }) => ({
@@ -16,22 +16,22 @@ const Inner = styled.View(({ theme }) => ({
16
16
  left: 0,
17
17
  width: HIDE_ICON_SIZE,
18
18
  height: HIDE_ICON_SIZE,
19
- borderRadius: HIDE_ICON_BORDER_WIDTH,
19
+ borderRadius: theme.navigation.visibilityBorderRadius,
20
20
  overflow: 'hidden',
21
- borderColor: theme.buttonTextColor || '#999999',
21
+ borderColor: theme.navigation.visibilityInnerBorderColor,
22
22
  borderWidth: HIDE_ICON_BORDER_WIDTH * 2,
23
23
  }));
24
- const Outer = styled.View({
24
+ const Outer = styled.View(({ theme }) => ({
25
25
  position: 'absolute',
26
26
  top: 0,
27
27
  left: 0,
28
28
  width: HIDE_ICON_SIZE,
29
29
  height: HIDE_ICON_SIZE,
30
- borderRadius: HIDE_ICON_BORDER_WIDTH,
30
+ borderRadius: theme.navigation.visibilityBorderRadius,
31
31
  overflow: 'hidden',
32
- borderColor: 'white',
32
+ borderColor: theme.navigation.visibilityOuterBorderColor,
33
33
  borderWidth: HIDE_ICON_BORDER_WIDTH,
34
- });
34
+ }));
35
35
  const hideIconStyles = {
36
36
  width: HIDE_ICON_SIZE,
37
37
  height: HIDE_ICON_SIZE,
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A general (flex)box layout component that accepts props for flexbox layout
3
+ * styles, such as `flex`, `alignItems`, `marginVertical`, etc.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * <Box flex flexDirection='row' alignItems='center' marginVertical={42}>
8
+ * <MyContent />
9
+ * </Box>
10
+ * ```
11
+ */
12
+ export declare const Box: any;
@@ -0,0 +1,27 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import styled from '@emotion/native';
13
+ /**
14
+ * A general (flex)box layout component that accepts props for flexbox layout
15
+ * styles, such as `flex`, `alignItems`, `marginVertical`, etc.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <Box flex flexDirection='row' alignItems='center' marginVertical={42}>
20
+ * <MyContent />
21
+ * </Box>
22
+ * ```
23
+ */
24
+ export const Box = styled.View((_a) => {
25
+ var { flex } = _a, layoutProps = __rest(_a, ["flex"]);
26
+ return (Object.assign({ flex: flex === true ? 1 : flex === false ? 0 : flex }, layoutProps));
27
+ });
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ interface TabButtonProps {
4
+ id: number | string;
5
+ active: boolean;
6
+ onPress: (id: number | string) => void;
7
+ testID?: string;
8
+ children: React.ReactNode;
9
+ }
10
+ export declare const TabButton: React.MemoExoticComponent<({ onPress, id, active, children, testID }: TabButtonProps) => JSX.Element>;
11
+ interface TabBarProps {
12
+ /**
13
+ * Should the tab bar contents scroll horizontally?
14
+ */
15
+ scrollable?: boolean;
16
+ style?: StyleProp<ViewStyle>;
17
+ children: React.ReactNode;
18
+ }
19
+ export declare const TabBar: React.MemoExoticComponent<({ scrollable, style, children }: TabBarProps) => JSX.Element>;
20
+ export {};
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { ScrollView, View } from 'react-native';
3
+ import styled from '@emotion/native';
4
+ import { useTheme } from '../../../hooks';
5
+ const TabButtonText = styled.Text(({ theme, active }) => ({
6
+ color: active ? theme.tabs.activeTextColor : theme.tabs.inactiveTextColor,
7
+ paddingVertical: theme.tabs.paddingVertical,
8
+ paddingHorizontal: theme.tabs.paddingHorizontal,
9
+ fontSize: theme.tabs.fontSize,
10
+ fontWeight: theme.tabs.fontWeight,
11
+ }));
12
+ const hitSlop = { top: 8, left: 0, right: 0, bottom: 20 };
13
+ const TabButtonTouchable = styled.TouchableOpacity(({ theme, active }) => ({
14
+ borderWidth: theme.tabs.borderWidth,
15
+ borderColor: active ? theme.tabs.activeBorderColor : theme.tabs.inactiveBorderColor,
16
+ borderRadius: theme.tabs.borderRadius,
17
+ backgroundColor: active ? theme.tabs.activeBackgroundColor : theme.tabs.inactiveBackgroundColor,
18
+ }));
19
+ export const TabButton = React.memo(({ onPress, id, active, children, testID }) => {
20
+ return (React.createElement(TabButtonTouchable, { active: active, testID: testID, onPress: () => onPress(id), activeOpacity: 0.8, hitSlop: hitSlop },
21
+ React.createElement(TabButtonText, { active: active }, children)));
22
+ });
23
+ export const TabBar = React.memo(({ scrollable = false, style, children }) => {
24
+ const theme = useTheme();
25
+ if (scrollable) {
26
+ children = (React.createElement(ScrollView, { showsHorizontalScrollIndicator: false, horizontal: true, contentContainerStyle: { paddingHorizontal: theme.tokens.spacing2 } }, children));
27
+ }
28
+ return (React.createElement(View, { style: style },
29
+ React.createElement(TabBarContainer, null, children)));
30
+ });
31
+ const TabBarContainer = styled.View({
32
+ flexDirection: 'row',
33
+ paddingVertical: 6,
34
+ justifyItems: 'center',
35
+ });
@@ -1,15 +1,185 @@
1
- export declare const theme: {
1
+ import { ShadowStyleIOS, ViewStyle, TextStyle } from 'react-native';
2
+ type ShadowStyle = ShadowStyleIOS | Pick<ViewStyle, 'elevation'>;
3
+ type FontWeight = TextStyle['fontWeight'];
4
+ /**
5
+ * Primitive tokens used to build the theme.
6
+ *
7
+ * Ideally components should not use these values directly, and should prefer
8
+ * to use more semantic values from the theme.
9
+ */
10
+ interface ThemeTokens {
11
+ spacing1: number;
12
+ spacing2: number;
13
+ spacing3: number;
14
+ spacing4: number;
15
+ spacing5: number;
16
+ spacing6: number;
17
+ fontSize: {
18
+ small: number;
19
+ smaller: number;
20
+ normal: number;
21
+ };
22
+ color: {
23
+ black: string;
24
+ white: string;
25
+ grey200: string;
26
+ grey700: string;
27
+ red500: string;
28
+ blue100: string;
29
+ blue200: string;
30
+ blue250: string;
31
+ blue300: string;
32
+ blue400: string;
33
+ blue600: string;
34
+ green500: string;
35
+ };
36
+ borderRadius: {
37
+ small: number;
38
+ medium: number;
39
+ large: number;
40
+ round: number;
41
+ };
42
+ borderWidthNormal: number;
43
+ /** Elevation shadows */
44
+ elevation: {
45
+ floating: ShadowStyle;
46
+ };
47
+ }
48
+ interface ThemeButton {
49
+ textColor: string;
2
50
  backgroundColor: string;
3
- storyListBackgroundColor: string;
4
- listItemTextColor: string;
5
- listItemActiveColor: string;
6
- listItemActiveTextColor: string;
7
- sectionActiveColor: string;
8
- headerTextColor: string;
9
- labelColor: string;
10
51
  borderColor: string;
11
- previewBorderColor: string;
12
- buttonTextColor: string;
13
- buttonActiveTextColor: string;
14
- secondaryLabelColor: string;
15
- };
52
+ borderWidth: number;
53
+ borderRadius: number;
54
+ }
55
+ export interface Theme {
56
+ tokens: ThemeTokens;
57
+ backgroundColor: string;
58
+ text: {
59
+ primaryColor: string;
60
+ secondaryColor: string;
61
+ linkColor: string;
62
+ };
63
+ preview: {
64
+ containerBackgroundColor: string;
65
+ backgroundColor: string;
66
+ };
67
+ /** Navigation bar and related area */
68
+ navigation: {
69
+ backgroundColor: string;
70
+ borderColor: string;
71
+ borderWidth: number;
72
+ visibilityBorderRadius: number;
73
+ visibilityInnerBorderColor: string;
74
+ visibilityOuterBorderColor: string;
75
+ };
76
+ /** Side panels (Story list, addons) */
77
+ panel: {
78
+ backgroundColor: string;
79
+ borderWidth: number;
80
+ borderColor: string;
81
+ paddingVertical: number;
82
+ paddingHorizontal: number;
83
+ };
84
+ /** Story list and list items */
85
+ storyList: {
86
+ fontSize: number;
87
+ headerPaddingHorizontal: number;
88
+ headerPaddingVertical: number;
89
+ headerTextColor: string;
90
+ headerFontWeight: FontWeight;
91
+ storyPaddingHorizontal: number;
92
+ storyPaddingVertical: number;
93
+ storyIndent: number;
94
+ storyTextColor: string;
95
+ storyFontWeight: FontWeight;
96
+ storySelectedBackgroundColor: string;
97
+ storySelectedTextColor: string;
98
+ storySelectedFontWeight: FontWeight;
99
+ sectionSpacing: number;
100
+ sectionActiveBackgroundColor: string;
101
+ sectionBorderRadius: number;
102
+ search: {
103
+ fontSize: number;
104
+ textColor: string;
105
+ placeholderTextColor: string;
106
+ borderRadius: number;
107
+ borderColor: string;
108
+ borderWidth: number;
109
+ backgroundColor: string;
110
+ paddingVertical: number;
111
+ paddingHorizontal: number;
112
+ };
113
+ };
114
+ /** Buttons */
115
+ button: {
116
+ fontSize: number;
117
+ fontWeight: FontWeight;
118
+ paddingVertical: number;
119
+ paddingHorizontal: number;
120
+ primary: ThemeButton;
121
+ secondary: ThemeButton;
122
+ };
123
+ /** Tabs (navigation and addons) */
124
+ tabs: {
125
+ fontSize: number;
126
+ fontWeight: FontWeight;
127
+ paddingVertical: number;
128
+ paddingHorizontal: number;
129
+ borderWidth: number;
130
+ borderRadius: number;
131
+ activeBorderColor: string;
132
+ activeBackgroundColor: string;
133
+ activeTextColor: string;
134
+ inactiveBorderColor: string;
135
+ inactiveBackgroundColor: string;
136
+ inactiveTextColor: string;
137
+ };
138
+ /** Inputs (text, radio, slider, etc.) */
139
+ inputs: {
140
+ errorTextColor: string;
141
+ labelFontSize: number;
142
+ labelTextColor: string;
143
+ text: {
144
+ fontSize: number;
145
+ textColor: string;
146
+ borderWidth: number;
147
+ borderColor: string;
148
+ backgroundColor: string;
149
+ borderRadius: number;
150
+ paddingVertical: number;
151
+ paddingHorizontal: number;
152
+ };
153
+ radio: {
154
+ fontSize: number;
155
+ height: number;
156
+ borderWidth: number;
157
+ borderColor: string;
158
+ backgroundColor: string;
159
+ paddingVertical: number;
160
+ paddingHorizontal: number;
161
+ activeBackgroundColor: string;
162
+ itemSpacing: number;
163
+ labelSpacing: number;
164
+ };
165
+ swatch: {
166
+ fontSize: number;
167
+ height: number;
168
+ borderWidth: number;
169
+ borderColor: string;
170
+ backgroundColor: string;
171
+ outerBorderRadius: number;
172
+ innerBorderRadius: number;
173
+ paddingVertical: number;
174
+ paddingHorizontal: number;
175
+ nameTextWeight: FontWeight;
176
+ };
177
+ slider: {
178
+ fontSize: number;
179
+ labelTextColor: string;
180
+ valueTextColor: string;
181
+ };
182
+ };
183
+ }
184
+ export declare const theme: Theme;
185
+ export {};
@@ -1,15 +1,179 @@
1
+ const tokens = {
2
+ spacing1: 4,
3
+ spacing2: 8,
4
+ spacing3: 12,
5
+ spacing4: 16,
6
+ spacing5: 20,
7
+ spacing6: 24,
8
+ fontSize: {
9
+ small: 12,
10
+ smaller: 14,
11
+ normal: 16,
12
+ },
13
+ color: {
14
+ black: '#001a23',
15
+ white: '#ffffff',
16
+ grey200: '#dee2e3',
17
+ grey700: '#859499',
18
+ red500: '#ff4400',
19
+ blue100: '#f6f9fc',
20
+ blue200: '#e0eaf5',
21
+ blue250: '#dcebf9',
22
+ blue300: '#b2cbe6',
23
+ blue400: '#a3c1e0',
24
+ blue600: '#1ea7fd',
25
+ green500: '#66bf3c',
26
+ },
27
+ borderRadius: {
28
+ small: 4,
29
+ medium: 6,
30
+ large: 8,
31
+ round: 100,
32
+ },
33
+ borderWidthNormal: 1,
34
+ elevation: {
35
+ floating: {
36
+ shadowColor: '#000000',
37
+ shadowOpacity: 0.2,
38
+ shadowOffset: { width: 0, height: 0 },
39
+ shadowRadius: 16,
40
+ elevation: 10,
41
+ },
42
+ },
43
+ };
44
+ const text = {
45
+ primaryColor: tokens.color.black,
46
+ secondaryColor: tokens.color.grey700,
47
+ linkColor: '#0000ff',
48
+ };
1
49
  export const theme = {
2
- backgroundColor: 'white',
3
- storyListBackgroundColor: '#f6f9fc',
4
- listItemTextColor: '#444444',
5
- listItemActiveColor: '#1ea7fd',
6
- listItemActiveTextColor: 'white',
7
- sectionActiveColor: '#e0ebf5',
8
- headerTextColor: 'black',
9
- labelColor: 'black',
10
- borderColor: '#e6e6e6',
11
- previewBorderColor: '#b3b3b3',
12
- buttonTextColor: '#999999',
13
- buttonActiveTextColor: '#444444',
14
- secondaryLabelColor: '#999999',
50
+ tokens,
51
+ text,
52
+ backgroundColor: tokens.color.white,
53
+ preview: {
54
+ containerBackgroundColor: tokens.color.white,
55
+ backgroundColor: tokens.color.white,
56
+ },
57
+ navigation: {
58
+ backgroundColor: tokens.color.white,
59
+ borderColor: tokens.color.grey200,
60
+ borderWidth: tokens.borderWidthNormal,
61
+ visibilityBorderRadius: tokens.borderRadius.small,
62
+ visibilityInnerBorderColor: tokens.color.grey700,
63
+ visibilityOuterBorderColor: tokens.color.white,
64
+ },
65
+ panel: {
66
+ backgroundColor: tokens.color.blue100,
67
+ borderWidth: tokens.borderWidthNormal,
68
+ borderColor: tokens.color.blue200,
69
+ paddingVertical: 0,
70
+ paddingHorizontal: tokens.spacing2,
71
+ },
72
+ storyList: {
73
+ fontSize: tokens.fontSize.normal,
74
+ headerPaddingHorizontal: tokens.spacing2,
75
+ headerPaddingVertical: tokens.spacing2,
76
+ headerTextColor: text.primaryColor,
77
+ headerFontWeight: '500',
78
+ storyPaddingHorizontal: tokens.spacing2,
79
+ storyPaddingVertical: tokens.spacing1 * 1.5,
80
+ storyIndent: tokens.spacing6,
81
+ storyTextColor: text.primaryColor,
82
+ storyFontWeight: '400',
83
+ storySelectedBackgroundColor: tokens.color.blue600,
84
+ storySelectedTextColor: tokens.color.white,
85
+ storySelectedFontWeight: '700',
86
+ sectionSpacing: tokens.spacing2,
87
+ sectionActiveBackgroundColor: tokens.color.blue200,
88
+ sectionBorderRadius: tokens.borderRadius.medium,
89
+ search: {
90
+ fontSize: tokens.fontSize.normal,
91
+ textColor: text.primaryColor,
92
+ placeholderTextColor: text.secondaryColor,
93
+ borderRadius: tokens.borderRadius.round,
94
+ borderColor: tokens.color.blue400,
95
+ borderWidth: tokens.borderWidthNormal,
96
+ backgroundColor: tokens.color.white,
97
+ paddingVertical: tokens.spacing2,
98
+ paddingHorizontal: tokens.spacing3,
99
+ },
100
+ },
101
+ button: {
102
+ fontSize: tokens.fontSize.smaller,
103
+ fontWeight: '600',
104
+ paddingVertical: tokens.spacing2,
105
+ paddingHorizontal: tokens.spacing5,
106
+ primary: {
107
+ textColor: text.primaryColor,
108
+ backgroundColor: tokens.color.blue250,
109
+ borderColor: tokens.color.blue300,
110
+ borderWidth: tokens.borderWidthNormal,
111
+ borderRadius: tokens.borderRadius.medium,
112
+ },
113
+ secondary: {
114
+ textColor: text.primaryColor,
115
+ backgroundColor: 'transparent',
116
+ borderColor: tokens.color.blue300,
117
+ borderWidth: tokens.borderWidthNormal,
118
+ borderRadius: tokens.borderRadius.medium,
119
+ },
120
+ },
121
+ tabs: {
122
+ fontSize: tokens.fontSize.small,
123
+ fontWeight: '500',
124
+ paddingVertical: tokens.spacing2,
125
+ paddingHorizontal: tokens.spacing2 * 1.25,
126
+ borderWidth: tokens.borderWidthNormal,
127
+ borderRadius: tokens.borderRadius.round,
128
+ activeBorderColor: tokens.color.blue300,
129
+ activeBackgroundColor: tokens.color.blue250,
130
+ activeTextColor: text.primaryColor,
131
+ inactiveBorderColor: 'transparent',
132
+ inactiveBackgroundColor: 'transparent',
133
+ inactiveTextColor: text.secondaryColor,
134
+ },
135
+ inputs: {
136
+ errorTextColor: tokens.color.red500,
137
+ labelFontSize: tokens.fontSize.smaller,
138
+ labelTextColor: text.primaryColor,
139
+ text: {
140
+ fontSize: tokens.fontSize.smaller,
141
+ textColor: text.primaryColor,
142
+ borderWidth: tokens.borderWidthNormal,
143
+ borderColor: tokens.color.blue400,
144
+ backgroundColor: tokens.color.white,
145
+ borderRadius: tokens.borderRadius.medium,
146
+ paddingVertical: tokens.spacing1 * 1.5,
147
+ paddingHorizontal: tokens.spacing1 * 1.5,
148
+ },
149
+ radio: {
150
+ fontSize: tokens.fontSize.smaller,
151
+ height: 20,
152
+ borderWidth: tokens.borderWidthNormal,
153
+ borderColor: tokens.color.blue400,
154
+ backgroundColor: tokens.color.white,
155
+ paddingVertical: 3,
156
+ paddingHorizontal: 3,
157
+ activeBackgroundColor: tokens.color.green500,
158
+ itemSpacing: tokens.spacing1,
159
+ labelSpacing: tokens.spacing2,
160
+ },
161
+ swatch: {
162
+ fontSize: tokens.fontSize.smaller,
163
+ height: 40,
164
+ borderWidth: tokens.borderWidthNormal,
165
+ borderColor: tokens.color.blue400,
166
+ backgroundColor: tokens.color.white,
167
+ outerBorderRadius: tokens.borderRadius.medium,
168
+ innerBorderRadius: tokens.borderRadius.small,
169
+ paddingVertical: tokens.spacing1,
170
+ paddingHorizontal: tokens.spacing1,
171
+ nameTextWeight: '600',
172
+ },
173
+ slider: {
174
+ fontSize: tokens.fontSize.smaller,
175
+ labelTextColor: text.secondaryColor,
176
+ valueTextColor: text.primaryColor,
177
+ },
178
+ },
15
179
  };
@@ -3,78 +3,79 @@ import { addons } from '@storybook/addons';
3
3
  import Events from '@storybook/core-events';
4
4
  import React, { useMemo, useState } from 'react';
5
5
  import { SectionList, StyleSheet } from 'react-native';
6
- import { useIsStorySectionSelected, useIsStorySelected } from '../../../hooks';
7
6
  import { GridIcon, SearchIcon, StoryIcon } from '../Shared/icons';
8
- import { Header, Name } from '../Shared/text';
9
- const SearchInput = styled.TextInput(Object.assign({ fontSize: 16, padding: 0, paddingHorizontal: 36 }, StyleSheet.absoluteFillObject), ({ theme }) => ({
10
- color: theme.buttonActiveTextColor,
7
+ import { Box } from '../Shared/layout';
8
+ import { useIsStorySelected, useIsStorySectionSelected, useTheme } from '../../../hooks';
9
+ const SectionHeaderText = styled.Text(({ theme }) => ({
10
+ fontSize: theme.storyList.fontSize,
11
+ color: theme.storyList.headerTextColor,
12
+ fontWeight: theme.storyList.headerFontWeight,
11
13
  }));
12
- const SearchContainer = styled.View({
13
- borderRadius: 100,
14
- borderWidth: 1.5,
15
- marginVertical: 4,
16
- marginHorizontal: 8,
17
- paddingVertical: 10,
18
- paddingLeft: 12,
14
+ const StoryNameText = styled.Text(({ selected, theme }) => ({
15
+ fontSize: theme.storyList.fontSize,
16
+ fontWeight: selected ? theme.storyList.storySelectedFontWeight : theme.storyList.storyFontWeight,
17
+ color: selected ? theme.storyList.storySelectedTextColor : theme.storyList.storyTextColor,
18
+ }));
19
+ const SEARCH_ICON_SIZE = 24;
20
+ const SearchInput = styled.TextInput(Object.assign({ padding: 0 }, StyleSheet.absoluteFillObject), ({ theme }) => ({
21
+ fontSize: theme.storyList.search.fontSize,
22
+ paddingStart: theme.storyList.search.paddingHorizontal + SEARCH_ICON_SIZE,
23
+ color: theme.storyList.search.textColor,
24
+ }));
25
+ const SearchContainer = styled.View(({ theme }) => ({
19
26
  flexDirection: 'row',
20
27
  alignItems: 'center',
21
- }, ({ theme }) => ({
22
- borderColor: theme.borderColor,
23
- backgroundColor: theme.storyListBackgroundColor,
28
+ margin: theme.panel.paddingHorizontal,
29
+ paddingVertical: theme.storyList.search.paddingVertical,
30
+ paddingStart: theme.storyList.search.paddingHorizontal,
31
+ borderColor: theme.storyList.search.borderColor,
32
+ borderWidth: theme.storyList.search.borderWidth,
33
+ borderRadius: theme.storyList.search.borderRadius,
34
+ backgroundColor: theme.storyList.search.backgroundColor,
24
35
  }));
25
36
  const SearchBar = (props) => {
37
+ const theme = useTheme();
26
38
  return (React.createElement(SearchContainer, null,
27
39
  React.createElement(SearchIcon, null),
28
- React.createElement(SearchInput, Object.assign({}, props, { autoCapitalize: "none", autoComplete: "off", autoCorrect: false, spellCheck: false, clearButtonMode: "while-editing", disableFullscreenUI: true, placeholderTextColor: "#666", returnKeyType: "search" }))));
40
+ React.createElement(SearchInput, Object.assign({}, props, { autoCapitalize: "none", autoComplete: "off", autoCorrect: false, spellCheck: false, clearButtonMode: "while-editing", disableFullscreenUI: true, placeholderTextColor: theme.storyList.search.placeholderTextColor, returnKeyType: "search" }))));
29
41
  };
30
42
  const HeaderContainer = styled.TouchableOpacity({
31
- marginTop: 8,
32
- marginHorizontal: 6,
33
- padding: 6,
34
- paddingHorizontal: 8,
35
- borderTopLeftRadius: 6,
36
- borderTopRightRadius: 6,
37
43
  flexDirection: 'row',
38
44
  alignItems: 'center',
39
45
  }, ({ selected, theme }) => ({
40
- backgroundColor: selected ? theme.sectionActiveColor : undefined,
41
- }));
42
- const StoryListContainer = styled.View(({ theme }) => ({
43
- flex: 1,
44
- borderRightWidth: StyleSheet.hairlineWidth,
45
- borderRightColor: theme.borderColor,
46
- backgroundColor: theme.storyListBackgroundColor,
46
+ marginTop: theme.storyList.sectionSpacing,
47
+ paddingHorizontal: theme.storyList.headerPaddingHorizontal,
48
+ paddingVertical: theme.storyList.headerPaddingVertical,
49
+ backgroundColor: selected ? theme.storyList.sectionActiveBackgroundColor : undefined,
50
+ borderTopLeftRadius: theme.storyList.sectionBorderRadius,
51
+ borderTopRightRadius: theme.storyList.sectionBorderRadius,
47
52
  }));
48
53
  const SectionHeader = React.memo(({ title, onPress }) => {
49
54
  const selected = useIsStorySectionSelected(title);
50
55
  return (React.createElement(HeaderContainer, { key: title, selected: selected, onPress: onPress, activeOpacity: 0.8 },
51
56
  React.createElement(GridIcon, null),
52
- React.createElement(Header, { selected: selected }, title)));
57
+ React.createElement(SectionHeaderText, { selected: selected }, title)));
53
58
  });
54
59
  const ItemTouchable = styled.TouchableOpacity({
55
- marginHorizontal: 6,
56
- padding: 6,
57
- paddingLeft: 24,
58
60
  flexDirection: 'row',
59
61
  alignItems: 'center',
60
- }, ({ selected, sectionSelected, isLastItem, theme }) => {
61
- var _a;
62
- return {
63
- backgroundColor: selected
64
- ? (_a = theme === null || theme === void 0 ? void 0 : theme.listItemActiveColor) !== null && _a !== void 0 ? _a : '#1ea7fd'
65
- : sectionSelected
66
- ? theme === null || theme === void 0 ? void 0 : theme.sectionActiveColor
67
- : undefined,
68
- borderBottomLeftRadius: isLastItem ? 6 : undefined,
69
- borderBottomRightRadius: isLastItem ? 6 : undefined,
70
- };
71
- });
62
+ }, ({ selected, sectionSelected, isLastItem, theme }) => ({
63
+ padding: theme.storyList.storyPaddingHorizontal,
64
+ paddingStart: theme.storyList.storyIndent,
65
+ backgroundColor: selected
66
+ ? theme.storyList.storySelectedBackgroundColor
67
+ : sectionSelected
68
+ ? theme.storyList.sectionActiveBackgroundColor
69
+ : undefined,
70
+ borderBottomLeftRadius: isLastItem ? theme.storyList.sectionBorderRadius : undefined,
71
+ borderBottomRightRadius: isLastItem ? theme.storyList.sectionBorderRadius : undefined,
72
+ }));
72
73
  const ListItem = React.memo(({ storyId, kind, title, isLastItem, onPress }) => {
73
74
  const selected = useIsStorySelected(storyId);
74
75
  const sectionSelected = useIsStorySectionSelected(kind);
75
76
  return (React.createElement(ItemTouchable, { key: title, onPress: onPress, activeOpacity: 0.8, testID: `Storybook.ListItem.${kind}.${title}`, accessibilityLabel: `Storybook.ListItem.${title}`, selected: selected, sectionSelected: sectionSelected, isLastItem: isLastItem },
76
77
  React.createElement(StoryIcon, { selected: selected }),
77
- React.createElement(Name, { selected: selected }, title)));
78
+ React.createElement(StoryNameText, { selected: selected }, title)));
78
79
  }, (prevProps, nextProps) => prevProps.storyId === nextProps.storyId);
79
80
  const getStories = (storyIndex) => {
80
81
  if (!storyIndex) {
@@ -100,6 +101,7 @@ function keyExtractor(item, index) {
100
101
  const StoryListView = ({ storyIndex }) => {
101
102
  const originalData = useMemo(() => getStories(storyIndex), [storyIndex]);
102
103
  const [data, setData] = useState(originalData);
104
+ const theme = useTheme();
103
105
  const handleChangeSearchText = (text) => {
104
106
  const query = text.trim();
105
107
  if (!query) {
@@ -127,8 +129,14 @@ const StoryListView = ({ storyIndex }) => {
127
129
  return (React.createElement(ListItem, { storyId: item.id, title: item.name, kind: item.title, isLastItem: index === section.data.length - 1, onPress: () => changeStory(item.id) }));
128
130
  }, []);
129
131
  const renderSectionHeader = React.useCallback(({ section: { title, data } }) => (React.createElement(SectionHeader, { title: title, onPress: () => changeStory(data[0].id) })), []);
130
- return (React.createElement(StoryListContainer, null,
132
+ return (React.createElement(Box, { flex: true },
131
133
  React.createElement(SearchBar, { testID: "Storybook.ListView.SearchBar", onChangeText: handleChangeSearchText, placeholder: "Find by name" }),
132
- React.createElement(SectionList, { style: styles.sectionList, contentContainerStyle: styles.sectionListContentContainer, testID: "Storybook.ListView", renderItem: renderItem, renderSectionHeader: renderSectionHeader, keyExtractor: keyExtractor, sections: data, stickySectionHeadersEnabled: false })));
134
+ React.createElement(SectionList, { style: styles.sectionList, contentContainerStyle: [
135
+ styles.sectionListContentContainer,
136
+ {
137
+ paddingVertical: theme.panel.paddingVertical,
138
+ paddingHorizontal: theme.panel.paddingHorizontal,
139
+ },
140
+ ], testID: "Storybook.ListView", renderItem: renderItem, renderSectionHeader: renderSectionHeader, keyExtractor: keyExtractor, sections: data, stickySectionHeadersEnabled: false })));
133
141
  };
134
142
  export default React.memo(StoryListView);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/react-native",
3
- "version": "6.5.0-rc.2",
3
+ "version": "6.5.0-rc.3",
4
4
  "description": "A better way to develop React Native Components for your app",
5
5
  "keywords": [
6
6
  "react",
@@ -61,6 +61,7 @@
61
61
  "@storybook/preview-web": "^6.5.14",
62
62
  "chokidar": "^3.5.1",
63
63
  "commander": "^8.2.0",
64
+ "deepmerge": "^4.3.0",
64
65
  "emotion-theming": "^10.0.19",
65
66
  "glob": "^7.1.7",
66
67
  "jotai": "^2.0.2",
@@ -86,5 +87,5 @@
86
87
  "publishConfig": {
87
88
  "access": "public"
88
89
  },
89
- "gitHead": "f94bf2102a2e59b583d23a89f22e29afe67ef8e4"
90
+ "gitHead": "f2a1a9100ba5ddf37fa59b58518751a525eb4788"
90
91
  }
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { ViewStyle } from 'react-native';
3
- export interface Props {
4
- index: number;
5
- onPress: (id: number) => void;
6
- style: ViewStyle;
7
- }
8
- declare const _default: React.MemoExoticComponent<({ index, onPress, style }: Props) => JSX.Element>;
9
- export default _default;
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- import styled from '@emotion/native';
3
- import Button from './Button';
4
- import { NAVIGATOR, PREVIEW, ADDONS } from './constants';
5
- const Container = styled.View(({ theme }) => ({
6
- flexDirection: 'row',
7
- paddingHorizontal: 8,
8
- backgroundColor: theme.backgroundColor || 'white',
9
- borderTopWidth: 1,
10
- borderBottomWidth: 1,
11
- borderColor: theme.borderColor || '#e6e6e6',
12
- }));
13
- const Bar = ({ index, onPress, style }) => (React.createElement(Container, { style: style },
14
- React.createElement(Button, { onPress: onPress, testID: "BottomMenu.Navigator", id: NAVIGATOR, active: index === NAVIGATOR }, "NAVIGATOR"),
15
- React.createElement(Button, { onPress: onPress, testID: "BottomMenu.Preview", id: PREVIEW, active: index === PREVIEW }, "PREVIEW"),
16
- React.createElement(Button, { onPress: onPress, testID: "BottomMenu.Addons", id: ADDONS, active: index === ADDONS }, "ADDONS")));
17
- export default React.memo(Bar);
@@ -1,10 +0,0 @@
1
- import React, { ReactNode } from 'react';
2
- interface Props {
3
- id: number | string;
4
- active: boolean;
5
- onPress: (id: number | string) => void;
6
- testID?: string;
7
- children: ReactNode;
8
- }
9
- declare const _default: React.MemoExoticComponent<({ onPress, id, active, children, testID }: Props) => JSX.Element>;
10
- export default _default;
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- import { TouchableOpacity } from 'react-native';
3
- import styled from '@emotion/native';
4
- const ActiveBorder = styled.View(({ active, theme }) => ({
5
- backgroundColor: active ? theme.borderColor || '#e6e6e6' : 'transparent',
6
- height: 3,
7
- }));
8
- const ButtonText = styled.Text(({ theme, active }) => ({
9
- color: active ? theme.buttonActiveTextColor || '#444444' : theme.buttonTextColor || '#999999',
10
- paddingHorizontal: 8,
11
- paddingVertical: 10,
12
- fontSize: 11,
13
- }));
14
- const Button = ({ onPress, id, active, children, testID }) => (React.createElement(TouchableOpacity, { testID: testID, onPress: () => onPress(id), activeOpacity: 0.8 },
15
- React.createElement(ButtonText, { active: active }, children),
16
- React.createElement(ActiveBorder, { active: active })));
17
- export default React.memo(Button);
@@ -1,3 +0,0 @@
1
- export declare const Header: any;
2
- export declare const Name: any;
3
- export declare const Label: any;
@@ -1,18 +0,0 @@
1
- import styled from '@emotion/native';
2
- export const Header = styled.Text(({ theme }) => ({
3
- fontSize: 16,
4
- color: theme.headerTextColor || 'black',
5
- fontWeight: '500',
6
- }));
7
- export const Name = styled.Text({
8
- fontSize: 16,
9
- }, ({ selected, theme }) => {
10
- var _a, _b;
11
- return selected
12
- ? { fontWeight: '700', color: (_a = theme.listItemActiveTextColor) !== null && _a !== void 0 ? _a : 'white' }
13
- : { color: (_b = theme.listItemTextColor) !== null && _b !== void 0 ? _b : 'black' };
14
- });
15
- export const Label = styled.Text(({ theme }) => ({
16
- fontSize: 18,
17
- color: theme.labelColor || 'black',
18
- }));