@storybook/react-native-ui-lite 9.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +94 -0
  3. package/dist/index.js +5437 -0
  4. package/package.json +80 -0
  5. package/src/Button.stories.tsx +134 -0
  6. package/src/Button.tsx +172 -0
  7. package/src/Explorer.stories.tsx +40 -0
  8. package/src/Explorer.tsx +38 -0
  9. package/src/IconButton.tsx +10 -0
  10. package/src/Layout.stories.tsx +70 -0
  11. package/src/Layout.tsx +310 -0
  12. package/src/LayoutProvider.tsx +32 -0
  13. package/src/MobileAddonsPanel.tsx +195 -0
  14. package/src/MobileMenuDrawer.tsx +90 -0
  15. package/src/Refs.tsx +82 -0
  16. package/src/Search.tsx +234 -0
  17. package/src/SearchResults.stories.tsx +102 -0
  18. package/src/SearchResults.tsx +254 -0
  19. package/src/SelectedNodeProvider.tsx +58 -0
  20. package/src/Sidebar.stories.tsx +188 -0
  21. package/src/Sidebar.tsx +131 -0
  22. package/src/StorageProvider.tsx +21 -0
  23. package/src/StorybookLogo.stories.tsx +76 -0
  24. package/src/StorybookLogo.tsx +108 -0
  25. package/src/Tree.stories.tsx +177 -0
  26. package/src/Tree.tsx +390 -0
  27. package/src/TreeNode.stories.tsx +117 -0
  28. package/src/TreeNode.tsx +154 -0
  29. package/src/assets/react-native-logo.png +0 -0
  30. package/src/constants.ts +4 -0
  31. package/src/hooks/useExpanded.ts +64 -0
  32. package/src/hooks/useLastViewed.ts +48 -0
  33. package/src/hooks/useStoreState.ts +27 -0
  34. package/src/icon/iconDataUris.tsx +365 -0
  35. package/src/index.tsx +11 -0
  36. package/src/mockdata.large.ts +25217 -0
  37. package/src/mockdata.ts +287 -0
  38. package/src/types.ts +66 -0
  39. package/src/util/StoryHash.ts +249 -0
  40. package/src/util/status.tsx +87 -0
  41. package/src/util/tree.ts +93 -0
  42. package/src/util/useStyle.ts +28 -0
