@storybook/react-native-ui-lite 9.0.0-beta.15 → 9.0.0-rc.5

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 CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as _storybook_react_native_theming from '@storybook/react-native-theming';
2
- import { useTheme, Theme } from '@storybook/react-native-theming';
2
+ import { useTheme } from '@storybook/react-native-theming';
3
3
  import * as react_native from 'react-native';
4
4
  import { View } from 'react-native';
5
- import React, { FC, ComponentProps, ReactNode, ReactElement } from 'react';
6
- import { Item, ExpandAction, CombinedDataset, Selection, Storage } from '@storybook/react-native-ui-common';
5
+ import React, { FC, ComponentProps, ReactNode } from 'react';
6
+ import { Item, ExpandAction, CombinedDataset, Selection, SBUI } from '@storybook/react-native-ui-common';
7
7
  import { State, StoriesHash } from 'storybook/internal/manager-api';
8
8
  import { API_LoadedRefData, API_IndexHash } from 'storybook/internal/types';
9
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -113,37 +113,44 @@ declare global {
113
113
  }
114
114
 
115
115
  interface SBBaseType {
116
- required?: boolean;
117
- raw?: string;
116
+ required?: boolean;
117
+ raw?: string;
118
118
  }
119
119
  type SBScalarType = SBBaseType & {
120
- name: 'boolean' | 'string' | 'number' | 'function' | 'symbol';
120
+ name: 'boolean' | 'string' | 'number' | 'function' | 'symbol';
121
121
  };
122
122
  type SBArrayType = SBBaseType & {
123
- name: 'array';
124
- value: SBType;
123
+ name: 'array';
124
+ value: SBType;
125
125
  };
126
126
  type SBObjectType = SBBaseType & {
127
- name: 'object';
128
- value: Record<string, SBType>;
127
+ name: 'object';
128
+ value: Record<string, SBType>;
129
129
  };
130
130
  type SBEnumType = SBBaseType & {
131
- name: 'enum';
132
- value: (string | number)[];
131
+ name: 'enum';
132
+ value: (string | number)[];
133
133
  };
134
134
  type SBIntersectionType = SBBaseType & {
135
- name: 'intersection';
136
- value: SBType[];
135
+ name: 'intersection';
136
+ value: SBType[];
137
137
  };
138
138
  type SBUnionType = SBBaseType & {
139
- name: 'union';
140
- value: SBType[];
139
+ name: 'union';
140
+ value: SBType[];
141
141
  };
142
142
  type SBOtherType = SBBaseType & {
143
- name: 'other';
144
- value: string;
143
+ name: 'other';
144
+ value: string;
145
145
  };
146
- type SBType = SBScalarType | SBEnumType | SBArrayType | SBObjectType | SBIntersectionType | SBUnionType | SBOtherType;
146
+ type SBType =
147
+ | SBScalarType
148
+ | SBEnumType
149
+ | SBArrayType
150
+ | SBObjectType
151
+ | SBIntersectionType
152
+ | SBUnionType
153
+ | SBOtherType;
147
154
 
148
155
  type StoryId = string;
149
156
  type ComponentId = string;
@@ -151,233 +158,274 @@ type ComponentTitle = string;
151
158
  type StoryName = string;
152
159
  type Tag = string;
153
160
  interface StoryIdentifier {
154
- componentId: ComponentId;
155
- title: ComponentTitle;
156
- /** @deprecated */
157
- kind: ComponentTitle;
158
- id: StoryId;
159
- name: StoryName;
160
- /** @deprecated */
161
- story: StoryName;
162
- tags: Tag[];
161
+ componentId: ComponentId;
162
+ title: ComponentTitle;
163
+ /** @deprecated */
164
+ kind: ComponentTitle;
165
+ id: StoryId;
166
+ name: StoryName;
167
+ /** @deprecated */
168
+ story: StoryName;
169
+ tags: Tag[];
163
170
  }
164
171
  interface Parameters {
165
- [name: string]: any;
172
+ [name: string]: any;
166
173
  }
167
- type ControlType = 'object' | 'boolean' | 'check' | 'inline-check' | 'radio' | 'inline-radio' | 'select' | 'multi-select' | 'number' | 'range' | 'file' | 'color' | 'date' | 'text';
168
- type ConditionalTest = {
169
- truthy?: boolean;
170
- } | {
171
- exists: boolean;
172
- } | {
173
- eq: any;
174
- } | {
175
- neq: any;
176
- };
177
- type ConditionalValue = {
178
- arg: string;
179
- } | {
180
- global: string;
181
- };
174
+ type ControlType =
175
+ | 'object'
176
+ | 'boolean'
177
+ | 'check'
178
+ | 'inline-check'
179
+ | 'radio'
180
+ | 'inline-radio'
181
+ | 'select'
182
+ | 'multi-select'
183
+ | 'number'
184
+ | 'range'
185
+ | 'file'
186
+ | 'color'
187
+ | 'date'
188
+ | 'text';
189
+ type ConditionalTest =
190
+ | {
191
+ truthy?: boolean;
192
+ }
193
+ | {
194
+ exists: boolean;
195
+ }
196
+ | {
197
+ eq: any;
198
+ }
199
+ | {
200
+ neq: any;
201
+ };
202
+ type ConditionalValue =
203
+ | {
204
+ arg: string;
205
+ }
206
+ | {
207
+ global: string;
208
+ };
182
209
  type Conditional = ConditionalValue & ConditionalTest;
183
210
  interface ControlBase {
184
- [key: string]: any;
185
- /**
186
- * @see https://storybook.js.org/docs/api/arg-types#controltype
187
- */
188
- type?: ControlType;
189
- disable?: boolean;
211
+ [key: string]: any;
212
+ /**
213
+ * @see https://storybook.js.org/docs/api/arg-types#controltype
214
+ */
215
+ type?: ControlType;
216
+ disable?: boolean;
190
217
  }
191
218
  interface Report {
192
- type: string;
193
- version?: number;
194
- result: unknown;
195
- status: 'failed' | 'passed' | 'warning';
219
+ type: string;
220
+ version?: number;
221
+ result: unknown;
222
+ status: 'failed' | 'passed' | 'warning';
196
223
  }
