panelui-native 0.59.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,498 @@
1
+ /**
2
+ * SelectionMode — turning a list into one you can pick several things out of.
3
+ *
4
+ * ```tsx
5
+ * <SelectionMode values={ids} onSelectedChange={setSelected}>
6
+ * <SelectionMode.Header title="Choose" />
7
+ * <FlashList
8
+ * data={threads}
9
+ * renderItem={({ item }) => (
10
+ * <SelectionMode.Item value={item.id} onPress={() => open(item)}>
11
+ * <Item>…</Item>
12
+ * </SelectionMode.Item>
13
+ * )}
14
+ * />
15
+ * <SelectionMode.Bar>
16
+ * <SelectionMode.Action icon={<TrashIcon size={20} />} destructive onPress={remove}>
17
+ * Delete
18
+ * </SelectionMode.Action>
19
+ * </SelectionMode.Bar>
20
+ * </SelectionMode>
21
+ * ```
22
+ *
23
+ * ## Two ways to present it
24
+ *
25
+ * On a screen it is a *mode*: the list is there to be read, and a long press
26
+ * turns it into one you can pick from. In a sheet it is a *picker*:
27
+ * `SelectionMode.Sheet` was opened in order to choose something, so it is
28
+ * choosing from the moment it appears, with the actions in the sheet's footer.
29
+ *
30
+ * ## The items stay yours
31
+ *
32
+ * `SelectionMode.Item` wraps whatever you put in it rather than replacing it.
33
+ * It adds the circle and takes over what a press means; what the item looks
34
+ * like is yours. That is what lets one component hold a row of people, a grid
35
+ * of colours, a run of slides and a list of files without growing a prop for
36
+ * each of them.
37
+ *
38
+ * ## A mode has to be obvious
39
+ *
40
+ * There are two states and the list behaves differently in each: normally a tap
41
+ * opens a row, and in selection a tap picks it. That is only safe if leaving is
42
+ * always available and never hidden — hence a cancel in the header, the Android
43
+ * back button, and the count in front of the reader the whole time.
44
+ *
45
+ * Entering is a long press on a row, which is the gesture the platform has used
46
+ * for this for fifteen years, and the row you pressed is the first one picked.
47
+ * Entering with nothing selected leaves the reader in a changed list with no
48
+ * explanation of what changed.
49
+ *
50
+ * ## Selection is a set of values, not of rows
51
+ *
52
+ * The component holds ids, never indices or elements. A list that reorders,
53
+ * pages in more rows or drops one underneath the reader would invalidate
54
+ * anything positional; a set of ids survives all three, and is also the shape
55
+ * the action at the end needs — deleting takes ids.
56
+ */
57
+ import { type ReactNode } from 'react';
58
+ import { type ViewProps } from 'react-native';
59
+ import { type VariantProps } from 'tailwind-variants';
60
+ declare const selectionVariants: import("tailwind-variants").TVReturnType<{
61
+ selected: {
62
+ true: {
63
+ circle: string;
64
+ ring: string;
65
+ };
66
+ };
67
+ destructive: {
68
+ true: {
69
+ actionLabel: string;
70
+ };
71
+ };
72
+ disabled: {
73
+ true: {
74
+ action: string;
75
+ };
76
+ };
77
+ /**
78
+ * Flush to the bottom edge, or lifted off it.
79
+ *
80
+ * `bar` is the platform shape — full width against the edge, a hairline
81
+ * along the top, and the same background as the screen's own chrome. It is
82
+ * the default because it is what a list with a selection in it does on both
83
+ * platforms, and because it does not take width away from the list.
84
+ */
85
+ placement: {
86
+ bar: {
87
+ bar: string;
88
+ };
89
+ floating: {
90
+ bar: string;
91
+ };
92
+ };
93
+ }, {
94
+ circle: string;
95
+ fill: string;
96
+ header: string;
97
+ title: string;
98
+ close: string;
99
+ group: string;
100
+ ring: string;
101
+ bar: string;
102
+ action: string;
103
+ actionLabel: string;
104
+ }, undefined, {
105
+ selected: {
106
+ true: {
107
+ circle: string;
108
+ ring: string;
109
+ };
110
+ };
111
+ destructive: {
112
+ true: {
113
+ actionLabel: string;
114
+ };
115
+ };
116
+ disabled: {
117
+ true: {
118
+ action: string;
119
+ };
120
+ };
121
+ /**
122
+ * Flush to the bottom edge, or lifted off it.
123
+ *
124
+ * `bar` is the platform shape — full width against the edge, a hairline
125
+ * along the top, and the same background as the screen's own chrome. It is
126
+ * the default because it is what a list with a selection in it does on both
127
+ * platforms, and because it does not take width away from the list.
128
+ */
129
+ placement: {
130
+ bar: {
131
+ bar: string;
132
+ };
133
+ floating: {
134
+ bar: string;
135
+ };
136
+ };
137
+ }, {
138
+ circle: string;
139
+ fill: string;
140
+ header: string;
141
+ title: string;
142
+ close: string;
143
+ group: string;
144
+ ring: string;
145
+ bar: string;
146
+ action: string;
147
+ actionLabel: string;
148
+ }, import("tailwind-variants").TVReturnType<{
149
+ selected: {
150
+ true: {
151
+ circle: string;
152
+ ring: string;
153
+ };
154
+ };
155
+ destructive: {
156
+ true: {
157
+ actionLabel: string;
158
+ };
159
+ };
160
+ disabled: {
161
+ true: {
162
+ action: string;
163
+ };
164
+ };
165
+ /**
166
+ * Flush to the bottom edge, or lifted off it.
167
+ *
168
+ * `bar` is the platform shape — full width against the edge, a hairline
169
+ * along the top, and the same background as the screen's own chrome. It is
170
+ * the default because it is what a list with a selection in it does on both
171
+ * platforms, and because it does not take width away from the list.
172
+ */
173
+ placement: {
174
+ bar: {
175
+ bar: string;
176
+ };
177
+ floating: {
178
+ bar: string;
179
+ };
180
+ };
181
+ }, {
182
+ circle: string;
183
+ fill: string;
184
+ header: string;
185
+ title: string;
186
+ close: string;
187
+ group: string;
188
+ ring: string;
189
+ bar: string;
190
+ action: string;
191
+ actionLabel: string;
192
+ }, undefined, unknown, unknown, undefined>>;
193
+ type SelectionVariantProps = VariantProps<typeof selectionVariants>;
194
+ interface SelectionModeContextValue {
195
+ active: boolean;
196
+ enter: (value?: string) => void;
197
+ exit: () => void;
198
+ selected: string[];
199
+ isSelected: (value: string) => boolean;
200
+ toggle: (value: string) => void;
201
+ selectAll: () => void;
202
+ clear: () => void;
203
+ /** True when everything selectable is picked, and there is something to pick. */
204
+ allSelected: boolean;
205
+ count: number;
206
+ /** How many rows `values` says there are, or 0 when it was not given. */
207
+ total: number;
208
+ max?: number;
209
+ haptics: boolean;
210
+ /**
211
+ * Whether the selection is being presented in a sheet.
212
+ *
213
+ * A sheet is opened *in order to* pick something, so there is no mode to
214
+ * enter and nothing to long-press for — and the action bar belongs to the
215
+ * sheet's footer rather than floating over the screen.
216
+ */
217
+ sheet: boolean;
218
+ }
219
+ /**
220
+ * Read the selection from anywhere inside a `SelectionMode` — for a header of
221
+ * your own, a count somewhere else on the screen, or an action that has to know
222
+ * what is picked.
223
+ */
224
+ export declare function useSelectionMode(): SelectionModeContextValue;
225
+ export interface SelectionModeProps extends ViewProps {
226
+ className?: string;
227
+ /**
228
+ * Every value that can be picked, in list order.
229
+ *
230
+ * Only "select all" and the "n of m" in the header need it — picking rows one
231
+ * at a time works without it. Give it the same ids you give the list.
232
+ */
233
+ values?: string[];
234
+ /** Controlled selection mode. Leave it out and a long press turns it on. */
235
+ active?: boolean;
236
+ /** Whether selection mode starts on. */
237
+ defaultActive?: boolean;
238
+ onActiveChange?: (active: boolean) => void;
239
+ /** Controlled selection. */
240
+ selected?: string[];
241
+ defaultSelected?: string[];
242
+ onSelectedChange?: (selected: string[]) => void;
243
+ /**
244
+ * The most that can be picked at once.
245
+ *
246
+ * A row that would go over it does not toggle on, and "select all" stops at
247
+ * the limit rather than refusing. Leave it out for no limit.
248
+ */
249
+ max?: number;
250
+ /**
251
+ * A tick when a row is picked and when the mode is entered. Off by default —
252
+ * needs the optional `expo-haptics`, and is silent without it.
253
+ */
254
+ haptics?: boolean;
255
+ children: ReactNode;
256
+ }
257
+ declare function SelectionModeRoot({ className, values, active: activeProp, defaultActive, onActiveChange, selected: selectedProp, defaultSelected, onSelectedChange, max, haptics, children, ...props }: SelectionModeProps): import("react").JSX.Element;
258
+ declare namespace SelectionModeRoot {
259
+ var displayName: string;
260
+ }
261
+ export interface SelectionModeIndicatorProps {
262
+ className?: string;
263
+ /** Which row this stands for. Defaults to the row it is inside. */
264
+ value?: string;
265
+ }
266
+ /**
267
+ * The circle at the left of a row.
268
+ *
269
+ * Round rather than square, and that is the convention doing real work: a
270
+ * square box is a form control the reader is filling in, a round one is a thing
271
+ * they are picking out of a list. `Checkbox` is the former and stays that way.
272
+ *
273
+ * `Item` draws one for you. This is exported for a row that wants it somewhere
274
+ * else — over a photo's corner, at the end instead of the start.
275
+ */
276
+ declare function SelectionModeIndicator({ className, value }: SelectionModeIndicatorProps): import("react").JSX.Element;
277
+ declare namespace SelectionModeIndicator {
278
+ var displayName: string;
279
+ }
280
+ export interface SelectionModeItemProps extends Omit<ViewProps, 'children'> {
281
+ className?: string;
282
+ /** This row's id. What ends up in `selected`. */
283
+ value: string;
284
+ /** What the row does when it is pressed and the mode is off. */
285
+ onPress?: () => void;
286
+ /**
287
+ * Stop this row entering selection mode, and being picked once in it. For a
288
+ * header row, an advert, a "load more" — anything in the list that is not one
289
+ * of the things being chosen between.
290
+ */
291
+ disabled?: boolean;
292
+ /** Draw the circle without waiting for the mode. */
293
+ alwaysShowIndicator?: boolean;
294
+ /**
295
+ * How being picked is drawn.
296
+ *
297
+ * `leading` puts the circle in front of the item, which is what a row wants.
298
+ * `ring` draws a ring around whatever you gave it instead — for a swatch, a
299
+ * thumbnail or a photo, where a circle beside it would be a second thing to
300
+ * look at and the item itself can carry the state. `none` draws nothing and
301
+ * leaves it to you; read `useSelectionMode().isSelected`.
302
+ */
303
+ indicator?: 'leading' | 'ring' | 'none';
304
+ children: ReactNode;
305
+ }
306
+ /**
307
+ * One row, with the circle in front of it.
308
+ *
309
+ * The press behaviour is the whole component: off mode, a press is the row's
310
+ * own and a long press turns the mode on with this row picked; in it, a press
311
+ * picks and unpicks and the row's own press is unreachable. Two meanings for
312
+ * one gesture is exactly why the mode has to be visible from the header.
313
+ */
314
+ declare function SelectionModeItem({ className, value, onPress, disabled, alwaysShowIndicator, indicator, children, ...props }: SelectionModeItemProps): import("react").JSX.Element;
315
+ declare namespace SelectionModeItem {
316
+ var displayName: string;
317
+ }
318
+ export interface SelectionModeGroupProps extends ViewProps {
319
+ className?: string;
320
+ /**
321
+ * Lay the items out in a grid this many across instead of stacking them.
322
+ *
323
+ * For things recognised by sight rather than read — swatches, thumbnails,
324
+ * slides. A grid of six colours is one glance; the same six as rows is a
325
+ * scroll.
326
+ */
327
+ columns?: number;
328
+ /** Space between items in a grid, in points. */
329
+ gap?: number;
330
+ /** Hairlines between stacked items. On by default; off in a grid. */
331
+ separators?: boolean;
332
+ children: ReactNode;
333
+ }
334
+ /**
335
+ * A rounded card holding a run of items.
336
+ *
337
+ * Grouping is what makes a sheet of choices readable: one card of options with
338
+ * hairlines between them reads as a set, and the same rows loose on the sheet's
339
+ * background read as a list that has not finished loading. It is also what the
340
+ * platform's own sheets do.
341
+ *
342
+ * Stacked by default, with a rule between each item. Pass `columns` for a grid.
343
+ */
344
+ declare function SelectionModeGroup({ className, columns, gap, separators, children, style, ...props }: SelectionModeGroupProps): import("react").JSX.Element;
345
+ declare namespace SelectionModeGroup {
346
+ var displayName: string;
347
+ }
348
+ export interface SelectionModeHeaderProps extends ViewProps {
349
+ className?: string;
350
+ /** The word in front of the count. */
351
+ title?: string;
352
+ /** Hide the select-all control, for a list where picking everything is wrong. */
353
+ hideSelectAll?: boolean;
354
+ /** Replaces the whole header's contents, keeping only its layout. */
355
+ children?: ReactNode;
356
+ }
357
+ /**
358
+ * The bar that says the mode is on: a way out, how many are picked, and all
359
+ * of them at once.
360
+ *
361
+ * Rendered only while the mode is on, and it is the thing that makes the mode
362
+ * legible — a list whose rows have quietly changed what a tap does, with no
363
+ * banner saying so, is a list that loses somebody's work.
364
+ */
365
+ declare function SelectionModeHeader({ className, title, hideSelectAll, children, ...props }: SelectionModeHeaderProps): import("react").JSX.Element | null;
366
+ declare namespace SelectionModeHeader {
367
+ var displayName: string;
368
+ }
369
+ export interface SelectionModeBarProps extends ViewProps, Pick<SelectionVariantProps, 'placement'> {
370
+ className?: string;
371
+ /**
372
+ * Room under the actions, in points — your safe-area inset.
373
+ *
374
+ * A bar against the bottom edge sits over the home indicator on a phone that
375
+ * has one, and an action under a home indicator is an action that takes two
376
+ * tries. `floating` uses it as the gap on all four sides instead.
377
+ */
378
+ inset?: number;
379
+ /**
380
+ * Keep the bar up with nothing picked.
381
+ *
382
+ * Off by default: every action on it needs something to act on, and a row of
383
+ * buttons that all refuse is worse than a row that is not there yet.
384
+ */
385
+ showWhenEmpty?: boolean;
386
+ children: ReactNode;
387
+ }
388
+ /**
389
+ * The actions, across the bottom of the list.
390
+ *
391
+ * Over the list rather than under it, because the list is as long as it is and
392
+ * a bar in the flow would be somewhere off the end of it. **Pad the bottom of
393
+ * your list so the last row can clear this** — nothing here can work out how
394
+ * tall the list is.
395
+ *
396
+ * Flush to the edge by default. A bar inset from the sides is a card floating
397
+ * over a list, which reads as something that arrived rather than as the mode
398
+ * the screen is in — and it takes width away from the actions, which are the
399
+ * one row of controls on screen that must not be cramped.
400
+ */
401
+ declare function SelectionModeBar({ className, placement, inset, showWhenEmpty, children, style, ...props }: SelectionModeBarProps): import("react").JSX.Element | null;
402
+ declare namespace SelectionModeBar {
403
+ var displayName: string;
404
+ }
405
+ export interface SelectionModeActionProps extends Omit<ViewProps, 'children'>, Pick<SelectionVariantProps, 'destructive'> {
406
+ className?: string;
407
+ /** The glyph above the label. */
408
+ icon?: ReactNode;
409
+ /**
410
+ * What it does. Handed the selection, so the common case needs no other
411
+ * wiring — and leaving the mode afterwards is up to you, because whether the
412
+ * list still makes sense depends on what you did to it.
413
+ */
414
+ onPress?: (selected: string[]) => void;
415
+ /** Leave selection mode after the action runs. */
416
+ exitOnPress?: boolean;
417
+ disabled?: boolean;
418
+ /** Extra classes for the label. */
419
+ labelClassName?: string;
420
+ children?: ReactNode;
421
+ }
422
+ /**
423
+ * One action in the bar: a glyph with its name under it.
424
+ *
425
+ * Labelled, always. A row of bare glyphs at the bottom of a screen is a row of
426
+ * guesses, and one of them usually deletes something.
427
+ */
428
+ declare function SelectionModeAction({ className, icon, onPress, exitOnPress, disabled, destructive, labelClassName, children, ...props }: SelectionModeActionProps): import("react").JSX.Element;
429
+ declare namespace SelectionModeAction {
430
+ var displayName: string;
431
+ }
432
+ export interface SelectionModeSheetProps {
433
+ className?: string;
434
+ /** Controlled open state of the sheet. */
435
+ open?: boolean;
436
+ defaultOpen?: boolean;
437
+ onOpenChange?: (open: boolean) => void;
438
+ /** The word in front of the count. */
439
+ title?: string;
440
+ /** Hide the select-all control. */
441
+ hideSelectAll?: boolean;
442
+ /**
443
+ * How tall the sheet opens.
444
+ *
445
+ * `half` by default, and deliberately not `auto`. A sheet that sizes to its
446
+ * content gives its scrolling body no height to fill, and a list inside a box
447
+ * of no height draws nothing — which looks like an empty sheet rather than
448
+ * like a missing style. A selection is a list; give it the room.
449
+ */
450
+ size?: 'auto' | 'half' | 'full';
451
+ /**
452
+ * The things to pick between, and optionally a `SelectionMode.Bar` of
453
+ * actions. The bar is lifted into the sheet's footer wherever it is written.
454
+ */
455
+ children: ReactNode;
456
+ }
457
+ /**
458
+ * The whole selection, presented in a bottom sheet.
459
+ *
460
+ * A picker rather than a mode. The list on a screen has to be *turned into* one
461
+ * you can pick from — hence the long press, the cancel and the count — but a
462
+ * sheet was opened in order to pick something, so it is picking from the moment
463
+ * it appears and there is nothing to enter or leave.
464
+ *
465
+ * What goes in it is anything: a column of friends, a grid of colours, a run of
466
+ * slides. `SelectionMode.Item` wraps whatever you give it, so the sheet does
467
+ * not need to know what it is holding.
468
+ *
469
+ * ```tsx
470
+ * <SelectionMode values={ids} selected={selected} onSelectedChange={setSelected}>
471
+ * <SelectionMode.Sheet open={open} onOpenChange={setOpen} title="Share with">
472
+ * {people.map((person) => (
473
+ * <SelectionMode.Item key={person.id} value={person.id}>
474
+ * <Item>…</Item>
475
+ * </SelectionMode.Item>
476
+ * ))}
477
+ * <SelectionMode.Bar>
478
+ * <SelectionMode.Action icon={<SendIcon size={20} />} onPress={share}>Send</SelectionMode.Action>
479
+ * </SelectionMode.Bar>
480
+ * </SelectionMode.Sheet>
481
+ * </SelectionMode>
482
+ * ```
483
+ */
484
+ declare function SelectionModeSheet({ className, open, defaultOpen, onOpenChange, title, hideSelectAll, size, children, }: SelectionModeSheetProps): import("react").JSX.Element;
485
+ declare namespace SelectionModeSheet {
486
+ var displayName: string;
487
+ }
488
+ export declare const SelectionMode: typeof SelectionModeRoot & {
489
+ Sheet: typeof SelectionModeSheet;
490
+ Group: typeof SelectionModeGroup;
491
+ Item: typeof SelectionModeItem;
492
+ Indicator: typeof SelectionModeIndicator;
493
+ Header: typeof SelectionModeHeader;
494
+ Bar: typeof SelectionModeBar;
495
+ Action: typeof SelectionModeAction;
496
+ };
497
+ export {};
498
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/selection-mode/index.tsx"],"names":[],"mappings":"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"}
@@ -16,14 +16,22 @@
16
16
  * </Tabs>
