@storybook/react-native-ui 9.0.0-beta.1 → 9.0.0-beta.10
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/index.d.ts +2 -2
- package/dist/index.js +227 -223
- package/package.json +8 -8
- package/src/MobileAddonsPanel.tsx +3 -2
- package/src/Refs.tsx +59 -59
- package/src/Search.tsx +3 -4
- package/src/SelectedNodeProvider.tsx +2 -1
- package/src/Tree.tsx +2 -3
- package/src/TreeNode.tsx +1 -2
- package/src/hooks/useExpanded.ts +3 -11
- package/src/util/StoryHash.ts +41 -36
- package/src/util/tree.ts +14 -12
- package/src/util/useStyle.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/react-native-ui",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.10",
|
|
4
4
|
"description": "ui components for react native storybook",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -49,17 +49,17 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/jest": "^29.4.3",
|
|
52
|
-
"@types/react": "~
|
|
52
|
+
"@types/react": "~19.0.10",
|
|
53
53
|
"babel-jest": "^29.7.0",
|
|
54
54
|
"jest": "^29.7.0",
|
|
55
|
-
"react-test-renderer": "^
|
|
55
|
+
"react-test-renderer": "^19.1.0",
|
|
56
56
|
"ts-dedent": "^2.2.0",
|
|
57
57
|
"tsup": "^7.2.0",
|
|
58
|
-
"typescript": "
|
|
58
|
+
"typescript": "~5.8.3"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@storybook/react": "9.0.0-beta.
|
|
62
|
-
"@storybook/react-native-theming": "^9.0.0-beta.
|
|
61
|
+
"@storybook/react": "9.0.0-beta.10",
|
|
62
|
+
"@storybook/react-native-theming": "^9.0.0-beta.10",
|
|
63
63
|
"fuse.js": "^7.0.0",
|
|
64
64
|
"memoizerific": "^1.11.3",
|
|
65
65
|
"polished": "^4.3.1",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"react-native-reanimated": ">=3",
|
|
74
74
|
"react-native-safe-area-context": "*",
|
|
75
75
|
"react-native-svg": ">=14",
|
|
76
|
-
"storybook": "9.0.0-beta.
|
|
76
|
+
"storybook": "9.0.0-beta.10"
|
|
77
77
|
},
|
|
78
78
|
"engines": {
|
|
79
79
|
"node": ">=18.0.0"
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"publishConfig": {
|
|
82
82
|
"access": "public"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "bce7f35509d03e5a5efabb8862e993ea98e201d6"
|
|
85
85
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BottomSheetModal } from '@gorhom/bottom-sheet';
|
|
2
2
|
import { addons } from 'storybook/internal/manager-api';
|
|
3
|
-
import { styled } from '@storybook/react-native-theming';
|
|
3
|
+
import { styled, useTheme } from '@storybook/react-native-theming';
|
|
4
4
|
import { Addon_TypesEnum } from 'storybook/internal/types';
|
|
5
5
|
import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
6
6
|
import { Platform, StyleProp, Text, View, ViewStyle, useWindowDimensions } from 'react-native';
|
|
@@ -12,7 +12,6 @@ import Animated, {
|
|
|
12
12
|
useSharedValue,
|
|
13
13
|
} from 'react-native-reanimated';
|
|
14
14
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
15
|
-
import { useTheme } from '@storybook/react-native-theming';
|
|
16
15
|
import { IconButton } from './IconButton';
|
|
17
16
|
import { CloseIcon } from './icon/CloseIcon';
|
|
18
17
|
import { useStyle } from './util/useStyle';
|
|
@@ -108,6 +107,8 @@ export const MobileAddonsPanel = forwardRef<MobileAddonsPanelRef, { storyId?: st
|
|
|
108
107
|
}
|
|
109
108
|
);
|
|
110
109
|
|
|
110
|
+
MobileAddonsPanel.displayName = 'MobileAddonsPanel';
|
|
111
|
+
|
|
111
112
|
const addonsTabsContainerStyle = {
|
|
112
113
|
flex: 1,
|
|
113
114
|
} satisfies StyleProp<ViewStyle>;
|
package/src/Refs.tsx
CHANGED
|
@@ -13,70 +13,70 @@ export interface RefProps {
|
|
|
13
13
|
setSelection: (selection: { refId: string; storyId: string }) => void;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const Wrapper = styled.View<{ isMain: boolean }>((
|
|
16
|
+
const Wrapper = styled.View<{ isMain: boolean }>(() => ({
|
|
17
17
|
position: 'relative',
|
|
18
18
|
}));
|
|
19
19
|
|
|
20
|
-
export const Ref: FC<RefType & RefProps & { status?: State['status'] }> = React.memo(
|
|
21
|
-
props
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const length = useMemo(() => (index ? Object.keys(index).length : 0), [index]);
|
|
20
|
+
export const Ref: FC<RefType & RefProps & { status?: State['status'] }> = React.memo(
|
|
21
|
+
function Ref(props) {
|
|
22
|
+
const {
|
|
23
|
+
index,
|
|
24
|
+
id: refId,
|
|
25
|
+
title = refId,
|
|
26
|
+
isLoading: isLoadingMain,
|
|
27
|
+
isBrowsing,
|
|
28
|
+
selectedStoryId,
|
|
29
|
+
loginUrl,
|
|
30
|
+
type,
|
|
31
|
+
expanded = true,
|
|
32
|
+
indexError,
|
|
33
|
+
previewInitialized,
|
|
34
|
+
setSelection,
|
|
35
|
+
} = props;
|
|
36
|
+
const length = useMemo(() => (index ? Object.keys(index).length : 0), [index]);
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
const isLoadingInjected =
|
|
39
|
+
(type === 'auto-inject' && !previewInitialized) || type === 'server-checked';
|
|
40
|
+
const isLoading = isLoadingMain || isLoadingInjected || type === 'unknown';
|
|
41
|
+
const isError = !!indexError;
|
|
42
|
+
const isEmpty = !isLoading && length === 0;
|
|
43
|
+
const isAuthRequired = !!loginUrl && length === 0;
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const state = getStateType(isLoading, isAuthRequired, isError, isEmpty);
|
|
46
|
+
const [isExpanded, setExpanded] = useState<boolean>(expanded);
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (index && selectedStoryId && index[selectedStoryId]) {
|
|
50
|
+
setExpanded(true);
|
|
51
|
+
}
|
|
52
|
+
}, [setExpanded, index, selectedStoryId]);
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
const onSelectStoryId = useCallback(
|
|
55
|
+
(storyId: string) => {
|
|
56
|
+
setSelection({ refId, storyId });
|
|
57
|
+
},
|
|
58
|
+
[refId, setSelection]
|
|
59
|
+
);
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
{isExpanded && (
|
|
64
|
+
<Wrapper data-title={title} isMain={true}>
|
|
65
|
+
{state === 'ready' && (
|
|
66
|
+
<Tree
|
|
67
|
+
status={props.status}
|
|
68
|
+
isBrowsing={isBrowsing}
|
|
69
|
+
isMain={true}
|
|
70
|
+
refId={refId}
|
|
71
|
+
data={index}
|
|
72
|
+
docsMode={false}
|
|
73
|
+
selectedStoryId={selectedStoryId}
|
|
74
|
+
onSelectStoryId={onSelectStoryId}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</Wrapper>
|
|
78
|
+
)}
|
|
79
|
+
</>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
);
|
package/src/Search.tsx
CHANGED
|
@@ -2,11 +2,11 @@ import { BottomSheetTextInput, useBottomSheetInternal } from '@gorhom/bottom-she
|
|
|
2
2
|
import { styled } from '@storybook/react-native-theming';
|
|
3
3
|
import type { IFuseOptions } from 'fuse.js';
|
|
4
4
|
import Fuse from 'fuse.js';
|
|
5
|
-
import React, { useCallback,
|
|
5
|
+
import React, { useCallback, useDeferredValue, useRef, useState } from 'react';
|
|
6
6
|
import { Platform, TextInput, View } from 'react-native';
|
|
7
7
|
import { CloseIcon } from './icon/CloseIcon';
|
|
8
8
|
import { SearchIcon } from './icon/SearchIcon';
|
|
9
|
-
import {
|
|
9
|
+
import { useSelectedNode } from './SelectedNodeProvider';
|
|
10
10
|
import {
|
|
11
11
|
type CombinedDataset,
|
|
12
12
|
type GetSearchItemProps,
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
type Selection,
|
|
18
18
|
} from './types';
|
|
19
19
|
import { searchItem } from './util/tree';
|
|
20
|
-
import { useSelectedNode } from './SelectedNodeProvider';
|
|
21
20
|
|
|
22
21
|
const DEFAULT_MAX_SEARCH_RESULTS = 50;
|
|
23
22
|
|
|
@@ -112,7 +111,7 @@ export const Search = React.memo<{
|
|
|
112
111
|
const [inputValue, setInputValue] = useState(initialQuery);
|
|
113
112
|
const [isOpen, setIsOpen] = useState(false);
|
|
114
113
|
const [allComponents, showAllComponents] = useState(false);
|
|
115
|
-
const { isMobile } = useLayout();
|
|
114
|
+
// const { isMobile } = useLayout();
|
|
116
115
|
const { scrollToSelectedNode } = useSelectedNode();
|
|
117
116
|
|
|
118
117
|
const selectStory = useCallback(
|
|
@@ -36,7 +36,8 @@ export const SelectedNodeProvider: FC<PropsWithChildren> = ({ children }) => {
|
|
|
36
36
|
nodeRef.current.measureLayout?.(scrollRef.current as any, (_x, y) => {
|
|
37
37
|
scrollRef.current?.scrollTo({ y: y - 100, animated: true });
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
40
|
+
} catch (_error) {}
|
|
40
41
|
}
|
|
41
42
|
}, 500);
|
|
42
43
|
}, []);
|
package/src/Tree.tsx
CHANGED
|
@@ -16,7 +16,6 @@ import { ExpandAllIcon } from './icon/ExpandAllIcon';
|
|
|
16
16
|
import { Item } from './types';
|
|
17
17
|
import type { ExpandAction, ExpandedState } from './hooks/useExpanded';
|
|
18
18
|
import { useExpanded } from './hooks/useExpanded';
|
|
19
|
-
import { getGroupStatus, statusMapping } from './util/status';
|
|
20
19
|
import { createId, getAncestorIds, getDescendantIds, isStoryHoistable } from './util/tree';
|
|
21
20
|
import { useSelectedNode } from './SelectedNodeProvider';
|
|
22
21
|
|
|
@@ -158,7 +157,7 @@ export const LeafNodeStyleWrapper = styled.View(({ theme }) => ({
|
|
|
158
157
|
borderRadius: 4,
|
|
159
158
|
}));
|
|
160
159
|
|
|
161
|
-
export const RootNode = styled.View((
|
|
160
|
+
export const RootNode = styled.View(() => ({
|
|
162
161
|
display: 'flex',
|
|
163
162
|
flexDirection: 'row',
|
|
164
163
|
alignItems: 'center',
|
|
@@ -177,7 +176,7 @@ export const RootNodeText = styled.Text(({ theme }) => ({
|
|
|
177
176
|
textTransform: 'uppercase',
|
|
178
177
|
}));
|
|
179
178
|
|
|
180
|
-
const CollapseButton = styled.TouchableOpacity((
|
|
179
|
+
const CollapseButton = styled.TouchableOpacity(() => ({
|
|
181
180
|
display: 'flex',
|
|
182
181
|
flexDirection: 'row',
|
|
183
182
|
paddingVertical: 0,
|
package/src/TreeNode.tsx
CHANGED
|
@@ -3,10 +3,9 @@ import { ComponentIcon } from './icon/ComponentIcon';
|
|
|
3
3
|
import { GroupIcon } from './icon/GroupIcon';
|
|
4
4
|
import { StoryIcon } from './icon/StoryIcon';
|
|
5
5
|
import { CollapseIcon } from './icon/CollapseIcon';
|
|
6
|
-
import { ComponentProps, FC, forwardRef, useMemo } from 'react';
|
|
6
|
+
import React, { ComponentProps, FC, forwardRef, useMemo } from 'react';
|
|
7
7
|
import { transparentize } from 'polished';
|
|
8
8
|
import { View } from 'react-native';
|
|
9
|
-
import React from 'react';
|
|
10
9
|
|
|
11
10
|
export interface NodeProps {
|
|
12
11
|
children: React.ReactNode | React.ReactNode[];
|
package/src/hooks/useExpanded.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StoriesHash } from 'storybook/internal/manager-api';
|
|
2
|
-
import type { Dispatch
|
|
2
|
+
import type { Dispatch } from 'react';
|
|
3
3
|
import { useCallback, useEffect, useReducer } from 'react';
|
|
4
4
|
import { getAncestorIds } from '../util/tree';
|
|
5
5
|
|
|
@@ -44,16 +44,8 @@ export const useExpanded = ({
|
|
|
44
44
|
}: ExpandedProps): [ExpandedState, Dispatch<ExpandAction>] => {
|
|
45
45
|
// Track the set of currently expanded nodes within this tree.
|
|
46
46
|
// Root nodes are expanded by default.
|
|
47
|
-
const [expanded, setExpanded] = useReducer
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
refId: string;
|
|
51
|
-
data: StoriesHash;
|
|
52
|
-
rootIds: string[];
|
|
53
|
-
initialExpanded: ExpandedState;
|
|
54
|
-
}
|
|
55
|
-
>(
|
|
56
|
-
(state, { ids, value }) =>
|
|
47
|
+
const [expanded, setExpanded] = useReducer(
|
|
48
|
+
(state: ExpandedState, { ids, value }: ExpandAction) =>
|
|
57
49
|
ids.reduce((acc, id) => Object.assign(acc, { [id]: value }), { ...state }),
|
|
58
50
|
{ refId, data, rootIds, initialExpanded },
|
|
59
51
|
initializeExpanded
|
package/src/util/StoryHash.ts
CHANGED
|
@@ -17,6 +17,10 @@ import type {
|
|
|
17
17
|
} from 'storybook/internal/types';
|
|
18
18
|
import countBy from 'lodash/countBy.js';
|
|
19
19
|
import { dedent } from 'ts-dedent';
|
|
20
|
+
import isEqual from 'lodash/isEqual.js';
|
|
21
|
+
import mergeWith from 'lodash/mergeWith.js';
|
|
22
|
+
import { logger } from 'storybook/internal/client-logger';
|
|
23
|
+
|
|
20
24
|
type ToStoriesHashOptions = {
|
|
21
25
|
provider: API_Provider<API>;
|
|
22
26
|
docsOptions: DocsOptions;
|
|
@@ -24,11 +28,6 @@ type ToStoriesHashOptions = {
|
|
|
24
28
|
status: State['status'];
|
|
25
29
|
};
|
|
26
30
|
|
|
27
|
-
import isEqual from 'lodash/isEqual.js';
|
|
28
|
-
import mergeWith from 'lodash/mergeWith.js';
|
|
29
|
-
|
|
30
|
-
import { logger } from 'storybook/internal/client-logger';
|
|
31
|
-
|
|
32
31
|
const merge = <TObj = any>(a: TObj, b: Partial<TObj>) =>
|
|
33
32
|
mergeWith({}, a, b, (objValue: TObj, srcValue: Partial<TObj>) => {
|
|
34
33
|
if (Array.isArray(srcValue) && Array.isArray(objValue)) {
|
|
@@ -202,16 +201,19 @@ export const transformStoryIndexToStoriesHash = (
|
|
|
202
201
|
export const transformStoryIndexV2toV3 = (index: StoryIndexV2): StoryIndexV3 => {
|
|
203
202
|
return {
|
|
204
203
|
v: 3,
|
|
205
|
-
stories: Object.values(index.stories).reduce(
|
|
206
|
-
acc
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
204
|
+
stories: Object.values(index.stories).reduce(
|
|
205
|
+
(acc, entry) => {
|
|
206
|
+
acc[entry.id] = {
|
|
207
|
+
...entry,
|
|
208
|
+
title: entry.kind,
|
|
209
|
+
name: entry.name || entry.story,
|
|
210
|
+
importPath: entry.parameters.fileName || '',
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return acc;
|
|
214
|
+
},
|
|
215
|
+
{} as StoryIndexV3['stories']
|
|
216
|
+
),
|
|
215
217
|
};
|
|
216
218
|
};
|
|
217
219
|
|
|
@@ -219,26 +221,29 @@ export const transformStoryIndexV3toV4 = (index: StoryIndexV3): API_PreparedStor
|
|
|
219
221
|
const countByTitle = countBy(Object.values(index.stories), 'title');
|
|
220
222
|
return {
|
|
221
223
|
v: 4,
|
|
222
|
-
entries: Object.values(index.stories).reduce(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
224
|
+
entries: Object.values(index.stories).reduce(
|
|
225
|
+
(acc, entry: any) => {
|
|
226
|
+
let type: IndexEntry['type'] = 'story';
|
|
227
|
+
if (
|
|
228
|
+
entry.parameters?.docsOnly ||
|
|
229
|
+
(entry.name === 'Page' && countByTitle[entry.title] === 1)
|
|
230
|
+
) {
|
|
231
|
+
type = 'docs';
|
|
232
|
+
}
|
|
233
|
+
acc[entry.id] = {
|
|
234
|
+
type,
|
|
235
|
+
...(type === 'docs' && { tags: ['stories-mdx'], storiesImports: [] }),
|
|
236
|
+
...entry,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// @ts-expect-error (we're removing something that should not be there)
|
|
240
|
+
delete acc[entry.id].story;
|
|
241
|
+
// @ts-expect-error (we're removing something that should not be there)
|
|
242
|
+
delete acc[entry.id].kind;
|
|
243
|
+
|
|
244
|
+
return acc;
|
|
245
|
+
},
|
|
246
|
+
{} as API_PreparedStoryIndex['entries']
|
|
247
|
+
),
|
|
243
248
|
};
|
|
244
249
|
};
|
package/src/util/tree.ts
CHANGED
|
@@ -29,18 +29,20 @@ export const getAncestorIds = memoize(1000)((data: IndexHash, id: string): strin
|
|
|
29
29
|
getParents(id, data).map((item) => item.id)
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
export const getDescendantIds = memoize(1000)(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
export const getDescendantIds = memoize(1000)((
|
|
33
|
+
data: IndexHash,
|
|
34
|
+
id: string,
|
|
35
|
+
skipLeafs: boolean
|
|
36
|
+
): string[] => {
|
|
37
|
+
const entry = data[id];
|
|
38
|
+
const children = entry.type === 'story' || entry.type === 'docs' ? [] : entry.children;
|
|
39
|
+
return children.reduce((acc, childId) => {
|
|
40
|
+
const child = data[childId];
|
|
41
|
+
if (!child || (skipLeafs && (child.type === 'story' || child.type === 'docs'))) return acc;
|
|
42
|
+
acc.push(childId, ...getDescendantIds(data, childId, skipLeafs));
|
|
43
|
+
return acc;
|
|
44
|
+
}, []);
|
|
45
|
+
});
|
|
44
46
|
|
|
45
47
|
export function getPath(item: Item, ref: RefType): string[] {
|
|
46
48
|
const parent = item.type !== 'root' && item.parent ? ref.index[item.parent] : null;
|
package/src/util/useStyle.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { ImageStyle, StyleProp, TextStyle, ViewStyle } from 'react-native';
|
|
|
19
19
|
*/
|
|
20
20
|
export const useStyle = <
|
|
21
21
|
TStyle extends ViewStyle | TextStyle | ImageStyle,
|
|
22
|
-
TOutput extends StyleProp<TStyle
|
|
22
|
+
TOutput extends StyleProp<TStyle>,
|
|
23
23
|
>(
|
|
24
24
|
styleFactory: () => TOutput,
|
|
25
25
|
deps?: DependencyList
|