197
224
  interface ReportingAPI {
198
- reports: Report[];
199
- addReport: (report: Report) => void;
225
+ reports: Report[];
226
+ addReport: (report: Report) => void;
200
227
  }
201
- type Control = ControlType | false | (ControlBase & (ControlBase | {
202
- type: 'color';
203
- /**
204
- * @see https://storybook.js.org/docs/api/arg-types#controlpresetcolors
205
- */
206
- presetColors?: string[];
207
- } | {
208
- type: 'file';
209
- /**
210
- * @see https://storybook.js.org/docs/api/arg-types#controlaccept
211
- */
212
- accept?: string;
213
- } | {
214
- type: 'inline-check' | 'radio' | 'inline-radio' | 'select' | 'multi-select';
215
- /**
216
- * @see https://storybook.js.org/docs/api/arg-types#controllabels
217
- */
218
- labels?: {
219
- [options: string]: string;
220
- };
221
- } | {
222
- type: 'number' | 'range';
223
- /**
224
- * @see https://storybook.js.org/docs/api/arg-types#controlmax
225
- */
226
- max?: number;
227
- /**
228
- * @see https://storybook.js.org/docs/api/arg-types#controlmin
229
- */
230
- min?: number;
231
- /**
232
- * @see https://storybook.js.org/docs/api/arg-types#controlstep
233
- */
234
- step?: number;
235
- }));
228
+ type Control =
229
+ | ControlType
230
+ | false
231
+ | (ControlBase &
232
+ (
233
+ | ControlBase
234
+ | {
235
+ type: 'color';
236
+ /**
237
+ * @see https://storybook.js.org/docs/api/arg-types#controlpresetcolors
238
+ */
239
+ presetColors?: string[];
240
+ }
241
+ | {
242
+ type: 'file';
243
+ /**
244
+ * @see https://storybook.js.org/docs/api/arg-types#controlaccept
245
+ */
246
+ accept?: string;
247
+ }
248
+ | {
249
+ type: 'inline-check' | 'radio' | 'inline-radio' | 'select' | 'multi-select';
250
+ /**
251
+ * @see https://storybook.js.org/docs/api/arg-types#controllabels
252
+ */
253
+ labels?: {
254
+ [options: string]: string;
255
+ };
256
+ }
257
+ | {
258
+ type: 'number' | 'range';
259
+ /**
260
+ * @see https://storybook.js.org/docs/api/arg-types#controlmax
261
+ */
262
+ max?: number;
263
+ /**
264
+ * @see https://storybook.js.org/docs/api/arg-types#controlmin
265
+ */
266
+ min?: number;
267
+ /**
268
+ * @see https://storybook.js.org/docs/api/arg-types#controlstep
269
+ */
270
+ step?: number;
271
+ }
272
+ ));
236
273
  interface InputType {
274
+ /**
275
+ * @see https://storybook.js.org/docs/api/arg-types#control
276
+ */
277
+ control?: Control;
278
+ /**
279
+ * @see https://storybook.js.org/docs/api/arg-types#description
280
+ */
281
+ description?: string;
282
+ /**
283
+ * @see https://storybook.js.org/docs/api/arg-types#if
284
+ */
285
+ if?: Conditional;
286
+ /**
287
+ * @see https://storybook.js.org/docs/api/arg-types#mapping
288
+ */
289
+ mapping?: {
290
+ [key: string]: any;
291
+ };
292
+ /**
293
+ * @see https://storybook.js.org/docs/api/arg-types#name
294
+ */
295
+ name?: string;
296
+ /**
297
+ * @see https://storybook.js.org/docs/api/arg-types#options
298
+ */
299
+ options?: readonly any[];
300
+ /**
301
+ * @see https://storybook.js.org/docs/api/arg-types#table
302
+ */
303
+ table?: {
304
+ [key: string]: unknown;
237
305
  /**
238
- * @see https://storybook.js.org/docs/api/arg-types#control
239
- */
240
- control?: Control;
241
- /**
242
- * @see https://storybook.js.org/docs/api/arg-types#description
243
- */
244
- description?: string;
245
- /**
246
- * @see https://storybook.js.org/docs/api/arg-types#if
306
+ * @see https://storybook.js.org/docs/api/arg-types#tablecategory
247
307
  */
248
- if?: Conditional;
308
+ category?: string;
249
309
  /**
250
- * @see https://storybook.js.org/docs/api/arg-types#mapping
310
+ * @see https://storybook.js.org/docs/api/arg-types#tabledefaultvalue
251
311
  */
252
- mapping?: {
253
- [key: string]: any;
312
+ defaultValue?: {
313
+ summary?: string;
314
+ detail?: string;
254
315
  };
255
316
  /**
256
- * @see https://storybook.js.org/docs/api/arg-types#name
317
+ * @see https://storybook.js.org/docs/api/arg-types#tabledisable
257
318
  */
258
- name?: string;
319
+ disable?: boolean;
259
320
  /**
260
- * @see https://storybook.js.org/docs/api/arg-types#options
321
+ * @see https://storybook.js.org/docs/api/arg-types#tablesubcategory
261
322
  */
262
- options?: readonly any[];
323
+ subcategory?: string;
263
324
  /**
264
- * @see https://storybook.js.org/docs/api/arg-types#table
325
+ * @see https://storybook.js.org/docs/api/arg-types#tabletype
265
326
  */
266
- table?: {
267
- [key: string]: unknown;
268
- /**
269
- * @see https://storybook.js.org/docs/api/arg-types#tablecategory
270
- */
271
- category?: string;
272
- /**
273
- * @see https://storybook.js.org/docs/api/arg-types#tabledefaultvalue
274
- */
275
- defaultValue?: {
276
- summary?: string;
277
- detail?: string;
278
- };
279
- /**
280
- * @see https://storybook.js.org/docs/api/arg-types#tabledisable
281
- */
282
- disable?: boolean;
283
- /**
284
- * @see https://storybook.js.org/docs/api/arg-types#tablesubcategory
285
- */
286
- subcategory?: string;
287
- /**
288
- * @see https://storybook.js.org/docs/api/arg-types#tabletype
289
- */
290
- type?: {
291
- summary?: string;
292
- detail?: string;
293
- };
327
+ type?: {
328
+ summary?: string;
329
+ detail?: string;
294
330
  };
295
- /**
296
- * @see https://storybook.js.org/docs/api/arg-types#type
297
- */
298
- type?: SBType | SBScalarType['name'];
299
- /**
300
- * @see https://storybook.js.org/docs/api/arg-types#defaultvalue
301
- *
302
- * @deprecated Use `table.defaultValue.summary` instead.
303
- */
304
- defaultValue?: any;
305
- [key: string]: any;
331
+ };
332
+ /**
333
+ * @see https://storybook.js.org/docs/api/arg-types#type
334
+ */
335
+ type?: SBType | SBScalarType['name'];
336
+ /**
337
+ * @see https://storybook.js.org/docs/api/arg-types#defaultvalue
338
+ *
339
+ * @deprecated Use `table.defaultValue.summary` instead.
340
+ */
341
+ defaultValue?: any;
342
+ [key: string]: any;
306
343
  }
307
344
  interface StrictInputType extends InputType {
308
- name: string;
309
- type?: SBType;
345
+ name: string;
346
+ type?: SBType;
310
347
  }
311
348
  interface Args {
312
- [name: string]: any;
349
+ [name: string]: any;
313
350
  }
314
351
  type StrictArgTypes<TArgs = Args> = {
315
- [name in keyof TArgs]: StrictInputType;
352
+ [name in keyof TArgs]: StrictInputType;
316
353
  };
317
354
  interface Globals {
318
- [name: string]: any;
355
+ [name: string]: any;
319
356
  }
320
357
  interface Renderer {
321
- /** What is the type of the `component` annotation in this renderer? */
322
- component: unknown;
323
- /** What does the story function return in this renderer? */
324
- storyResult: unknown;
325
- /** What type of element does this renderer render to? */
326
- canvasElement: unknown;
327
- mount(): Promise<Canvas>;
328
- T?: unknown;
358
+ /** What is the type of the `component` annotation in this renderer? */
359
+ component: unknown;
360
+ /** What does the story function return in this renderer? */
361
+ storyResult: unknown;
362
+ /** What type of element does this renderer render to? */
363
+ canvasElement: unknown;
364
+ mount(): Promise<Canvas>;
365
+ T?: unknown;
329
366
  }
330
- interface StoryContextForEnhancers<TRenderer extends Renderer = Renderer, TArgs = Args> extends StoryIdentifier {
331
- component?: (TRenderer & {
332
- T: any;
333
- })['component'];
334
- subcomponents?: Record<string, (TRenderer & {
335
- T: any;
336
- })['component']>;
337
- parameters: Parameters;
338
- initialArgs: TArgs;
339
- argTypes: StrictArgTypes<TArgs>;
367
+ interface StoryContextForEnhancers<TRenderer extends Renderer = Renderer, TArgs = Args>
368
+ extends StoryIdentifier {
369
+ component?: (TRenderer & {
370
+ T: any;
371
+ })['component'];
372
+ subcomponents?: Record<
373
+ string,
374
+ (TRenderer & {
375
+ T: any;
376
+ })['component']
377
+ >;
378
+ parameters: Parameters;
379
+ initialArgs: TArgs;
380
+ argTypes: StrictArgTypes<TArgs>;
340
381
  }
341
382
  interface StoryContextUpdate<TArgs = Args> {
342
- args?: TArgs;
343
- globals?: Globals;
344
- [key: string]: any;
383
+ args?: TArgs;
384
+ globals?: Globals;
385
+ [key: string]: any;
345
386
  }
346
387
  type ViewMode = 'story' | 'docs';
347
- interface Canvas {
348
- }
349
- interface StoryContext<TRenderer extends Renderer = Renderer, TArgs = Args> extends StoryContextForEnhancers<TRenderer, TArgs>, Required<StoryContextUpdate<TArgs>> {
350
- loaded: Record<string, any>;
351
- abortSignal: AbortSignal;
352
- canvasElement: TRenderer['canvasElement'];
353
- hooks: unknown;
354
- originalStoryFn: StoryFn<TRenderer>;
355
- viewMode: ViewMode;
356
- step: StepFunction<TRenderer, TArgs>;
357
- context: this;
358
- canvas: Canvas;
359
- mount: TRenderer['mount'];
360
- reporting: ReportingAPI;
388
+ interface Canvas {}
389
+ interface StoryContext<TRenderer extends Renderer = Renderer, TArgs = Args>
390
+ extends StoryContextForEnhancers<TRenderer, TArgs>,
391
+ Required<StoryContextUpdate<TArgs>> {
392
+ loaded: Record<string, any>;
393
+ abortSignal: AbortSignal;
394
+ canvasElement: TRenderer['canvasElement'];
395
+ hooks: unknown;
396
+ originalStoryFn: StoryFn<TRenderer>;
397
+ viewMode: ViewMode;
398
+ step: StepFunction<TRenderer, TArgs>;
399
+ context: this;
400
+ canvas: Canvas;
401
+ mount: TRenderer['mount'];
402
+ reporting: ReportingAPI;
361
403
  }
362
404
  /** @deprecated Use {@link StoryContext} instead. */
363
- interface PlayFunctionContext<TRenderer extends Renderer = Renderer, TArgs = Args> extends StoryContext<TRenderer, TArgs> {
364
- }
405
+ interface PlayFunctionContext<TRenderer extends Renderer = Renderer, TArgs = Args>
406
+ extends StoryContext<TRenderer, TArgs> {}
365
407
  type StepLabel = string;
366
- type StepFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (label: StepLabel, play: PlayFunction<TRenderer, TArgs>) => Promise<void> | void;
367
- type PlayFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (context: PlayFunctionContext<TRenderer, TArgs>) => Promise<void> | void;
368
- type LegacyStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (context: StoryContext<TRenderer, TArgs>) => TRenderer['storyResult'];
369
- type ArgsStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (args: TArgs, context: StoryContext<TRenderer, TArgs>) => (TRenderer & {
370
- T: TArgs;
408
+ type StepFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (
409
+ label: StepLabel,
410
+ play: PlayFunction<TRenderer, TArgs>
411
+ ) => Promise<void> | void;
412
+ type PlayFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (
413
+ context: PlayFunctionContext<TRenderer, TArgs>
414
+ ) => Promise<void> | void;
415
+ type LegacyStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (
416
+ context: StoryContext<TRenderer, TArgs>
417
+ ) => TRenderer['storyResult'];
418
+ type ArgsStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (
419
+ args: TArgs,
420
+ context: StoryContext<TRenderer, TArgs>
421
+ ) => (TRenderer & {
422
+ T: TArgs;
371
423
  })['storyResult'];
372
- type StoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = LegacyStoryFn<TRenderer, TArgs> | ArgsStoryFn<TRenderer, TArgs>;
424
+ type StoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> =
425
+ | LegacyStoryFn<TRenderer, TArgs>
426
+ | ArgsStoryFn<TRenderer, TArgs>;
373
427
 
374
- declare const LiteUI: ({ storage, theme, storyHash, story, children, }: {
375
- storage: Storage;
376
- theme: Theme;
377
- storyHash: API_IndexHash | undefined;
378
- story?: StoryContext<ReactRenderer, Args>;
379
- children: ReactNode | ReactNode[];
380
- }) => ReactElement;
428
+ declare const LiteUI: SBUI;
381
429
  declare const Layout: ({ storyHash, story, children, }: {
382
430
  storyHash: API_IndexHash | undefined;
383
431
  story?: StoryContext<ReactRenderer, Args>;
package/dist/index.js CHANGED
@@ -662,6 +662,7 @@ var Tree = import_react4.default.memo(function Tree2({ isMain, refId, data, stat
662
662
  }, [data]);
663
663
  const collapsedItems = (0, import_react4.useMemo)(
664
664
  () => Object.keys(data).filter((id) => !singleStoryComponentIds.includes(id)),
665
+ // eslint-disable-next-line react-compiler/react-compiler
665
666
  // eslint-disable-next-line react-hooks/exhaustive-deps
666
667
  [singleStoryComponentIds]
667
668
  );
@@ -1372,6 +1373,55 @@ var MobileAddonsPanel = (0, import_react12.forwardRef)(
1372
1373
  ({ storyId }, ref) => {
1373
1374
  const theme = (0, import_react_native_theming8.useTheme)();
1374
1375
  const [mobileMenuOpen, setMobileMenuOpen] = (0, import_react12.useState)(false);
1376
+ const { height } = (0, import_react_native6.useWindowDimensions)();
1377
+ const panelHeight = (0, import_react_native6.useAnimatedValue)(height / 2);
1378
+ const positionBottomAnimation = (0, import_react_native6.useAnimatedValue)(0);
1379
+ (0, import_react12.useEffect)(() => {
1380
+ const handleKeyboardShow = ({ endCoordinates, duration, easing }) => {
1381
+ import_react_native6.Animated.parallel([
1382
+ import_react_native6.Animated.timing(positionBottomAnimation, {
1383
+ toValue: -endCoordinates.height,
1384
+ // Negative to move up
1385
+ duration,
1386
+ useNativeDriver: false,
1387
+ easing: import_react_native6.Easing[easing] || import_react_native6.Easing.out(import_react_native6.Easing.ease)
1388
+ }),
1389
+ import_react_native6.Animated.timing(panelHeight, {
1390
+ toValue: (height - endCoordinates.height) / 2,
1391
+ duration: duration + 250,
1392
+ useNativeDriver: false,
1393
+ easing: import_react_native6.Easing[easing] || import_react_native6.Easing.out(import_react_native6.Easing.ease)
1394
+ })
1395
+ ]).start();
1396
+ };
1397
+ const handleKeyboardHide = ({ duration, easing }) => {
1398
+ import_react_native6.Animated.parallel([
1399
+ import_react_native6.Animated.timing(positionBottomAnimation, {
1400
+ toValue: 0,
1401
+ // Back to original position
1402
+ duration,
1403
+ useNativeDriver: false,
1404
+ easing: import_react_native6.Easing[easing] || import_react_native6.Easing.out(import_react_native6.Easing.ease)
1405
+ }),
1406
+ import_react_native6.Animated.timing(panelHeight, {
1407
+ toValue: height / 2,
1408
+ duration,
1409
+ useNativeDriver: false,
1410
+ easing: import_react_native6.Easing[easing] || import_react_native6.Easing.out(import_react_native6.Easing.ease)
1411
+ })
1412
+ ]).start();
1413
+ };
1414
+ const showSubscription = import_react_native6.Keyboard.addListener("keyboardDidShow", handleKeyboardShow);
1415
+ const willShowSubscription = import_react_native6.Keyboard.addListener("keyboardWillShow", handleKeyboardShow);
1416
+ const hideSubscription = import_react_native6.Keyboard.addListener("keyboardWillHide", handleKeyboardHide);
1417
+ const didHideSubscription = import_react_native6.Keyboard.addListener("keyboardDidHide", handleKeyboardHide);
1418
+ return () => {
1419
+ showSubscription.remove();
1420
+ willShowSubscription.remove();
1421
+ hideSubscription.remove();
1422
+ didHideSubscription.remove();
1423
+ };
1424
+ }, [height, panelHeight, positionBottomAnimation]);
1375
1425
  (0, import_react12.useImperativeHandle)(ref, () => ({
1376
1426
  setAddonsPanelOpen: (open) => {
1377
1427
  if (open) {
@@ -1381,34 +1431,50 @@ var MobileAddonsPanel = (0, import_react12.forwardRef)(
1381
1431
  }
1382
1432
  }
1383
1433
  }));
1434
+ if (!mobileMenuOpen) {
1435
+ return null;
1436
+ }
1384
1437
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1385
- import_react_native6.Modal,
1438
+ import_react_native6.Animated.View,
1386
1439
  {
1387
- visible: mobileMenuOpen,
1388
- onRequestClose: () => setMobileMenuOpen(false),
1389
- transparent: true,
1390
- animationType: "slide",
1391
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native6.KeyboardAvoidingView, { behavior: "height", style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native6.SafeAreaView, { style: { justifyContent: "flex-end", flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1392
- import_react_native6.View,
1440
+ style: {
1441
+ position: "absolute",
1442
+ bottom: 0,
1443
+ left: 0,
1444
+ right: 0,
1445
+ height: panelHeight,
1446
+ transform: [{ translateY: positionBottomAnimation }]
1447
+ },
1448
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1449
+ import_react_native6.SafeAreaView,
1393
1450
  {
1394
1451
  style: {
1395
- height: "50%",
1396
- backgroundColor: theme.background.content,
1397
- paddingTop: 10,
1398
- borderTopColor: theme.appBorderColor,
1399
- borderTopWidth: 1
1452
+ justifyContent: "flex-end"
1400
1453
  },
1401
1454
  children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1402
- AddonsTabs,
1455
+ import_react_native6.View,
1403
1456
  {
1404
- onClose: () => {
1405
- setMobileMenuOpen(false);
1457
+ style: {
1458
+ height: "100%",
1459
+ backgroundColor: theme.background.content,
1460
+ paddingTop: 10,
1461
+ borderTopColor: theme.appBorderColor,
1462
+ borderTopWidth: 1,
1463
+ paddingBottom: import_react_native6.Platform.OS === "android" ? 16 : 0
1406
1464
  },
1407
- storyId
1465
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1466
+ AddonsTabs,
1467
+ {
1468
+ onClose: () => {
1469
+ setMobileMenuOpen(false);
1470
+ },
1471
+ storyId
1472
+ }
1473
+ )
1408
1474
  }
1409
1475
  )
1410
1476
  }
1411
- ) }) })
1477
+ )
1412
1478
  }
1413
1479
  );
1414
1480
  }
@@ -1524,10 +1590,36 @@ var MobileMenuDrawer = (0, import_react13.memo)(
1524
1590
  (0, import_react13.forwardRef)(({ children }, ref) => {
1525
1591
  const [mobileMenuOpen, setMobileMenuOpen] = (0, import_react13.useState)(false);
1526
1592
  const { scrollToSelectedNode, scrollRef } = useSelectedNode();
1527
- const { height } = (0, import_react_native7.useWindowDimensions)();
1593
+ const theme = (0, import_react_native_theming9.useTheme)();
1594
+ const dragY = (0, import_react_native7.useAnimatedValue)(0);
1595
+ const panResponder = (0, import_react13.useRef)(
1596
+ import_react_native7.PanResponder.create({
1597
+ onStartShouldSetPanResponder: () => true,
1598
+ onMoveShouldSetPanResponder: (_, gestureState) => {
1599
+ return gestureState.dy > 0;
1600
+ },
1601
+ onPanResponderMove: (_, gestureState) => {
1602
+ if (gestureState.dy > 0) {
1603
+ dragY.setValue(gestureState.dy);
1604
+ }
1605
+ },
1606
+ onPanResponderRelease: (_, gestureState) => {
1607
+ if (gestureState.dy > 50) {
1608
+ import_react_native7.Keyboard.dismiss();
1609
+ setMobileMenuOpen(false);
1610
+ }
1611
+ import_react_native7.Animated.timing(dragY, {
1612
+ toValue: 0,
1613
+ duration: 300,
1614
+ useNativeDriver: true
1615
+ }).start();
1616
+ }
1617
+ })
1618
+ ).current;
1528
1619
  (0, import_react13.useImperativeHandle)(ref, () => ({
1529
1620
  setMobileMenuOpen: (open) => {
1530
1621
  if (open) {
1622
+ dragY.setValue(0);
1531
1623
  scrollToSelectedNode();
1532
1624
  setMobileMenuOpen(true);
1533
1625
  } else {
@@ -1536,48 +1628,73 @@ var MobileMenuDrawer = (0, import_react13.memo)(
1536
1628
  }
1537
1629
  }
1538
1630
  }));
1539
- const theme = (0, import_react_native_theming9.useTheme)();
1540
- const bgColorStyle = (0, import_react13.useMemo)(() => {
1541
- return {
1542
- marginTop: "auto",
1543
- backgroundColor: theme.background.content,
1544
- height,
1545
- width: "100%",
1546
- overflow: "hidden"
1547
- };
1548
- }, [height, theme.background.content]);
1631
+ const handleStyle = (0, import_react13.useMemo)(
1632
+ () => ({
1633
+ width: 40,
1634
+ height: 5,
1635
+ backgroundColor: theme.color.mediumdark,
1636
+ borderRadius: 2.5,
1637
+ alignSelf: "center",
1638
+ // TypeScript needs this to recognize 'center' as a valid FlexAlignType
1639
+ marginVertical: 8
1640
+ }),
1641
+ [theme.color.mediumdark]
1642
+ );
1549
1643
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1550
1644
  import_react_native7.Modal,
1551
1645
  {
1552
1646
  visible: mobileMenuOpen,
1553
- style: bgColorStyle,
1554
1647
  animationType: "slide",
1555
1648
  transparent: true,
1649
+ statusBarTranslucent: true,
1556
1650
  onRequestClose: () => setMobileMenuOpen(false),
1557
1651
  children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.KeyboardAvoidingView, { behavior: "height", style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native7.SafeAreaView, { style: { justifyContent: "flex-end", flex: 1 }, children: [
1558
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1559
- import_react_native7.View,
1652
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.View, { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.Pressable, { style: { flex: 1 }, onPress: () => setMobileMenuOpen(false) }) }),
1653
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1654
+ import_react_native7.Animated.View,
1560
1655
  {
1561
- style: { flex: 1, borderBottomColor: theme.appBorderColor, borderBottomWidth: 1 },
1562
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.Pressable, { style: { flex: 1 }, onPress: () => setMobileMenuOpen(false) })
1563
- }
1564
- ),
1565
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.View, { style: { height: "65%" }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1566
- import_react_native7.ScrollView,
1567
- {
1568
- ref: scrollRef,
1569
- keyboardShouldPersistTaps: "handled",
1570
- style: {
1571
- flex: 1,
1572
- paddingBottom: 150,
1573
- paddingTop: 24,
1574
- alignSelf: "flex-end",
1575
- width: "100%",
1576
- backgroundColor: theme.background.content
1577
- },
1578
- children
1656
+ style: [
1657
+ {
1658
+ height: "65%",
1659
+ borderTopColor: theme.appBorderColor,
1660
+ borderTopWidth: 1,
1661
+ borderStyle: "solid",
1662
+ backgroundColor: theme.background.content,
1663
+ elevation: 8
1664
+ },
1665
+ { transform: [{ translateY: dragY }] }
1666
+ ],
1667
+ children: [
1668
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1669
+ import_react_native7.View,
1670
+ {
1671
+ ...panResponder.panHandlers,
1672
+ style: {
1673
+ alignItems: "center",
1674
+ justifyContent: "center",
1675
+ backgroundColor: theme.background.content
1676
+ },
1677
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.View, { style: handleStyle })
1678
+ }
1679
+ ),
1680
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1681
+ import_react_native7.ScrollView,
1682
+ {
1683
+ ref: scrollRef,
1684
+ keyboardShouldPersistTaps: "handled",
1685
+ style: {
1686
+ flex: 1,
1687
+ paddingBottom: 150,
1688
+ alignSelf: "flex-end",
1689
+ width: "100%",
1690
+ backgroundColor: theme.background.content
1691
+ },
1692
+ children
1693
+ }
1694
+ )
1695
+ ]
1579
1696
  }
1580
- ) })
1697
+ )
1581
1698
  ] }) })