17
17
  * ```
18
18
  *
19
- * **Swiping.** Only the visible panel is mounted, so a drag has nothing behind
20
- * it to reveal. The panel still tracks the finger one to one and dims as it
21
- * goes, and the panel arriving comes back up through the same fade — the
22
- * movement carries the change and the dissolve covers the gap. On release the
23
- * arriving panel picks up a whole panel's width from wherever the outgoing one
24
- * was let go, so the two views draw one continuous movement between them. The
25
- * displacement lives on the root for exactly that reason: a value belonging to
26
- * either panel would be destroyed at the handover.
19
+ * **Swiping puts the panels in a row.** With `swipeable`, the panels are laid
20
+ * out side by side in a strip as wide as all of them, inside a viewport that
21
+ * shows one at a time, and moving between tabs is that strip translating. The
22
+ * neighbours are therefore already built and already the right size before the
23
+ * finger arrives at them, which is the whole point: a panel that has to be
24
+ * mounted and measured at the moment it becomes visible is a panel that stalls
25
+ * there, and it stalls for exactly as long as it takes to build.
26
+ *
27
+ * One shared value carries the strip's position, in panels rather than points,
28
+ * and it is the only thing that decides where the strip is. A press springs it,
29
+ * a drag sets it, and neither waits for React: the value the tab set reports is
30
+ * updated alongside the movement, not ahead of it.
31
+ *
32
+ * A swipeable tab set therefore needs a height to fill, the same as any pager.
33
+ * Give it one — `flex-1` on the tab set, or a fixed height — or the strip has
34
+ * nothing to lay its panels out in.
27
35
  */
28
36
  import { type ReactNode } from 'react';
29
37
  import { type ViewProps } from 'react-native';
@@ -31,12 +39,23 @@ export type TabsVariant = 'segmented' | 'underline' | 'pill' | 'expanding';
31
39
  /**
32
40
  * How much of an inactive panel survives a switch away from it.
33
41
  *
34
- * `false` unmounts it. `true` keeps it mounted but takes it out of layout, so
35
- * it costs nothing to have around. `'measured'` keeps it laid out at full size
36
- * as well — the expensive option, and the only one a child that sizes itself
37
- * from its parent can be built inside while it is hidden.
42
+ * `false` unmounts it. `true` keeps it mounted.
43
+ *
44
+ * `'measured'` meant "keep it mounted *and* laid out at a real size", which was
45
+ * a distinction only a tab set of separately hidden panels had to make. In a
46
+ * swipeable tab set every panel in the strip is laid out at a real size
47
+ * already, so it is the same as `true` there and is kept only so that passing
48
+ * it does not break.
49
+ *
50
+ * @see TabsProps.keepMounted
38
51
  */
39
52
  export type TabsKeepMounted = boolean | 'measured';
53
+ /**
54
+ * `'disable-all'` turns off every animation in the tab set — the indicator, the
55
+ * strip, and an expanding tab's reveal — including the ones its parts run
56
+ * themselves.
57
+ */
58
+ export type TabsAnimation = 'disable-all';
40
59
  export interface TabsProps extends ViewProps {
41
60
  className?: string;
42
61
  value?: string;
@@ -54,34 +73,24 @@ export interface TabsProps extends ViewProps {
54
73
  */
55
74
  variant?: TabsVariant;
56
75
  /**
57
- * Keep inactive panels mounted and hidden instead of unmounting them, so a
58
- * scroll position or a half-filled form survives a switch away and back.
59
- * Costs the render of every panel up front.
76
+ * Mount every panel up front instead of only the ones that have been
77
+ * reached, so a scroll position or a half-filled form is there from the
78
+ * start rather than from the first visit.
60
79
  *
61
- * `true` hides a kept panel with `display: none`, which also takes it out of
62
- * layout: it is mounted, but it has no size. That is what makes it cheap, and
63
- * it is enough for a panel whose content sizes itself — a column of views, a
64
- * form, a `ScrollView` of known children.
80
+ * Usually unnecessary. A panel that has been shown once stays mounted for
81
+ * the life of the tab set either way, and with `swipeable` the panels on
82
+ * each side of the active one are mounted before you get to them. What this
83
+ * adds is the panels you have *not* been near — the fourth tab of four —
84
+ * which costs their render at startup and buys nothing until somebody opens
85
+ * them.
65
86
  *
66
- * It is *not* enough for a child that decides what to render by measuring the
67
- * space it has been given. A virtualised list asks its parent how tall it is
68
- * and fills that many rows; asked inside a panel of zero height it answers
69
- * zero rows, and the whole first render still lands on the frame the tab
70
- * becomes visible — the stall this flag looks like it should have avoided.
71
- *
72
- * `'measured'` is for that case. A kept panel stays laid out at the full size
73
- * of the tab set, and is hidden by not being drawn rather than by being
74
- * removed from layout: a list inside it measures, renders its rows and
75
- * settles while it is still hidden, so becoming visible costs nothing.
76
- *
77
- * The trade is real and is why it is not the default — every kept panel lays
78
- * out and draws, up front and on every size change, so a five-tab set builds
79
- * five panels' worth of rows to show one. Reach for it when a panel is slow
80
- * to appear and its content is virtualised; leave it at `true` otherwise.
87
+ * Turn it on when a panel has to be live while it is off screen: a form that
88
+ * must validate as another tab is edited, a chart that has to be ready to
89
+ * print, a subscription that must not miss a message.
81
90
  */
82
91
  keepMounted?: TabsKeepMounted;
83
92
  /**
84
- * Move between tabs by dragging sideways on the panel, as well as by
93
+ * Move between tabs by dragging sideways on the panels, as well as by
85
94
  * pressing the triggers.
86
95
  *
87
96
  * Off by default, because a panel is allowed to contain something that
@@ -89,21 +98,30 @@ export interface TabsProps extends ViewProps {
89
98
  * open — and the two cannot both have it. Turn it on for panels of ordinary
90
99
  * scrolling content, where it is the gesture people try first.
91
100
  *
92
- * **It does not change what is mounted.** Only `keepMounted` decides that,
93
- * with or without this — a swipe animates between two panels of which one is
94
- * being unmounted and the other mounted for the first time, exactly as a
95
- * press does. What it does change is that the mount now happens *while
96
- * something is moving*, so a panel that is slow to build stops being a pause
97
- * before it appears and starts being a stutter in the movement. If a swipe
98
- * feels heavier than a press on the same tab set, the panel is expensive to
99
- * mount — and the answer is whichever `keepMounted` actually keeps its
100
- * content built, which for a virtualised list is `'measured'` rather than
101
- * `true`. Turning this off hides the cost rather than removing it.
101
+ * **It changes how the panels are laid out.** They go side by side in a strip
102
+ * that is as wide as all of them, and the tab set shows one panel of it at a
103
+ * time. So the panel on each side of the active one is built and sized before
104
+ * you swipe to it, which is what stops a heavy panel — a virtualised list, a
105
+ * chart — from stalling on the frame it becomes visible.
106
+ *
107
+ * **It needs a height to fill**, the same as any pager: `flex-1` on the tab
108
+ * set, or a fixed height. Without one the strip has no room to lay its panels
109
+ * out in, and a list inside a panel of no height renders no rows. In
110
+ * development the tab set says so rather than rendering nothing.
102
111
  */
103
112
  swipeable?: boolean;
113
+ /**
114
+ * Turn the tab set's animations off — the indicator, the strip, and an
115
+ * expanding tab's reveal.
116
+ *
117
+ * For a screen that is already animating something more important, and as a
118
+ * blunt instrument on a device that cannot afford them. The system's own
119
+ * reduce-motion setting is honoured without this.
120
+ */
121
+ animation?: TabsAnimation;
104
122
  children: ReactNode;
105
123
  }
106
- declare function TabsRoot({ className, value, onValueChange, defaultValue, variant, keepMounted, swipeable, children, ...props }: TabsProps): import("react").JSX.Element;
124
+ declare function TabsRoot({ className, value, onValueChange, defaultValue, variant, keepMounted, swipeable, animation, children, ...props }: TabsProps): import("react").JSX.Element;
107
125
  export interface TabsListProps extends ViewProps {
108
126
  className?: string;
109
127
  /**