panelui-native 0.75.1 → 0.77.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.
- package/lib/module/components/ai-input/ai-input-growth.js +62 -0
- package/lib/module/components/ai-input/ai-input-growth.js.map +1 -0
- package/lib/module/components/ai-input/index.js +1584 -0
- package/lib/module/components/ai-input/index.js.map +1 -0
- package/lib/module/components/alert/index.js +1 -1
- package/lib/module/components/alert/index.js.map +1 -1
- package/lib/module/components/avatar/avatar-source.js +15 -0
- package/lib/module/components/avatar/avatar-source.js.map +1 -0
- package/lib/module/components/avatar/index.js +32 -31
- package/lib/module/components/avatar/index.js.map +1 -1
- package/lib/module/components/bottom-sheet/index.js +4 -2
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/button/index.js +7 -1
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/button-group/index.js +2 -3
- package/lib/module/components/button-group/index.js.map +1 -1
- package/lib/module/components/carousel/index.js +10 -7
- package/lib/module/components/carousel/index.js.map +1 -1
- package/lib/module/components/collapsible/index.js +1 -1
- package/lib/module/components/collapsible/index.js.map +1 -1
- package/lib/module/components/field/index.js +7 -8
- package/lib/module/components/field/index.js.map +1 -1
- package/lib/module/components/label/index.js +1 -1
- package/lib/module/components/label/index.js.map +1 -1
- package/lib/module/components/marquee/index.js +36 -11
- package/lib/module/components/marquee/index.js.map +1 -1
- package/lib/module/components/marquee/marquee-math.js +22 -6
- package/lib/module/components/marquee/marquee-math.js.map +1 -1
- package/lib/module/components/plan/index.js +2 -1
- package/lib/module/components/plan/index.js.map +1 -1
- package/lib/module/components/plot/index.js +27 -9
- package/lib/module/components/plot/index.js.map +1 -1
- package/lib/module/components/search-bar/index.js +11 -3
- package/lib/module/components/search-bar/index.js.map +1 -1
- package/lib/module/components/select/index.js +1 -0
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/slider/index.js +1 -0
- package/lib/module/components/slider/index.js.map +1 -1
- package/lib/module/components/split-view/index.js +26 -27
- package/lib/module/components/split-view/index.js.map +1 -1
- package/lib/module/components/split-view/split-view-lifecycle.js +32 -0
- package/lib/module/components/split-view/split-view-lifecycle.js.map +1 -0
- package/lib/module/components/splitter/index.js +7 -13
- package/lib/module/components/splitter/index.js.map +1 -1
- package/lib/module/components/splitter/splitter-math.js +14 -0
- package/lib/module/components/splitter/splitter-math.js.map +1 -1
- package/lib/module/components/switch/index.js +1 -0
- package/lib/module/components/switch/index.js.map +1 -1
- package/lib/module/components/tabs/index.js +1 -1
- package/lib/module/components/tabs/index.js.map +1 -1
- package/lib/module/components/timeline/index.js +156 -42
- package/lib/module/components/timeline/index.js.map +1 -1
- package/lib/module/components/timeline/timeline-geometry.js +11 -0
- package/lib/module/components/timeline/timeline-geometry.js.map +1 -1
- package/lib/module/components/toast/index.js +1 -1
- package/lib/module/components/toast/index.js.map +1 -1
- package/lib/module/components/tooltip/index.js +2 -2
- package/lib/module/components/tooltip/index.js.map +1 -1
- package/lib/module/components/tree/index.js +2 -2
- package/lib/module/components/tree/index.js.map +1 -1
- package/lib/module/components/typography/index.js +2 -1
- package/lib/module/components/typography/index.js.map +1 -1
- package/lib/module/components/waterfall-chart/index.js +22 -3
- package/lib/module/components/waterfall-chart/index.js.map +1 -1
- package/lib/module/hooks/use-disclosure.js +10 -8
- package/lib/module/hooks/use-disclosure.js.map +1 -1
- package/lib/module/icons/index.js +135 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +5 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/native/index.js.map +1 -1
- package/lib/module/primitives/controllable-state.js +61 -0
- package/lib/module/primitives/controllable-state.js.map +1 -0
- package/lib/module/primitives/finite-chart.js +15 -0
- package/lib/module/primitives/finite-chart.js.map +1 -0
- package/lib/module/primitives/glass.js +136 -0
- package/lib/module/primitives/glass.js.map +1 -0
- package/lib/module/primitives/scrim.js +8 -1
- package/lib/module/primitives/scrim.js.map +1 -1
- package/lib/typescript/src/components/ai-input/ai-input-growth.d.ts +59 -0
- package/lib/typescript/src/components/ai-input/ai-input-growth.d.ts.map +1 -0
- package/lib/typescript/src/components/ai-input/index.d.ts +442 -0
- package/lib/typescript/src/components/ai-input/index.d.ts.map +1 -0
- package/lib/typescript/src/components/avatar/avatar-source.d.ts +4 -0
- package/lib/typescript/src/components/avatar/avatar-source.d.ts.map +1 -0
- package/lib/typescript/src/components/avatar/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts +10 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/button/index.d.ts +15 -0
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/carousel/index.d.ts.map +1 -1
- package/lib/typescript/src/components/marquee/index.d.ts +15 -6
- package/lib/typescript/src/components/marquee/index.d.ts.map +1 -1
- package/lib/typescript/src/components/marquee/marquee-math.d.ts +6 -0
- package/lib/typescript/src/components/marquee/marquee-math.d.ts.map +1 -1
- package/lib/typescript/src/components/plan/index.d.ts.map +1 -1
- package/lib/typescript/src/components/plot/index.d.ts +2 -1
- package/lib/typescript/src/components/plot/index.d.ts.map +1 -1
- package/lib/typescript/src/components/search-bar/index.d.ts.map +1 -1
- package/lib/typescript/src/components/split-view/index.d.ts.map +1 -1
- package/lib/typescript/src/components/split-view/split-view-lifecycle.d.ts +14 -0
- package/lib/typescript/src/components/split-view/split-view-lifecycle.d.ts.map +1 -0
- package/lib/typescript/src/components/splitter/index.d.ts +2 -2
- package/lib/typescript/src/components/splitter/index.d.ts.map +1 -1
- package/lib/typescript/src/components/splitter/splitter-math.d.ts +2 -0
- package/lib/typescript/src/components/splitter/splitter-math.d.ts.map +1 -1
- package/lib/typescript/src/components/timeline/index.d.ts +24 -2
- package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
- package/lib/typescript/src/components/timeline/timeline-geometry.d.ts +2 -0
- package/lib/typescript/src/components/timeline/timeline-geometry.d.ts.map +1 -1
- package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
- package/lib/typescript/src/components/waterfall-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/waterfall-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/use-disclosure.d.ts.map +1 -1
- package/lib/typescript/src/icons/index.d.ts +18 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/index.d.ts +17 -0
- package/lib/typescript/src/native/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/controllable-state.d.ts +33 -0
- package/lib/typescript/src/primitives/controllable-state.d.ts.map +1 -0
- package/lib/typescript/src/primitives/finite-chart.d.ts +5 -0
- package/lib/typescript/src/primitives/finite-chart.d.ts.map +1 -0
- package/lib/typescript/src/primitives/glass.d.ts +43 -0
- package/lib/typescript/src/primitives/glass.d.ts.map +1 -0
- package/lib/typescript/src/primitives/scrim.d.ts +7 -0
- package/lib/typescript/src/primitives/scrim.d.ts.map +1 -1
- package/package.json +7 -2
- package/src/components/ai-input/ai-input-growth.ts +65 -0
- package/src/components/ai-input/index.tsx +1971 -0
- package/src/components/alert/index.tsx +1 -1
- package/src/components/avatar/avatar-source.ts +18 -0
- package/src/components/avatar/index.tsx +35 -27
- package/src/components/bottom-sheet/index.tsx +16 -4
- package/src/components/button/index.tsx +20 -1
- package/src/components/button-group/index.tsx +1 -1
- package/src/components/carousel/index.tsx +10 -11
- package/src/components/collapsible/index.tsx +1 -1
- package/src/components/field/index.tsx +4 -4
- package/src/components/label/index.tsx +1 -1
- package/src/components/marquee/index.tsx +56 -12
- package/src/components/marquee/marquee-math.ts +26 -3
- package/src/components/plan/index.tsx +6 -2
- package/src/components/plot/index.tsx +37 -11
- package/src/components/search-bar/index.tsx +9 -3
- package/src/components/select/index.tsx +1 -1
- package/src/components/slider/index.tsx +1 -1
- package/src/components/split-view/index.tsx +24 -33
- package/src/components/split-view/split-view-lifecycle.ts +43 -0
- package/src/components/splitter/index.tsx +7 -11
- package/src/components/splitter/splitter-math.ts +28 -0
- package/src/components/switch/index.tsx +1 -1
- package/src/components/tabs/index.tsx +1 -1
- package/src/components/timeline/index.tsx +189 -34
- package/src/components/timeline/timeline-geometry.ts +11 -0
- package/src/components/toast/index.tsx +6 -1
- package/src/components/tooltip/index.tsx +1 -1
- package/src/components/tree/index.tsx +2 -2
- package/src/components/typography/index.tsx +2 -2
- package/src/components/waterfall-chart/index.tsx +37 -4
- package/src/hooks/use-disclosure.ts +7 -12
- package/src/icons/index.tsx +106 -0
- package/src/index.ts +27 -0
- package/src/native/index.ts +17 -0
- package/src/primitives/controllable-state.ts +112 -0
- package/src/primitives/finite-chart.ts +14 -0
- package/src/primitives/glass.tsx +171 -0
- package/src/primitives/scrim.tsx +7 -1
|
@@ -45,14 +45,23 @@
|
|
|
45
45
|
*/
|
|
46
46
|
import {
|
|
47
47
|
Children,
|
|
48
|
+
cloneElement,
|
|
48
49
|
createContext,
|
|
49
50
|
forwardRef,
|
|
50
51
|
isValidElement,
|
|
51
52
|
useContext,
|
|
52
53
|
useMemo,
|
|
54
|
+
type ReactElement,
|
|
53
55
|
type ReactNode,
|
|
54
56
|
} from 'react';
|
|
55
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
ScrollView,
|
|
59
|
+
View,
|
|
60
|
+
type FlatListProps,
|
|
61
|
+
type ListRenderItemInfo,
|
|
62
|
+
type Text as RNText,
|
|
63
|
+
type ViewProps,
|
|
64
|
+
} from 'react-native';
|
|
56
65
|
import Animated, {
|
|
57
66
|
interpolate,
|
|
58
67
|
useAnimatedScrollHandler,
|
|
@@ -65,7 +74,7 @@ import { tv } from 'tailwind-variants';
|
|
|
65
74
|
import { useCSSVariable } from 'uniwind';
|
|
66
75
|
import { IconColorProvider } from '../../icons';
|
|
67
76
|
import { Text, type TextProps, textChildren } from '../../primitives/text';
|
|
68
|
-
import { timelineColumnWidth } from './timeline-geometry';
|
|
77
|
+
import { TIMELINE_WIDE_COLUMN, timelineColumnOffsets, timelineColumnWidth } from './timeline-geometry';
|
|
69
78
|
|
|
70
79
|
export type TimelineVariant = 'dot' | 'icon' | 'numbered' | 'card' | 'compact';
|
|
71
80
|
/** Semantic colour for a single event, independent of progress. */
|
|
@@ -74,6 +83,7 @@ export type TimelineTone = 'default' | 'info' | 'success' | 'warning' | 'danger'
|
|
|
74
83
|
export type TimelineOrientation = 'vertical' | 'horizontal';
|
|
75
84
|
|
|
76
85
|
const AnimatedScrollView = Animated.createAnimatedComponent(ScrollView);
|
|
86
|
+
const TimelineColumnOffsetContext = createContext<number | null>(null);
|
|
77
87
|
|
|
78
88
|
/*
|
|
79
89
|
* Horizontal geometry.
|
|
@@ -252,6 +262,8 @@ interface TimelineContextValue {
|
|
|
252
262
|
offsets: number[];
|
|
253
263
|
/** Horizontal only: false when the reader has asked for less movement. */
|
|
254
264
|
animate: boolean;
|
|
265
|
+
/** A virtualized list draws one rail segment per mounted cell. */
|
|
266
|
+
virtualized: boolean;
|
|
255
267
|
}
|
|
256
268
|
|
|
257
269
|
interface TimelineItemContextValue {
|
|
@@ -330,17 +342,28 @@ const TimelineRoot = forwardRef<View, TimelineProps>(
|
|
|
330
342
|
* themselves by. These are the snap points, and they are what an item reads
|
|
331
343
|
* to know how far it is from the reading edge.
|
|
332
344
|
*/
|
|
333
|
-
const
|
|
334
|
-
if (!horizontal) return [];
|
|
335
|
-
const
|
|
336
|
-
let sum = 0;
|
|
345
|
+
const columns = useMemo(() => {
|
|
346
|
+
if (!horizontal) return { offsets: [], children };
|
|
347
|
+
const items: ReactElement<TimelineItemProps>[] = [];
|
|
337
348
|
Children.forEach(children, (child) => {
|
|
338
|
-
if (
|
|
339
|
-
|
|
340
|
-
|
|
349
|
+
if (isValidElement(child) && child.type === TimelineItem) {
|
|
350
|
+
items.push(child as ReactElement<TimelineItemProps>);
|
|
351
|
+
}
|
|
341
352
|
});
|
|
342
|
-
|
|
353
|
+
const offsets = timelineColumnOffsets(items.map((item) => itemWidth(item.props)));
|
|
354
|
+
let position = 0;
|
|
355
|
+
const rendered = Children.map(children, (child) => {
|
|
356
|
+
if (!isValidElement(child) || child.type !== TimelineItem) return child;
|
|
357
|
+
const offset = offsets[position++] ?? 0;
|
|
358
|
+
return (
|
|
359
|
+
<TimelineColumnOffsetContext.Provider value={offset}>
|
|
360
|
+
{child}
|
|
361
|
+
</TimelineColumnOffsetContext.Provider>
|
|
362
|
+
);
|
|
363
|
+
});
|
|
364
|
+
return { offsets, children: rendered };
|
|
343
365
|
}, [children, horizontal]);
|
|
366
|
+
const { offsets } = columns;
|
|
344
367
|
|
|
345
368
|
const context = useMemo(
|
|
346
369
|
() => ({
|
|
@@ -350,6 +373,7 @@ const TimelineRoot = forwardRef<View, TimelineProps>(
|
|
|
350
373
|
scrollX,
|
|
351
374
|
offsets,
|
|
352
375
|
animate: !reducedMotion,
|
|
376
|
+
virtualized: false,
|
|
353
377
|
}),
|
|
354
378
|
[value, variant, orientation, scrollX, offsets, reducedMotion]
|
|
355
379
|
);
|
|
@@ -402,7 +426,7 @@ const TimelineRoot = forwardRef<View, TimelineProps>(
|
|
|
402
426
|
borderColor: typeof border === 'string' ? border : undefined,
|
|
403
427
|
}}
|
|
404
428
|
/>
|
|
405
|
-
{textChildren(children)}
|
|
429
|
+
{textChildren(columns.children)}
|
|
406
430
|
</View>
|
|
407
431
|
</AnimatedScrollView>
|
|
408
432
|
</View>
|
|
@@ -412,6 +436,128 @@ const TimelineRoot = forwardRef<View, TimelineProps>(
|
|
|
412
436
|
);
|
|
413
437
|
TimelineRoot.displayName = 'Timeline';
|
|
414
438
|
|
|
439
|
+
export interface TimelineListProps<T>
|
|
440
|
+
extends Omit<
|
|
441
|
+
FlatListProps<T>,
|
|
442
|
+
| 'data'
|
|
443
|
+
| 'renderItem'
|
|
444
|
+
| 'horizontal'
|
|
445
|
+
| 'getItemLayout'
|
|
446
|
+
| 'onScroll'
|
|
447
|
+
| 'snapToOffsets'
|
|
448
|
+
| 'CellRendererComponent'
|
|
449
|
+
> {
|
|
450
|
+
/** Complete event collection; rows outside the native window stay unmounted. */
|
|
451
|
+
data: readonly T[];
|
|
452
|
+
/** Render one `Timeline.Item`. Its step, width, and last marker are owned by the list. */
|
|
453
|
+
renderItem: (info: ListRenderItemInfo<T>) => ReactElement<TimelineItemProps>;
|
|
454
|
+
/** Width of each column, or a resolver for mixed-width histories. */
|
|
455
|
+
itemWidth?: number | ((item: T, index: number) => number);
|
|
456
|
+
/** Steps at or below this index render as completed. */
|
|
457
|
+
value?: number;
|
|
458
|
+
variant?: TimelineVariant;
|
|
459
|
+
snap?: boolean;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Opt-in bounded mount path for long horizontal histories. The compound
|
|
464
|
+
* `Timeline` API remains the simpler choice for short or mixed-content lists.
|
|
465
|
+
*/
|
|
466
|
+
function TimelineList<T>({
|
|
467
|
+
data,
|
|
468
|
+
renderItem,
|
|
469
|
+
itemWidth: requestedWidth = TIMELINE_WIDE_COLUMN,
|
|
470
|
+
value = 0,
|
|
471
|
+
variant = 'dot',
|
|
472
|
+
snap = true,
|
|
473
|
+
initialNumToRender = 6,
|
|
474
|
+
maxToRenderPerBatch = 6,
|
|
475
|
+
windowSize = 5,
|
|
476
|
+
className,
|
|
477
|
+
...props
|
|
478
|
+
}: TimelineListProps<T>) {
|
|
479
|
+
const reducedMotion = useReducedMotion();
|
|
480
|
+
const scrollX = useSharedValue(0);
|
|
481
|
+
const widths = useMemo(
|
|
482
|
+
() =>
|
|
483
|
+
data.map((item, index) =>
|
|
484
|
+
timelineColumnWidth(
|
|
485
|
+
typeof requestedWidth === 'function' ? requestedWidth(item, index) : requestedWidth,
|
|
486
|
+
true
|
|
487
|
+
)
|
|
488
|
+
),
|
|
489
|
+
[data, requestedWidth]
|
|
490
|
+
);
|
|
491
|
+
const offsets = useMemo(() => {
|
|
492
|
+
let offset = 0;
|
|
493
|
+
return widths.map((width) => {
|
|
494
|
+
const current = offset;
|
|
495
|
+
offset += width;
|
|
496
|
+
return current;
|
|
497
|
+
});
|
|
498
|
+
}, [widths]);
|
|
499
|
+
const context = useMemo(
|
|
500
|
+
() => ({
|
|
501
|
+
activeStep: value,
|
|
502
|
+
variant,
|
|
503
|
+
orientation: 'horizontal' as const,
|
|
504
|
+
scrollX,
|
|
505
|
+
offsets,
|
|
506
|
+
animate: !reducedMotion,
|
|
507
|
+
virtualized: true,
|
|
508
|
+
}),
|
|
509
|
+
[value, variant, scrollX, offsets, reducedMotion]
|
|
510
|
+
);
|
|
511
|
+
const { root } = timelineVariants({ variant, orientation: 'horizontal' });
|
|
512
|
+
const onScroll = useAnimatedScrollHandler((event) => {
|
|
513
|
+
scrollX.value = event.contentOffset.x;
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
return (
|
|
517
|
+
<TimelineContext.Provider value={context}>
|
|
518
|
+
<Animated.FlatList
|
|
519
|
+
data={data}
|
|
520
|
+
horizontal
|
|
521
|
+
accessibilityRole="list"
|
|
522
|
+
showsHorizontalScrollIndicator={false}
|
|
523
|
+
decelerationRate="fast"
|
|
524
|
+
snapToAlignment="start"
|
|
525
|
+
initialNumToRender={initialNumToRender}
|
|
526
|
+
maxToRenderPerBatch={maxToRenderPerBatch}
|
|
527
|
+
windowSize={windowSize}
|
|
528
|
+
removeClippedSubviews
|
|
529
|
+
className={root({ className })}
|
|
530
|
+
{...props}
|
|
531
|
+
getItemLayout={(_, index) => ({
|
|
532
|
+
index,
|
|
533
|
+
length: widths[index] ?? TIMELINE_WIDE_COLUMN,
|
|
534
|
+
offset: offsets[index] ?? 0,
|
|
535
|
+
})}
|
|
536
|
+
snapToOffsets={snap ? offsets : undefined}
|
|
537
|
+
onScroll={onScroll}
|
|
538
|
+
scrollEventThrottle={16}
|
|
539
|
+
renderItem={(info) => (
|
|
540
|
+
/*
|
|
541
|
+
* The list owns the order, so it hands each column its own left edge
|
|
542
|
+
* the same way the compound root does. An item reads its offset from
|
|
543
|
+
* here rather than indexing by `step`, and a virtualized item that
|
|
544
|
+
* was given none would sit at zero and never recede.
|
|
545
|
+
*/
|
|
546
|
+
<TimelineColumnOffsetContext.Provider value={offsets[info.index] ?? 0}>
|
|
547
|
+
{cloneElement(renderItem(info), {
|
|
548
|
+
step: info.index,
|
|
549
|
+
width: widths[info.index],
|
|
550
|
+
last: info.index === data.length - 1,
|
|
551
|
+
role: 'listitem',
|
|
552
|
+
})}
|
|
553
|
+
</TimelineColumnOffsetContext.Provider>
|
|
554
|
+
)}
|
|
555
|
+
/>
|
|
556
|
+
</TimelineContext.Provider>
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
TimelineList.displayName = 'Timeline.List';
|
|
560
|
+
|
|
415
561
|
export interface TimelineItemProps extends ViewProps {
|
|
416
562
|
className?: string;
|
|
417
563
|
/** Position in the sequence, zero-based. */
|
|
@@ -450,8 +596,16 @@ const TimelineItem = forwardRef<View, TimelineItemProps>(
|
|
|
450
596
|
},
|
|
451
597
|
ref
|
|
452
598
|
) => {
|
|
453
|
-
const { activeStep, variant, orientation, scrollX,
|
|
599
|
+
const { activeStep, variant, orientation, scrollX, animate, virtualized } =
|
|
454
600
|
useTimeline('Timeline.Item');
|
|
601
|
+
/*
|
|
602
|
+
* Where this column starts, from its position among the rendered items
|
|
603
|
+
* rather than from `step`. `step` is the semantic progress value: it may
|
|
604
|
+
* be sparse, repeated or reordered, and indexing the offsets by it lands a
|
|
605
|
+
* column on another column's snap point.
|
|
606
|
+
*/
|
|
607
|
+
const columnOffset = useContext(TimelineColumnOffsetContext);
|
|
608
|
+
const border = useCSSVariable('--color-border');
|
|
455
609
|
const isCompleted = completed ?? step <= activeStep;
|
|
456
610
|
const { item } = timelineVariants({
|
|
457
611
|
variant,
|
|
@@ -464,7 +618,7 @@ const TimelineItem = forwardRef<View, TimelineItemProps>(
|
|
|
464
618
|
const columnWidth = horizontal
|
|
465
619
|
? itemWidth({ step, width, children } as TimelineItemProps)
|
|
466
620
|
: undefined;
|
|
467
|
-
const offset =
|
|
621
|
+
const offset = columnOffset ?? 0;
|
|
468
622
|
|
|
469
623
|
const context = useMemo(
|
|
470
624
|
() => ({
|
|
@@ -479,8 +633,8 @@ const TimelineItem = forwardRef<View, TimelineItemProps>(
|
|
|
479
633
|
);
|
|
480
634
|
|
|
481
635
|
/*
|
|
482
|
-
* A column
|
|
483
|
-
*
|
|
636
|
+
* A column scales and drops as it leaves the reading edge, so the one being
|
|
637
|
+
* read is distinct without fading informative text below its contrast.
|
|
484
638
|
*
|
|
485
639
|
* One column's width either side, not two: a window wide enough to hold
|
|
486
640
|
* three columns near full strength is a row where nothing is picked out,
|
|
@@ -494,12 +648,11 @@ const TimelineItem = forwardRef<View, TimelineItemProps>(
|
|
|
494
648
|
* the rest.
|
|
495
649
|
*/
|
|
496
650
|
const columnStyle = useAnimatedStyle(() => {
|
|
497
|
-
if (!horizontal || !animate) return {
|
|
651
|
+
if (!horizontal || !animate) return { transform: [] };
|
|
498
652
|
const distance = Math.abs(scrollX.value - offset);
|
|
499
653
|
const window = Math.max(columnWidth ?? timelineColumnWidth(undefined, true), 1);
|
|
500
654
|
const away = interpolate(distance, [0, window], [0, 1], 'clamp');
|
|
501
655
|
return {
|
|
502
|
-
opacity: 1 - away * 0.4,
|
|
503
656
|
transform: [{ scale: 1 - away * 0.04 }, { translateY: away * 4 }],
|
|
504
657
|
};
|
|
505
658
|
});
|
|
@@ -522,6 +675,22 @@ const TimelineItem = forwardRef<View, TimelineItemProps>(
|
|
|
522
675
|
{...props}
|
|
523
676
|
style={[style, { width: columnWidth }, columnStyle]}
|
|
524
677
|
>
|
|
678
|
+
{virtualized && !last ? (
|
|
679
|
+
<View
|
|
680
|
+
accessibilityElementsHidden
|
|
681
|
+
importantForAccessibility="no-hide-descendants"
|
|
682
|
+
pointerEvents="none"
|
|
683
|
+
style={{
|
|
684
|
+
position: 'absolute',
|
|
685
|
+
left: 0,
|
|
686
|
+
right: 0,
|
|
687
|
+
top: HORIZONTAL_RAIL_TOP,
|
|
688
|
+
borderTopWidth: 1,
|
|
689
|
+
borderStyle: 'dashed',
|
|
690
|
+
borderColor: typeof border === 'string' ? border : undefined,
|
|
691
|
+
}}
|
|
692
|
+
/>
|
|
693
|
+
) : null}
|
|
525
694
|
{textChildren(children)}
|
|
526
695
|
</Animated.View>
|
|
527
696
|
</TimelineItemContext.Provider>
|
|
@@ -678,22 +847,7 @@ const TimelineContent = forwardRef<View, ViewProps & { className?: string }>(
|
|
|
678
847
|
const { body, panel } = timelineVariants({ variant, tone, completed, orientation });
|
|
679
848
|
const horizontal = orientation === 'horizontal';
|
|
680
849
|
|
|
681
|
-
/*
|
|
682
|
-
* Horizontal: the body recedes further than the column around it.
|
|
683
|
-
*
|
|
684
|
-
* The rail is a continuous thing and has to stay readable across the whole
|
|
685
|
-
* track — the years either side of the one being read are half of what a
|
|
686
|
-
* timeline is for. The prose under them is not: several columns of it at
|
|
687
|
-
* equal weight is a wall, and no amount of fading the column as a whole
|
|
688
|
-
* fixes that without taking the years down with it. So the body takes a
|
|
689
|
-
* second, steeper curve and the dates keep the first one.
|
|
690
|
-
*/
|
|
691
|
-
const bodyStyle = useAnimatedStyle(() => {
|
|
692
|
-
if (!horizontal || !animate) return { opacity: 1 };
|
|
693
|
-
const distance = Math.abs(scrollX.value - offset);
|
|
694
|
-
const window = Math.max(columnWidth, 1);
|
|
695
|
-
return { opacity: interpolate(distance, [0, window], [1, 0.3], 'clamp') };
|
|
696
|
-
});
|
|
850
|
+
/* Horizontal content stays fully opaque; scale and translation provide focus. */
|
|
697
851
|
|
|
698
852
|
const inner =
|
|
699
853
|
variant === 'card' ? (
|
|
@@ -715,7 +869,7 @@ const TimelineContent = forwardRef<View, ViewProps & { className?: string }>(
|
|
|
715
869
|
ref={ref}
|
|
716
870
|
className={body({ className })}
|
|
717
871
|
{...props}
|
|
718
|
-
style={
|
|
872
|
+
style={style}
|
|
719
873
|
>
|
|
720
874
|
{inner}
|
|
721
875
|
</Animated.View>
|
|
@@ -825,6 +979,7 @@ const TimelineStat = forwardRef<View, TimelineStatProps>(
|
|
|
825
979
|
TimelineStat.displayName = 'Timeline.Stat';
|
|
826
980
|
|
|
827
981
|
export const Timeline = Object.assign(TimelineRoot, {
|
|
982
|
+
List: TimelineList,
|
|
828
983
|
Item: TimelineItem,
|
|
829
984
|
Aside: TimelineAside,
|
|
830
985
|
Indicator: TimelineIndicator,
|
|
@@ -7,3 +7,14 @@ export function timelineColumnWidth(requested: number | undefined, filled: boole
|
|
|
7
7
|
}
|
|
8
8
|
return filled ? TIMELINE_WIDE_COLUMN : TIMELINE_NARROW_COLUMN;
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
/** Left edge of each column in render order. */
|
|
12
|
+
export function timelineColumnOffsets(widths: readonly number[]): number[] {
|
|
13
|
+
const offsets: number[] = [];
|
|
14
|
+
let sum = 0;
|
|
15
|
+
for (const width of widths) {
|
|
16
|
+
offsets.push(sum);
|
|
17
|
+
sum += width;
|
|
18
|
+
}
|
|
19
|
+
return offsets;
|
|
20
|
+
}
|
|
@@ -175,7 +175,12 @@ const ToastRoot = ({ className, variant = 'default', onHide, children, ...props
|
|
|
175
175
|
|
|
176
176
|
return (
|
|
177
177
|
<ToastContext.Provider value={context}>
|
|
178
|
-
<View
|
|
178
|
+
<View
|
|
179
|
+
{...props}
|
|
180
|
+
accessibilityRole="alert"
|
|
181
|
+
accessibilityLiveRegion="polite"
|
|
182
|
+
className={root({ className })}
|
|
183
|
+
>
|
|
179
184
|
{textChildren(children)}
|
|
180
185
|
</View>
|
|
181
186
|
</ToastContext.Provider>
|
|
@@ -623,7 +623,7 @@ function TooltipTitle({ className, ...props }: TooltipTitleProps) {
|
|
|
623
623
|
const { title } = tooltipVariants({ variant });
|
|
624
624
|
|
|
625
625
|
return (
|
|
626
|
-
<Text accessibilityRole="header" className={cn(title(), className)}
|
|
626
|
+
<Text {...props} accessibilityRole="header" className={cn(title(), className)} />
|
|
627
627
|
);
|
|
628
628
|
}
|
|
629
629
|
|
|
@@ -286,10 +286,10 @@ const TreeRoot = forwardRef<View, TreeProps>(
|
|
|
286
286
|
<TreeContext.Provider value={context}>
|
|
287
287
|
<Animated.View
|
|
288
288
|
ref={ref}
|
|
289
|
+
{...props}
|
|
289
290
|
layout={LinearTransition.duration(TRANSITION_DURATION)}
|
|
290
291
|
accessibilityRole="list"
|
|
291
292
|
className={root({ className })}
|
|
292
|
-
{...props}
|
|
293
293
|
>
|
|
294
294
|
{children}
|
|
295
295
|
</Animated.View>
|
|
@@ -394,6 +394,7 @@ const TreeTrigger = forwardRef<View, TreeTriggerProps>(
|
|
|
394
394
|
return (
|
|
395
395
|
<Pressable
|
|
396
396
|
ref={ref}
|
|
397
|
+
{...props}
|
|
397
398
|
accessibilityRole="button"
|
|
398
399
|
accessibilityState={{
|
|
399
400
|
expanded: isBranch ? isExpanded : undefined,
|
|
@@ -403,7 +404,6 @@ const TreeTrigger = forwardRef<View, TreeTriggerProps>(
|
|
|
403
404
|
aria-level={level + 1}
|
|
404
405
|
disabled={triggerDisabled}
|
|
405
406
|
className={trigger({ className })}
|
|
406
|
-
{...props}
|
|
407
407
|
onPress={handlePress}
|
|
408
408
|
>
|
|
409
409
|
<IconColorProvider color={isSelected ? selectedColor : undefined}>
|
|
@@ -290,9 +290,9 @@ export interface TypographyListProps extends ViewProps {
|
|
|
290
290
|
*/
|
|
291
291
|
const TypographyList = forwardRef<View, TypographyListProps>(
|
|
292
292
|
({ className, ordered = false, children, ...props }, ref) => (
|
|
293
|
-
<View ref={ref} accessibilityRole="list" className={cn('gap-2', className)}
|
|
293
|
+
<View ref={ref} {...props} accessibilityRole="list" className={cn('gap-2', className)}>
|
|
294
294
|
{Children.map(children, (child, index) => (
|
|
295
|
-
<View className="w-full flex-row gap-2">
|
|
295
|
+
<View role="listitem" className="w-full flex-row gap-2">
|
|
296
296
|
{ordered ? (
|
|
297
297
|
<Text className="text-base text-muted-foreground">{index + 1}.</Text>
|
|
298
298
|
) : (
|
|
@@ -65,7 +65,12 @@ import Animated, {
|
|
|
65
65
|
} from 'react-native-reanimated';
|
|
66
66
|
import Svg, { Defs, G, Line as SvgLine, LinearGradient, Path, Stop } from 'react-native-svg';
|
|
67
67
|
import { useCSSVariable } from 'uniwind';
|
|
68
|
+
import { ChartAccessibilityData, type ChartAccessibilityProps } from '../../primitives/chart-accessibility';
|
|
68
69
|
import { Text } from '../../primitives/text';
|
|
70
|
+
import {
|
|
71
|
+
finiteChartDomain,
|
|
72
|
+
finiteChartNumber,
|
|
73
|
+
} from '../../primitives/finite-chart';
|
|
69
74
|
import { barPath, compactNumber, type Plot } from '../../utils/chart';
|
|
70
75
|
import { cn } from '../../utils/cn';
|
|
71
76
|
|
|
@@ -196,7 +201,7 @@ export function waterfallSteps(data: WaterfallDatum[]): WaterfallStep[] {
|
|
|
196
201
|
let running = 0;
|
|
197
202
|
|
|
198
203
|
for (const datum of data) {
|
|
199
|
-
const value =
|
|
204
|
+
const value = finiteChartNumber(datum.value) ?? 0;
|
|
200
205
|
|
|
201
206
|
if (datum.total) {
|
|
202
207
|
// A total is a reading, so it is measured from the baseline and the
|
|
@@ -228,7 +233,7 @@ export function waterfallSteps(data: WaterfallDatum[]): WaterfallStep[] {
|
|
|
228
233
|
return steps;
|
|
229
234
|
}
|
|
230
235
|
|
|
231
|
-
export interface WaterfallChartProps extends ViewProps {
|
|
236
|
+
export interface WaterfallChartProps extends ViewProps, ChartAccessibilityProps<WaterfallStep> {
|
|
232
237
|
className?: string;
|
|
233
238
|
/** The steps, in the order they happen. */
|
|
234
239
|
data: WaterfallDatum[];
|
|
@@ -327,6 +332,11 @@ const WaterfallChartRoot = forwardRef<WaterfallChartHandle, WaterfallChartProps>
|
|
|
327
332
|
fallColor,
|
|
328
333
|
totalColor,
|
|
329
334
|
onActiveIndexChange,
|
|
335
|
+
accessible,
|
|
336
|
+
accessibilityLabel,
|
|
337
|
+
accessibilityHint,
|
|
338
|
+
accessibilityLabelForDatum,
|
|
339
|
+
onAccessibilityDatumPress,
|
|
330
340
|
compact = false,
|
|
331
341
|
children,
|
|
332
342
|
...props
|
|
@@ -385,7 +395,8 @@ const WaterfallChartRoot = forwardRef<WaterfallChartHandle, WaterfallChartProps>
|
|
|
385
395
|
};
|
|
386
396
|
|
|
387
397
|
const extent = useMemo<[number, number]>(() => {
|
|
388
|
-
|
|
398
|
+
const explicit = finiteChartDomain(yDomain);
|
|
399
|
+
if (explicit) return explicit;
|
|
389
400
|
|
|
390
401
|
/*
|
|
391
402
|
* Both ends of every bar, not just the values. A step's bar occupies the
|
|
@@ -535,7 +546,29 @@ const WaterfallChartRoot = forwardRef<WaterfallChartHandle, WaterfallChartProps>
|
|
|
535
546
|
<WaterfallChartContext.Provider value={context}>
|
|
536
547
|
<View {...props} style={props.style} className={cn('w-full', className)}>
|
|
537
548
|
{header}
|
|
538
|
-
<
|
|
549
|
+
<ChartAccessibilityData
|
|
550
|
+
chart="Waterfall chart"
|
|
551
|
+
data={steps}
|
|
552
|
+
disabled={accessible === false || loading}
|
|
553
|
+
accessibilityLabel={accessibilityLabel}
|
|
554
|
+
accessibilityHint={accessibilityHint}
|
|
555
|
+
accessibilityLabelForDatum={accessibilityLabelForDatum}
|
|
556
|
+
onAccessibilityDatumPress={onAccessibilityDatumPress}
|
|
557
|
+
valueOf={(step) => [
|
|
558
|
+
['label', step.label],
|
|
559
|
+
['change', step.value],
|
|
560
|
+
['kind', step.kind],
|
|
561
|
+
['starts at', step.start],
|
|
562
|
+
['ends at', step.end],
|
|
563
|
+
]}
|
|
564
|
+
/>
|
|
565
|
+
<View
|
|
566
|
+
onLayout={onLayout}
|
|
567
|
+
style={{ aspectRatio }}
|
|
568
|
+
className="w-full"
|
|
569
|
+
accessibilityElementsHidden
|
|
570
|
+
importantForAccessibility="no-hide-descendants"
|
|
571
|
+
>
|
|
539
572
|
{plot.width > 0 ? (
|
|
540
573
|
<>
|
|
541
574
|
<Svg width="100%" height="100%" style={StyleSheet.absoluteFill}>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { useCallback, useMemo
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { useControllableState } from '../primitives/controllable-state';
|
|
2
3
|
|
|
3
4
|
export interface UseDisclosureOptions {
|
|
4
5
|
defaultOpen?: boolean;
|
|
@@ -34,17 +35,11 @@ export function useDisclosure({
|
|
|
34
35
|
open: controlledOpen,
|
|
35
36
|
onOpenChange,
|
|
36
37
|
}: UseDisclosureOptions = {}): UseDisclosureResult {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
(next: boolean) => {
|
|
43
|
-
if (!isControlled) setUncontrolledOpen(next);
|
|
44
|
-
onOpenChange?.(next);
|
|
45
|
-
},
|
|
46
|
-
[isControlled, onOpenChange]
|
|
47
|
-
);
|
|
38
|
+
const { value: isOpen, setValue: setOpen } = useControllableState({
|
|
39
|
+
value: controlledOpen,
|
|
40
|
+
defaultValue: defaultOpen,
|
|
41
|
+
onChange: onOpenChange,
|
|
42
|
+
});
|
|
48
43
|
|
|
49
44
|
const open = useCallback(() => setOpen(true), [setOpen]);
|
|
50
45
|
const close = useCallback(() => setOpen(false), [setOpen]);
|
package/src/icons/index.tsx
CHANGED
|
@@ -852,6 +852,22 @@ export function PaperclipIcon({ size = 16, color, ...props }: IconProps) {
|
|
|
852
852
|
}
|
|
853
853
|
|
|
854
854
|
/** A capsule on a stand — a microphone, for anything voice. */
|
|
855
|
+
/** A voice waveform — dictation, voice mode, a recording that has a shape. */
|
|
856
|
+
export function AudioLinesIcon({ size = 16, color, ...props }: IconProps) {
|
|
857
|
+
const resolved = useResolvedColor(color, '#737373');
|
|
858
|
+
return (
|
|
859
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none" {...props}>
|
|
860
|
+
<Path
|
|
861
|
+
d="M2 10v3M6 6v11M10 3v18M14 8v7M18 5v13M22 10v3"
|
|
862
|
+
stroke={resolved}
|
|
863
|
+
strokeWidth={2}
|
|
864
|
+
strokeLinecap="round"
|
|
865
|
+
strokeLinejoin="round"
|
|
866
|
+
/>
|
|
867
|
+
</Svg>
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
|
|
855
871
|
export function MicIcon({ size = 16, color, ...props }: IconProps) {
|
|
856
872
|
const resolved = useResolvedColor(color, '#737373');
|
|
857
873
|
return (
|
|
@@ -1078,6 +1094,73 @@ export function CrosshairIcon({ size = 16, color, ...props }: IconProps) {
|
|
|
1078
1094
|
}
|
|
1079
1095
|
|
|
1080
1096
|
/** A compass needle — which way is north. */
|
|
1097
|
+
export function GlobeIcon({ size = 16, color, ...props }: IconProps) {
|
|
1098
|
+
const resolved = useResolvedColor(color, '#737373');
|
|
1099
|
+
return (
|
|
1100
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none" {...props}>
|
|
1101
|
+
<Circle
|
|
1102
|
+
cx={12}
|
|
1103
|
+
cy={12}
|
|
1104
|
+
r={10}
|
|
1105
|
+
stroke={resolved}
|
|
1106
|
+
strokeWidth={2}
|
|
1107
|
+
strokeLinecap="round"
|
|
1108
|
+
strokeLinejoin="round"
|
|
1109
|
+
/>
|
|
1110
|
+
<Path
|
|
1111
|
+
d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20M2 12h20"
|
|
1112
|
+
stroke={resolved}
|
|
1113
|
+
strokeWidth={2}
|
|
1114
|
+
strokeLinecap="round"
|
|
1115
|
+
strokeLinejoin="round"
|
|
1116
|
+
/>
|
|
1117
|
+
</Svg>
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
export function CameraIcon({ size = 16, color, ...props }: IconProps) {
|
|
1122
|
+
const resolved = useResolvedColor(color, '#737373');
|
|
1123
|
+
return (
|
|
1124
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none" {...props}>
|
|
1125
|
+
<Path
|
|
1126
|
+
d="M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z"
|
|
1127
|
+
stroke={resolved}
|
|
1128
|
+
strokeWidth={2}
|
|
1129
|
+
strokeLinecap="round"
|
|
1130
|
+
strokeLinejoin="round"
|
|
1131
|
+
/>
|
|
1132
|
+
<Circle
|
|
1133
|
+
cx={12}
|
|
1134
|
+
cy={13}
|
|
1135
|
+
r={3}
|
|
1136
|
+
stroke={resolved}
|
|
1137
|
+
strokeWidth={2}
|
|
1138
|
+
strokeLinecap="round"
|
|
1139
|
+
strokeLinejoin="round"
|
|
1140
|
+
/>
|
|
1141
|
+
</Svg>
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* The glyph on a control that opens a list of values — a stacked pair, because
|
|
1147
|
+
* one chevron promises a direction the control does not travel in.
|
|
1148
|
+
*/
|
|
1149
|
+
export function ChevronsUpDownIcon({ size = 16, color, ...props }: IconProps) {
|
|
1150
|
+
const resolved = useResolvedColor(color, '#737373');
|
|
1151
|
+
return (
|
|
1152
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none" {...props}>
|
|
1153
|
+
<Path
|
|
1154
|
+
d="m7 15 5 5 5-5M7 9l5-5 5 5"
|
|
1155
|
+
stroke={resolved}
|
|
1156
|
+
strokeWidth={2}
|
|
1157
|
+
strokeLinecap="round"
|
|
1158
|
+
strokeLinejoin="round"
|
|
1159
|
+
/>
|
|
1160
|
+
</Svg>
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1081
1164
|
export function CompassIcon({ size = 16, color, ...props }: IconProps) {
|
|
1082
1165
|
const resolved = useResolvedColor(color, '#737373');
|
|
1083
1166
|
return (
|
|
@@ -1256,6 +1339,29 @@ export interface ToggleIconProps extends IconProps {
|
|
|
1256
1339
|
}
|
|
1257
1340
|
|
|
1258
1341
|
/** Upvote. Filled once the vote is cast. */
|
|
1342
|
+
/**
|
|
1343
|
+
* A plain up arrow, drawn symmetrically about the centre of its box so it sits
|
|
1344
|
+
* dead centre in a circular button.
|
|
1345
|
+
*
|
|
1346
|
+
* Distinct from `ArrowUpIcon`, which is the heavy solid arrow a vote control
|
|
1347
|
+
* wants, and from `SendIcon`, which is a paper plane. This is the one a
|
|
1348
|
+
* composer's send button uses.
|
|
1349
|
+
*/
|
|
1350
|
+
export function SendArrowIcon({ size = 16, color, ...props }: IconProps) {
|
|
1351
|
+
const resolved = useResolvedColor(color, '#737373');
|
|
1352
|
+
return (
|
|
1353
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none" {...props}>
|
|
1354
|
+
<Path
|
|
1355
|
+
d="m5 12 7-7 7 7M12 19V5"
|
|
1356
|
+
stroke={resolved}
|
|
1357
|
+
strokeWidth={2.5}
|
|
1358
|
+
strokeLinecap="round"
|
|
1359
|
+
strokeLinejoin="round"
|
|
1360
|
+
/>
|
|
1361
|
+
</Svg>
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1259
1365
|
export function ArrowUpIcon({ size = 16, color, filled, ...props }: ToggleIconProps) {
|
|
1260
1366
|
const resolved = useResolvedColor(color, '#737373');
|
|
1261
1367
|
return (
|