1582
1699
  }
1583
1700
  );
@@ -1691,13 +1808,7 @@ var mobileMenuDrawerContentStyle = {
1691
1808
  paddingTop: 4,
1692
1809
  paddingBottom: 4
1693
1810
  };
1694
- var LiteUI = ({
1695
- storage,
1696
- theme,
1697
- storyHash,
1698
- story,
1699
- children
1700
- }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_theming10.ThemeProvider, { theme, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_ui_common7.StorageProvider, { storage, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_ui_common7.LayoutProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Layout, { storyHash, story, children }) }) }) }) });
1811
+ var LiteUI = ({ storage, theme, storyHash, story, children }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_theming10.ThemeProvider, { theme, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_ui_common7.StorageProvider, { storage, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_ui_common7.LayoutProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Layout, { storyHash, story, children }) }) }) }) });
1701
1812
  var Layout = ({
1702
1813
  storyHash,
1703
1814
  story,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/react-native-ui-lite",
3
- "version": "9.0.0-beta.15",
3
+ "version": "9.0.0-rc.5",
4
4
  "description": "lightweight ui components for react native storybook",
5
5
  "keywords": [
6
6
  "react",
@@ -58,9 +58,9 @@
58
58
  "typescript": "~5.8.3"
59
59
  },
60
60
  "dependencies": {
61
- "@storybook/react": "9.0.0-beta.10",
62
- "@storybook/react-native-theming": "^9.0.0-beta.15",
63
- "@storybook/react-native-ui-common": "^9.0.0-beta.15",
61
+ "@storybook/react": "^9",
62
+ "@storybook/react-native-theming": "^9.0.0-rc.5",
63
+ "@storybook/react-native-ui-common": "^9.0.0-rc.5",
64
64
  "fuse.js": "^7.0.0",
65
65
  "memoizerific": "^1.11.3",
66
66
  "polished": "^4.3.1",
@@ -69,7 +69,7 @@
69
69
  "peerDependencies": {
70
70
  "react": "*",
71
71
  "react-native": ">=0.57.0",
72
- "storybook": "9.0.0-beta.10"
72
+ "storybook": "^9"
73
73
  },
74
74
  "engines": {
75
75
  "node": ">=18.0.0"
@@ -77,5 +77,5 @@
77
77
  "publishConfig": {
78
78
  "access": "public"
79
79
  },
80
- "gitHead": "905adcca4ea272933c7f0fa16f10dda201da9a5f"
80
+ "gitHead": "bed522706a1296d1550ff4446045b71d53e0902d"
81
81
  }
package/src/Layout.tsx CHANGED
@@ -1,10 +1,10 @@
1
1
  import type { Args, StoryContext } from '@storybook/csf';
2
2
  import type { ReactRenderer } from '@storybook/react';
3
- import { styled, Theme, ThemeProvider, useTheme } from '@storybook/react-native-theming';
3
+ import { styled, ThemeProvider, useTheme } from '@storybook/react-native-theming';
4
4
  import {
5
5
  IconButton,
6
6
  LayoutProvider,
7
- Storage,
7
+ SBUI,
8
8
  StorageProvider,
9
9
  useLayout,
10
10
  useStoreBooleanState,
@@ -64,19 +64,7 @@ const mobileMenuDrawerContentStyle = {
64
64
  paddingBottom: 4,
65
65
  } satisfies ViewStyle;
66
66
 
67
- export const LiteUI = ({
68
- storage,
69
- theme,
70
- storyHash,
71
- story,
72
- children,
73
- }: {
74
- storage: Storage;
75
- theme: Theme;
76
- storyHash: API_IndexHash | undefined;
77
- story?: StoryContext<ReactRenderer, Args>;
78
- children: ReactNode | ReactNode[];
79
- }): ReactElement => (
67
+ export const LiteUI: SBUI = ({ storage, theme, storyHash, story, children }): ReactElement => (
80
68
  <>
81
69
  <ThemeProvider theme={theme}>
82
70
  {/* @ts-ignore something weird with story type */}
@@ -1,12 +1,16 @@
1
1
  import { styled, useTheme } from '@storybook/react-native-theming';
2
- import { forwardRef, useImperativeHandle, useMemo, useState } from 'react';
2
+ import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react';
3
3
  import {
4
- KeyboardAvoidingView,
5
- Modal,
4
+ Animated,
5
+ Easing,
6
+ Keyboard,
7
+ Platform,
6
8
  SafeAreaView,
7
9
  ScrollView,
8
10
  StyleProp,
9
11
  Text,
12
+ useAnimatedValue,
13
+ useWindowDimensions,
10
14
  View,
11
15
  ViewStyle,
12
16
  } from 'react-native';
@@ -23,6 +27,63 @@ export const MobileAddonsPanel = forwardRef<MobileAddonsPanelRef, { storyId?: st
23
27
  ({ storyId }, ref) => {
24
28
  const theme = useTheme();
25
29
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
30
+ const { height } = useWindowDimensions();
31
+ const panelHeight = useAnimatedValue(height / 2);
32
+ const positionBottomAnimation = useAnimatedValue(0);
33
+
34
+ useEffect(() => {
35
+ // Define keyboard show handler
36
+ const handleKeyboardShow = ({ endCoordinates, duration, easing }) => {
37
+ Animated.parallel([
38
+ Animated.timing(positionBottomAnimation, {
39
+ toValue: -endCoordinates.height, // Negative to move up
40
+ duration,
41
+ useNativeDriver: false,
42
+ easing: Easing[easing] || Easing.out(Easing.ease),
43
+ }),
44
+
45
+ Animated.timing(panelHeight, {
46
+ toValue: (height - endCoordinates.height) / 2,
47
+ duration: duration + 250,
48
+ useNativeDriver: false,
49
+ easing: Easing[easing] || Easing.out(Easing.ease),
50
+ }),
51
+ ]).start();
52
+ };
53
+
54
+ // Define keyboard hide handler
55
+ const handleKeyboardHide = ({ duration, easing }) => {
56
+ Animated.parallel([
57
+ Animated.timing(positionBottomAnimation, {
58
+ toValue: 0, // Back to original position
59
+ duration,
60
+ useNativeDriver: false,
61
+ easing: Easing[easing] || Easing.out(Easing.ease),
62
+ }),
63
+
64
+ Animated.timing(panelHeight, {
65
+ toValue: height / 2,
66
+ duration,
67
+ useNativeDriver: false,
68
+ easing: Easing[easing] || Easing.out(Easing.ease),
69
+ }),
70
+ ]).start();
71
+ };
72
+
73
+ // Add keyboard event listeners
74
+ const showSubscription = Keyboard.addListener('keyboardDidShow', handleKeyboardShow);
75
+ const willShowSubscription = Keyboard.addListener('keyboardWillShow', handleKeyboardShow);
76
+ const hideSubscription = Keyboard.addListener('keyboardWillHide', handleKeyboardHide);
77
+ const didHideSubscription = Keyboard.addListener('keyboardDidHide', handleKeyboardHide);
78
+
79
+ // Clean up subscriptions on unmount
80
+ return () => {
81
+ showSubscription.remove();
82
+ willShowSubscription.remove();
83
+ hideSubscription.remove();
84
+ didHideSubscription.remove();
85
+ };
86
+ }, [height, panelHeight, positionBottomAnimation]);
26
87
 
27
88
  useImperativeHandle(ref, () => ({
28
89
  setAddonsPanelOpen: (open: boolean) => {
@@ -34,34 +95,45 @@ export const MobileAddonsPanel = forwardRef<MobileAddonsPanelRef, { storyId?: st
34
95
  },
35
96
  }));
36
97
 
98
+ if (!mobileMenuOpen) {
99
+ return null;
100
+ }
101
+
37
102
  return (
38
- <Modal
39
- visible={mobileMenuOpen}
40
- onRequestClose={() => setMobileMenuOpen(false)}
41
- transparent
42
- animationType="slide"
103
+ <Animated.View
104
+ style={{
105
+ position: 'absolute',
106
+ bottom: 0,
107
+ left: 0,
108
+ right: 0,
109
+ height: panelHeight,
110
+ transform: [{ translateY: positionBottomAnimation }],
111
+ }}
43
112
  >
44
- <KeyboardAvoidingView behavior="height" style={{ flex: 1 }}>
45
- <SafeAreaView style={{ justifyContent: 'flex-end', flex: 1 }}>
46
- <View
47
- style={{
48
- height: '50%',
49
- backgroundColor: theme.background.content,
50
- paddingTop: 10,
51
- borderTopColor: theme.appBorderColor,
52
- borderTopWidth: 1,
113
+ <SafeAreaView
114
+ style={{
115
+ justifyContent: 'flex-end',
116
+ }}
117
+ >
118
+ <View
119
+ style={{
120
+ height: '100%',
121
+ backgroundColor: theme.background.content,
122
+ paddingTop: 10,
123
+ borderTopColor: theme.appBorderColor,
124
+ borderTopWidth: 1,
125
+ paddingBottom: Platform.OS === 'android' ? 16 : 0,
126
+ }}
127
+ >
128
+ <AddonsTabs
129
+ onClose={() => {
130
+ setMobileMenuOpen(false);
53
131
  }}
54
- >
55
- <AddonsTabs
56
- onClose={() => {
57
- setMobileMenuOpen(false);
58
- }}
59
- storyId={storyId}
60
- />
61
- </View>
62
- </SafeAreaView>
63
- </KeyboardAvoidingView>
64
- </Modal>
132
+ storyId={storyId}
133
+ />
134
+ </View>
135
+ </SafeAreaView>
136
+ </Animated.View>
65
137
  );
66
138
  }
67
139
  );
@@ -1,16 +1,17 @@
1
1
  import { useTheme } from '@storybook/react-native-theming';
2
- import { forwardRef, memo, ReactNode, useImperativeHandle, useMemo, useState } from 'react';
2
+ import { forwardRef, memo, ReactNode, useImperativeHandle, useMemo, useRef, useState } from 'react';
3
3
  import {
4
+ Animated,
4
5
  Keyboard,
5
6
  KeyboardAvoidingView,
6
7
  Modal,
8
+ PanResponder,
9
+ PanResponderInstance,
7
10
  Pressable,
8
11
  SafeAreaView,
9
12
  ScrollView,
10
- StyleProp,
11
- useWindowDimensions,
13
+ useAnimatedValue,
12
14
  View,
13
- ViewStyle,
14
15
  } from 'react-native';
15
16
 
16
17
  import { useSelectedNode } from './SelectedNodeProvider';
@@ -27,10 +28,45 @@ export const MobileMenuDrawer = memo(
27
28
  forwardRef<MobileMenuDrawerRef, MobileMenuDrawerProps>(({ children }, ref) => {
28
29
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
29
30
  const { scrollToSelectedNode, scrollRef } = useSelectedNode();
30
- const { height } = useWindowDimensions();
31
+ const theme = useTheme();
32
+
33
+ // Create a reference for the drag handle animation
34
+ const dragY = useAnimatedValue(0);
35
+
36
+ // Create the pan responder for handling drag gestures
37
+ const panResponder = useRef<PanResponderInstance>(
38
+ PanResponder.create({
39
+ onStartShouldSetPanResponder: () => true,
40
+ onMoveShouldSetPanResponder: (_, gestureState) => {
41
+ // Only capture downward dragging motions
42
+ return gestureState.dy > 0;
43
+ },
44
+ onPanResponderMove: (_, gestureState) => {
45
+ // Update dragY based on the gesture
46
+ if (gestureState.dy > 0) {
47
+ dragY.setValue(gestureState.dy);
48
+ }
49
+ },
50
+ onPanResponderRelease: (_, gestureState) => {
51
+ // If dragged down enough, close the drawer
52
+ if (gestureState.dy > 50) {
53
+ Keyboard.dismiss();
54
+ setMobileMenuOpen(false);
55
+ }
56
+ // Reset the drag position
57
+ Animated.timing(dragY, {
58
+ toValue: 0,
59
+ duration: 300,
60
+ useNativeDriver: true,
61
+ }).start();
62
+ },
63
+ })
64
+ ).current;
65
+
31
66
  useImperativeHandle(ref, () => ({
32
67
  setMobileMenuOpen: (open: boolean) => {
33
68
  if (open) {
69
+ dragY.setValue(0);
34
70
  scrollToSelectedNode();
35
71
  setMobileMenuOpen(true);
36
72
  } else {
@@ -39,41 +75,65 @@ export const MobileMenuDrawer = memo(
39
75
  }
40
76
  },
41
77
  }));
42
- const theme = useTheme();
43
- const bgColorStyle = useMemo(() => {
44
- return {
45
- marginTop: 'auto',
46
- backgroundColor: theme.background.content,
47
- height: height,
48
- width: '100%',
49
- overflow: 'hidden',
50
- } satisfies StyleProp<ViewStyle>;
51
- }, [height, theme.background.content]);
78
+
79
+ // Create the styles for the drag handle
80
+ const handleStyle = useMemo(
81
+ () => ({
82
+ width: 40,
83
+ height: 5,
84
+ backgroundColor: theme.color.mediumdark,
85
+ borderRadius: 2.5,
86
+ alignSelf: 'center' as const, // TypeScript needs this to recognize 'center' as a valid FlexAlignType
87
+ marginVertical: 8,
88
+ }),
89
+ [theme.color.mediumdark]
90
+ );
52
91
 
53
92
  return (
54
93
  <Modal
55
94
  visible={mobileMenuOpen}
56
- style={bgColorStyle}
57
95
  animationType="slide"
58
96
  transparent
97
+ statusBarTranslucent
59
98
  onRequestClose={() => setMobileMenuOpen(false)}
60
99
  >
61
100
  <KeyboardAvoidingView behavior="height" style={{ flex: 1 }}>
62
101
  <SafeAreaView style={{ justifyContent: 'flex-end', flex: 1 }}>
63
- <View
64
- style={{ flex: 1, borderBottomColor: theme.appBorderColor, borderBottomWidth: 1 }}
65
- >
102
+ <View style={{ flex: 1 }}>
66
103
  <Pressable style={{ flex: 1 }} onPress={() => setMobileMenuOpen(false)}></Pressable>
67
104
  </View>
68
105
 
69
- <View style={{ height: '65%' }}>
106
+ <Animated.View
107
+ style={[
108
+ {
109
+ height: '65%',
110
+ borderTopColor: theme.appBorderColor,
111
+ borderTopWidth: 1,
112
+ borderStyle: 'solid',
113
+ backgroundColor: theme.background.content,
114
+ elevation: 8,
115
+ },
116
+ { transform: [{ translateY: dragY }] },
117
+ ]}
118
+ >
119
+ {/* Drag handle */}
120
+ <View
121
+ {...panResponder.panHandlers}
122
+ style={{
123
+ alignItems: 'center',
124
+ justifyContent: 'center',
125
+ backgroundColor: theme.background.content,
126
+ }}
127
+ >
128
+ <View style={handleStyle} />
129
+ </View>
130
+
70
131
  <ScrollView
71
132
  ref={scrollRef}
72
133
  keyboardShouldPersistTaps="handled"
73
134
  style={{
74
135
  flex: 1,
75
136
  paddingBottom: 150,
76
- paddingTop: 24,
77
137
  alignSelf: 'flex-end',
78
138
  width: '100%',
79
139
  backgroundColor: theme.background.content,
@@ -81,7 +141,7 @@ export const MobileMenuDrawer = memo(
81
141
  >
82
142
  {children}
83
143
  </ScrollView>
84
- </View>
144
+ </Animated.View>
85
145
  </SafeAreaView>
86
146
  </KeyboardAvoidingView>
87
147
  </Modal>
package/src/Tree.tsx CHANGED
@@ -256,6 +256,7 @@ export const Tree = React.memo<{
256
256
  // Omit single-story components from the list of nodes.
257
257
  const collapsedItems = useMemo(
258
258
  () => Object.keys(data).filter((id) => !singleStoryComponentIds.includes(id)),
259
+ // eslint-disable-next-line react-compiler/react-compiler
259
260
  // eslint-disable-next-line react-hooks/exhaustive-deps
260
261
  [singleStoryComponentIds]
261
262
  );
@@ -281,6 +282,7 @@ export const Tree = React.memo<{
281
282
  },
282
283
  { ...data }
283
284
  );
285
+ // eslint-disable-next-line react-compiler/react-compiler
284
286
  // eslint-disable-next-line react-hooks/exhaustive-deps
285
287
  }, [data]);
286
288