@@ -0,0 +1,287 @@
1
+ import type { API_HashEntry } from 'storybook/internal/types';
2
+
3
+ export type MockDataSet = Record<string, Record<string, Partial<API_HashEntry>>>;
4
+
5
+ export const mockDataset: MockDataSet = {
6
+ withRoot: {
7
+ 'group-1': {
8
+ type: 'group',
9
+ children: ['group-1--child-b1', 'group-1--child-b2'],
10
+ depth: 0,
11
+ id: 'group-1',
12
+ name: 'Group 1',
13
+ },
14
+ 'group-1--child-b1': {
15
+ type: 'story',
16
+ prepared: true,
17
+ id: 'group-1--child-b1',
18
+ depth: 1,
19
+ name: 'Child B1',
20
+ parent: 'group-1',
21
+ title: '',
22
+ args: {},
23
+ initialArgs: {},
24
+ importPath: './importPath.js',
25
+ },
26
+ 'group-1--child-b2': {
27
+ type: 'story',
28
+ prepared: true,
29
+ id: 'group-1--child-b2',
30
+ depth: 1,
31
+ name: 'Child B2',
32
+ parent: 'group-1',
33
+ title: '',
34
+ args: {},
35
+ initialArgs: {},
36
+ importPath: './importPath.js',
37
+ },
38
+ 'root-1': {
39
+ type: 'root',
40
+ children: ['root-1-child-a1', 'root-1-child-a2'],
41
+ depth: 0,
42
+ id: 'root-1',
43
+ name: 'Root 1',
44
+ },
45
+ 'root-1-child-a1': {
46
+ type: 'component',
47
+ id: 'root-1-child-a1',
48
+ parent: 'root-1',
49
+ depth: 1,
50
+ name: 'Child A1',
51
+ children: [],
52
+ },
53
+ 'root-1-child-a2': {
54
+ type: 'component',
55
+ id: 'root-1-child-a2',
56
+ parent: 'root-1',
57
+ name: 'Child A2',
58
+ depth: 1,
59
+ children: ['root-1-child-a2--grandchild-a1-1', 'root-1-child-a2--grandchild-a1-2'],
60
+ },
61
+ 'root-1-child-a2--grandchild-a1-1': {
62
+ type: 'story',
63
+ prepared: true,
64
+ id: 'root-1-child-a2--grandchild-a1-1',
65
+ parent: 'root-1-child-a2',
66
+ depth: 2,
67
+ name: 'GrandChild A1.1',
68
+ title: '',
69
+ args: {},
70
+ initialArgs: {},
71
+ importPath: './importPath.js',
72
+ },
73
+ 'root-1-child-a2--grandchild-a1-2': {
74
+ type: 'story',
75
+ prepared: true,
76
+ id: 'root-1-child-a2--grandchild-a1-2',
77
+ parent: 'root-1-child-a2',
78
+ depth: 2,
79
+ name: 'GrandChild A1.2',
80
+ title: '',
81
+ args: {},
82
+ initialArgs: {},
83
+ importPath: './importPath.js',
84
+ },
85
+ 'root-3': {
86
+ type: 'root',
87
+ children: ['root-3--child-a1', 'root-3-child-a2'],
88
+ depth: 0,
89
+ id: 'root-3',
90
+ name: 'Root 3',
91
+ },
92
+ 'root-3--child-a1': {
93
+ type: 'story',
94
+ prepared: true,
95
+ id: 'root-3--child-a1',
96
+ depth: 1,
97
+ name: 'Child A1',
98
+ parent: 'root-3',
99
+ title: '',
100
+ args: {},
101
+ initialArgs: {},
102
+ importPath: './importPath.js',
103
+ },
104
+ 'root-3-child-a2': {
105
+ type: 'component',
106
+ id: 'root-3-child-a2',
107
+ name: 'Child A2',
108
+ depth: 1,
109
+ children: ['root-3-child-a2--grandchild-a1-1', 'root-3-child-a2--grandchild-a1-2'],
110
+ parent: 'root-3',
111
+ },
112
+ 'root-3-child-a2--grandchild-a1-1': {
113
+ type: 'story',
114
+ prepared: true,
115
+ id: 'root-3-child-a2--grandchild-a1-1',
116
+ depth: 2,
117
+ name: 'GrandChild A1.1',
118
+ parent: 'root-3-child-a2',
119
+ title: '',
120
+ args: {},
121
+ initialArgs: {},
122
+ importPath: './importPath.js',
123
+ },
124
+ 'root-3-child-a2--grandchild-a1-2': {
125
+ type: 'story',
126
+ prepared: true,
127
+ id: 'root-3-child-a2--grandchild-a1-2',
128
+ depth: 2,
129
+ name: 'GrandChild A1.2',
130
+ parent: 'root-3-child-a2',
131
+ title: '',
132
+ args: {},
133
+ initialArgs: {},
134
+ importPath: './importPath.js',
135
+ },
136
+ },
137
+ noRoot: {
138
+ 'root-1': {
139
+ children: ['root-1-child-a1', 'root-1-child-a2'],
140
+ type: 'group',
141
+ depth: 0,
142
+ id: 'root-1',
143
+ name: 'Parent A',
144
+ },
145
+ 'group-1': {
146
+ children: ['group-1--child-b1', 'group-1--child-b2'],
147
+ type: 'component',
148
+ depth: 0,
149
+ id: 'group-1',
150
+ name: 'Parent B',
151
+ },
152
+ 'root-1-child-a1': {
153
+ id: 'root-1-child-a1',
154
+ depth: 1,
155
+ name: 'Child A1',
156
+ type: 'story',
157
+ prepared: true,
158
+ parent: 'root-1',
159
+ title: '',
160
+ args: {},
161
+ initialArgs: {},
162
+ importPath: './importPath.js',
163
+ },
164
+ 'root-1-child-a2--grandchild-a1-1': {
165
+ id: 'root-1-child-a2--grandchild-a1-1',
166
+ depth: 2,
167
+ name: 'GrandChild A1.1',
168
+ type: 'story',
169
+ prepared: true,
170
+ parent: 'root-1-child-a2',
171
+ title: '',
172
+ args: {},
173
+ initialArgs: {},
174
+ importPath: './importPath.js',
175
+ },
176
+ 'root-1-child-a2--grandchild-a1-2': {
177
+ id: 'root-1-child-a2--grandchild-a1-2',
178
+ depth: 2,
179
+ name: 'GrandChild A1.2',
180
+ type: 'story',
181
+ prepared: true,
182
+ parent: 'root-1-child-a2',
183
+ title: '',
184
+ args: {},
185
+ initialArgs: {},
186
+ importPath: './importPath.js',
187
+ },
188
+ 'root-1-child-a2': {
189
+ id: 'root-1-child-a2',
190
+ name: 'Child A2',
191
+ depth: 1,
192
+ children: ['root-1-child-a2--grandchild-a1-1', 'root-1-child-a2--grandchild-a1-2'],
193
+ type: 'component',
194
+ parent: 'root-1',
195
+ },
196
+ 'group-1--child-b1': {
197
+ id: 'group-1--child-b1',
198
+ depth: 1,
199
+ name: 'Child B1',
200
+ type: 'story',
201
+ prepared: true,
202
+ parent: 'group-1',
203
+ title: '',
204
+ args: {},
205
+ initialArgs: {},
206
+ importPath: './importPath.js',
207
+ },
208
+ 'group-1--child-b2': {
209
+ id: 'group-1--child-b2',
210
+ depth: 1,
211
+ name: 'Child B2',
212
+ type: 'story',
213
+ prepared: true,
214
+ parent: 'group-1',
215
+ title: '',
216
+ args: {},
217
+ initialArgs: {},
218
+ importPath: './importPath.js',
219
+ },
220
+ },
221
+ };
222
+
223
+ export const mockSelected = {
224
+ withRoot: {
225
+ 'root-1': false,
226
+ 'group-1': false,
227
+ 'root-1-child-a1': false,
228
+ 'root-1-child-a2--grandchild-a1-1': false,
229
+ 'root-1-child-a2--grandchild-a1-2': false,
230
+ 'root-1-child-a2': false,
231
+ 'group-1--child-b1': false,
232
+ 'group-1--child-b2': false,
233
+ 'root-3': false,
234
+ 'root-3--child-a1': false,
235
+ 'root-3-child-a2': false,
236
+ 'root-3-child-a2--grandchild-a1-1': false,
237
+ 'root-3-child-a2--grandchild-a1-2': false,
238
+ },
239
+ noRoot: {
240
+ 'root-1': false,
241
+ 'group-1': false,
242
+ 'root-1-child-a1': false,
243
+ 'root-1-child-a2--grandchild-a1-1': false,
244
+ 'root-1-child-a2--grandchild-a1-2': false,
245
+ 'root-1-child-a2': false,
246
+ 'group-1--child-b1': false,
247
+ 'group-1--child-b2': false,
248
+ },
249
+ };
250
+
251
+ export const mockExpanded = {
252
+ withRoot: {
253
+ 'root-1': true,
254
+ 'group-1': false,
255
+ 'root-1-child-a1': true,
256
+ 'root-1-child-a2--grandchild-a1-1': false,
257
+ 'root-1-child-a2--grandchild-a1-2': false,
258
+ 'root-1-child-a2': false,
259
+ 'group-1--child-b1': false,
260
+ 'group-1--child-b2': false,
261
+ 'root-3': false,
262
+ 'root-3--child-a1': false,
263
+ 'root-3-child-a2': false,
264
+ 'root-3-child-a2--grandchild-a1-1': false,
265
+ 'root-3-child-a2--grandchild-a1-2': false,
266
+ },
267
+ noRoot: {
268
+ 'root-1': true,
269
+ 'group-1': false,
270
+ 'root-1-child-a1': true,
271
+ 'root-1-child-a2--grandchild-a1-1': false,
272
+ 'root-1-child-a2--grandchild-a1-2': false,
273
+ 'root-1-child-a2': false,
274
+ 'group-1--child-b1': false,
275
+ 'group-1--child-b2': false,
276
+ },
277
+ noRootSecond: {
278
+ 'root-1': true,
279
+ 'group-1': false,
280
+ 'root-1-child-a1': true,
281
+ 'root-1-child-a2--grandchild-a1-1': true,
282
+ 'root-1-child-a2--grandchild-a1-2': true,
283
+ 'root-1-child-a2': true,
284
+ 'group-1--child-b1': false,
285
+ 'group-1--child-b2': false,
286
+ },
287
+ };
package/src/types.ts ADDED
@@ -0,0 +1,66 @@
1
+ import type { StoriesHash, State } from 'storybook/internal/manager-api';
2
+ import type { StatusValue, StatusesByStoryIdAndTypeId } from 'storybook/internal/types';
3
+ import * as Fuse from 'fuse.js';
4
+ import { PressableProps } from 'react-native';
5
+
6
+ export type Refs = State['refs'];
7
+ export type RefType = Refs[keyof Refs] & { allStatuses?: StatusesByStoryIdAndTypeId };
8
+ export type Item = StoriesHash[keyof StoriesHash];
9
+ export type Dataset = Record<string, Item>;
10
+
11
+ export interface CombinedDataset {
12
+ hash: Refs;
13
+ entries: [string, RefType][];
14
+ }
15
+
16
+ export interface ItemRef {
17
+ itemId: string;
18
+ refId: string;
19
+ }
20
+ export interface StoryRef {
21
+ storyId: string;
22
+ refId: string;
23
+ }
24
+
25
+ export type Highlight = ItemRef | null;
26
+ export type Selection = StoryRef | null;
27
+
28
+ export function isExpandType(x: any): x is ExpandType {
29
+ return !!(x && x.showAll);
30
+ }
31
+
32
+ export interface ExpandType {
33
+ showAll: () => void;
34
+ totalCount: number;
35
+ moreCount: number;
36
+ }
37
+
38
+ export type SearchItem = Item & {
39
+ refId: string;
40
+ path: string[];
41
+ status?: StatusValue;
42
+ showAll?: () => void;
43
+ };
44
+
45
+ export type SearchResult = Fuse.FuseResult<SearchItem>;
46
+
47
+ export type SearchResultProps = SearchResult & {
48
+ icon: string;
49
+ isHighlighted: boolean;
50
+ onPress: PressableProps['onPress'];
51
+ };
52
+
53
+ export type GetSearchItemProps = (args: {
54
+ item: SearchResult;
55
+ index: number;
56
+ key: string;
57
+ }) => SearchResultProps;
58
+
59
+ export type SearchChildrenFn = (args: {
60
+ query: string;
61
+ results: SearchResult[]; // TODO fix this type
62
+ isBrowsing: boolean;
63
+ closeMenu: (cb?: () => void) => void;
64
+ getItemProps: GetSearchItemProps;
65
+ highlightedIndex: number | null;
66
+ }) => React.ReactNode;
@@ -0,0 +1,249 @@
1
+ import { sanitize } from '@storybook/csf';
2
+ import { type API, type State } from 'storybook/internal/manager-api';
3
+ import type {
4
+ API_ComponentEntry,
5
+ API_DocsEntry,
6
+ API_GroupEntry,
7
+ API_HashEntry,
8
+ API_IndexHash,
9
+ API_PreparedStoryIndex,
10
+ API_Provider,
11
+ API_RootEntry,
12
+ API_StoryEntry,
13
+ DocsOptions,
14
+ IndexEntry,
15
+ StoryIndexV2,
16
+ StoryIndexV3,
17
+ } from 'storybook/internal/types';
18
+ import countBy from 'lodash/countBy.js';
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
+
24
+ type ToStoriesHashOptions = {
25
+ provider: API_Provider<API>;
26
+ docsOptions: DocsOptions;
27
+ filters: State['filters'];
28
+ status: State['status'];
29
+ };
30
+
31
+ const merge = <TObj = any>(a: TObj, b: Partial<TObj>) =>
32
+ mergeWith({}, a, b, (objValue: TObj, srcValue: Partial<TObj>) => {
33
+ if (Array.isArray(srcValue) && Array.isArray(objValue)) {
34
+ srcValue.forEach((s) => {
35
+ const existing = objValue.find((o) => o === s || isEqual(o, s));
36
+ if (!existing) {
37
+ objValue.push(s);
38
+ }
39
+ });
40
+
41
+ return objValue;
42
+ }
43
+ if (Array.isArray(objValue)) {
44
+ logger.log(['the types mismatch, picking', objValue]);
45
+ return objValue;
46
+ }
47
+ return undefined;
48
+ });
49
+
50
+ const TITLE_PATH_SEPARATOR = /\s*\/\s*/;
51
+
52
+ export const transformStoryIndexToStoriesHash = (
53
+ input: API_PreparedStoryIndex | StoryIndexV2 | StoryIndexV3,
54
+ { provider, docsOptions, filters, status }: ToStoriesHashOptions
55
+ ): API_IndexHash | any => {
56
+ if (!input.v) {
57
+ throw new Error('Composition: Missing stories.json version');
58
+ }
59
+
60
+ let index = input;
61
+ index = index.v === 2 ? transformStoryIndexV2toV3(index as any) : index;
62
+ index = index.v === 3 ? transformStoryIndexV3toV4(index as any) : index;
63
+ index = index as API_PreparedStoryIndex;
64
+
65
+ const entryValues = Object.values(index.entries).filter((entry: any) => {
66
+ let result = true;
67
+
68
+ Object.values(filters).forEach((filter: any) => {
69
+ if (result === false) {
70
+ return;
71
+ }
72
+ result = filter({ ...entry, status: status[entry.id] });
73
+ });
74
+
75
+ return result;
76
+ });
77
+
78
+ const { sidebar = {} } = provider.getConfig();
79
+ const { showRoots, collapsedRoots = [], renderLabel }: any = sidebar;
80
+
81
+ const setShowRoots = typeof showRoots !== 'undefined';
82
+
83
+ const storiesHashOutOfOrder = entryValues.reduce((acc: any, item: any) => {
84
+ if (docsOptions.docsMode && item.type !== 'docs') {
85
+ return acc;
86
+ }
87
+
88
+ // First, split the title into a set of names, separated by '/' and trimmed.
89
+ const { title } = item;
90
+ const groups = title.trim().split(TITLE_PATH_SEPARATOR);
91
+ const root = (!setShowRoots || showRoots) && groups.length > 1 ? [groups.shift()] : [];
92
+ const names = [...root, ...groups];
93
+
94
+ // Now create a "path" or sub id for each name
95
+ const paths = names.reduce((list, name, idx) => {
96
+ const parent = idx > 0 && list[idx - 1];
97
+ const id = sanitize(parent ? `${parent}-${name}` : name!);
98
+
99
+ if (parent === id) {
100
+ throw new Error(
101
+ dedent`
102
+ Invalid part '${name}', leading to id === parentId ('${id}'), inside title '${title}'
103
+
104
+ Did you create a path that uses the separator char accidentally, such as 'Vue <docs/>' where '/' is a separator char? See https://github.com/storybookjs/storybook/issues/6128
105
+ `
106
+ );
107
+ }
108
+ list.push(id);
109
+ return list;
110
+ }, [] as string[]);
111
+
112
+ // Now, let's add an entry to the hash for each path/name pair
113
+ paths.forEach((id: any, idx: any) => {
114
+ // The child is the next path, OR the story/docs entry itself
115
+ const childId = paths[idx + 1] || item.id;
116
+
117
+ if (root.length && idx === 0) {
118
+ acc[id] = merge<API_RootEntry>((acc[id] || {}) as API_RootEntry, {
119
+ type: 'root',
120
+ id,
121
+ name: names[idx],
122
+ depth: idx,
123
+ renderLabel,
124
+ startCollapsed: collapsedRoots.includes(id),
125
+ // Note that this will later get appended to the previous list of children (see below)
126
+ children: [childId],
127
+ });
128
+ // Usually the last path/name pair will be displayed as a component,
129
+ // *unless* there are other stories that are more deeply nested under it
130
+ //
131
+ // For example, if we had stories for both
132
+ // - Atoms / Button
133
+ // - Atoms / Button / LabelledButton
134
+ //
135
+ // In this example the entry for 'atoms-button' would *not* be a component.
136
+ } else if ((!acc[id] || acc[id].type === 'component') && idx === paths.length - 1) {
137
+ acc[id] = merge<API_ComponentEntry>((acc[id] || {}) as API_ComponentEntry, {
138
+ type: 'component',
139
+ id,
140
+ name: names[idx],
141
+ parent: paths[idx - 1],
142
+ depth: idx,
143
+ renderLabel,
144
+ ...(childId && {
145
+ children: [childId],
146
+ }),
147
+ });
148
+ } else {
149
+ acc[id] = merge<API_GroupEntry>((acc[id] || {}) as API_GroupEntry, {
150
+ type: 'group',
151
+ id,
152
+ name: names[idx],
153
+ parent: paths[idx - 1],
154
+ depth: idx,
155
+ renderLabel,
156
+ ...(childId && {
157
+ children: [childId],
158
+ }),
159
+ });
160
+ }
161
+ });
162
+
163
+ // Finally add an entry for the docs/story itself
164
+ acc[item.id] = {
165
+ type: 'story',
166
+ ...item,
167
+ depth: paths.length,
168
+ parent: paths[paths.length - 1],
169
+ renderLabel,
170
+ prepared: !!item.parameters,
171
+ } as API_DocsEntry | API_StoryEntry;
172
+
173
+ return acc;
174
+ }, {} as API_IndexHash);
175
+
176
+ // This function adds a "root" or "orphan" and all of its descendents to the hash.
177
+ function addItem(acc: API_IndexHash | any, item: API_HashEntry | any) {
178
+ // If we were already inserted as part of a group, that's great.
179
+ if (acc[item.id]) {
180
+ return acc;
181
+ }
182
+
183
+ acc[item.id] = item;
184
+ // Ensure we add the children depth-first *before* inserting any other entries
185
+ if (item.type === 'root' || item.type === 'group' || item.type === 'component') {
186
+ item.children.forEach((childId: any) => addItem(acc, storiesHashOutOfOrder[childId]));
187
+ }
188
+ return acc;
189
+ }
190
+
191
+ // We'll do two passes over the data, adding all the orphans, then all the roots
192
+ const orphanHash = Object.values(storiesHashOutOfOrder)
193
+ .filter((i: any) => i.type !== 'root' && !i.parent)
194
+ .reduce(addItem, {});
195
+
196
+ return Object.values(storiesHashOutOfOrder)
197
+ .filter((i: any) => i.type === 'root')
198
+ .reduce(addItem, orphanHash);
199
+ };
200
+
201
+ export const transformStoryIndexV2toV3 = (index: StoryIndexV2): StoryIndexV3 => {
202
+ return {
203
+ v: 3,
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
+ ),
217
+ };
218
+ };
219
+
220
+ export const transformStoryIndexV3toV4 = (index: StoryIndexV3): API_PreparedStoryIndex => {
221
+ const countByTitle = countBy(Object.values(index.stories), 'title');
222
+ return {
223
+ v: 4,
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
+ ),
248
+ };
249
+ };
@@ -0,0 +1,87 @@
1
+ import { useMemo, type ReactElement } from 'react';
2
+ import type {
3
+ API_HashEntry,
4
+ StatusValue,
5
+ StatusesByStoryIdAndTypeId,
6
+ } from 'storybook/internal/types';
7
+
8
+ import { useTheme } from '@storybook/react-native-theming';
9
+
10
+ import { getDescendantIds } from './tree';
11
+
12
+ function CircleIcon({ height = 14, width = 14, color, ...props }: any) {
13
+ return (
14
+ <></>
15
+ // <Svg width={width} height={height} viewBox="0 0 14 14" fill="none" {...props}>
16
+ // <Path d="M14 7A7 7 0 110 7a7 7 0 0114 0z" fill={color} />
17
+ // </Svg>
18
+ );
19
+ }
20
+
21
+ function SmallIcons(props: any) {
22
+ return <CircleIcon width={6} height={6} {...props} />;
23
+ }
24
+
25
+ function LoadingIcons(props: any) {
26
+ const theme = useTheme();
27
+
28
+ const color = useMemo(() => {
29
+ return theme.base === 'light' ? theme.color.mediumdark : theme.color.darker;
30
+ }, [theme.base, theme.color.darker, theme.color.mediumdark]);
31
+
32
+ return <SmallIcons color={color} {...props} />;
33
+ }
34
+
35
+ export const statusMapping: Record<StatusValue, [ReactElement | null, string | null]> = {
36
+ ['status-value:unknown']: [null, null],
37
+ ['status-value:pending']: [<LoadingIcons key="icon" />, 'currentColor'],
38
+ ['status-value:success']: [<SmallIcons key="icon" color="green" />, 'currentColor'],
39
+ ['status-value:warning']: [<SmallIcons key="icon" color="orange" />, '#A15C20'],
40
+ ['status-value:error']: [<SmallIcons key="icon" color="red" />, 'brown'],
41
+ };
42
+
43
+ // export const getHighestStatus = (statuses: API_StatusValue[]): API_StatusValue => {
44
+ // return statusPriority.reduce(
45
+ // (acc, status) => (statuses.includes(status) ? status : acc),
46
+ // 'unknown'
47
+ // );
48
+ // };
49
+
50
+ export const statusPriority: StatusValue[] = [
51
+ 'status-value:unknown',
52
+ 'status-value:pending',
53
+ 'status-value:success',
54
+ 'status-value:warning',
55
+ 'status-value:error',
56
+ ];
57
+
58
+ export const getMostCriticalStatusValue = (statusValues: StatusValue[]): StatusValue => {
59
+ return statusPriority.reduce(
60
+ (acc, value) => (statusValues.includes(value) ? value : acc),
61
+ 'status-value:unknown'
62
+ );
63
+ };
64
+
65
+ export function getGroupStatus(
66
+ collapsedData: {
67
+ [x: string]: Partial<API_HashEntry>;
68
+ },
69
+ allStatuses: StatusesByStoryIdAndTypeId
70
+ ): Record<string, StatusValue> {
71
+ return Object.values(collapsedData).reduce<Record<string, StatusValue>>((acc, item) => {
72
+ if (item.type === 'group' || item.type === 'component') {
73
+ const leafs = getDescendantIds(collapsedData as any, item.id, false)
74
+ .map((id) => collapsedData[id])
75
+ .filter((i) => i.type === 'story');
76
+
77
+ const combinedStatus = getMostCriticalStatusValue(
78
+ leafs.flatMap((story) => Object.values(allStatuses[story.id] || {})).map((s) => s.value)
79
+ );
80
+
81
+ if (combinedStatus) {
82
+ acc[item.id] = combinedStatus;
83
+ }
84
+ }
85
+ return acc;
86
+ }, {});
87
+ }