panelui-native 0.25.0 → 0.30.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/README.md +18 -1
- package/lib/module/components/accordion/index.js +8 -8
- package/lib/module/components/accordion/index.js.map +1 -1
- package/lib/module/components/alert/index.js +2 -2
- package/lib/module/components/alert/index.js.map +1 -1
- package/lib/module/components/area-chart/index.js +182 -50
- package/lib/module/components/area-chart/index.js.map +1 -1
- package/lib/module/components/attachment/index.js +2 -1
- package/lib/module/components/attachment/index.js.map +1 -1
- package/lib/module/components/avatar/index.js +3 -3
- package/lib/module/components/avatar/index.js.map +1 -1
- package/lib/module/components/badge/index.js +4 -4
- package/lib/module/components/badge/index.js.map +1 -1
- package/lib/module/components/bar-chart/index.js +197 -56
- package/lib/module/components/bar-chart/index.js.map +1 -1
- package/lib/module/components/bottom-sheet/index.js +15 -10
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/breadcrumb/index.js +6 -6
- package/lib/module/components/breadcrumb/index.js.map +1 -1
- package/lib/module/components/button/index.js +11 -6
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/calendar/index.js +792 -0
- package/lib/module/components/calendar/index.js.map +1 -0
- package/lib/module/components/carousel/index.js +680 -0
- package/lib/module/components/carousel/index.js.map +1 -0
- package/lib/module/components/chip/index.js +4 -4
- package/lib/module/components/chip/index.js.map +1 -1
- package/lib/module/components/code-block/highlight.js +363 -0
- package/lib/module/components/code-block/highlight.js.map +1 -0
- package/lib/module/components/code-block/index.js +313 -0
- package/lib/module/components/code-block/index.js.map +1 -0
- package/lib/module/components/date-picker/index.js +165 -0
- package/lib/module/components/date-picker/index.js.map +1 -0
- package/lib/module/components/dialog/index.js +7 -2
- package/lib/module/components/dialog/index.js.map +1 -1
- package/lib/module/components/direction/index.js +2 -1
- package/lib/module/components/direction/index.js.map +1 -1
- package/lib/module/components/empty-state/index.js +2 -2
- package/lib/module/components/empty-state/index.js.map +1 -1
- package/lib/module/components/field/index.js +5 -5
- package/lib/module/components/field/index.js.map +1 -1
- package/lib/module/components/flow/index.js +3 -3
- package/lib/module/components/flow/index.js.map +1 -1
- package/lib/module/components/frame/index.js +5 -5
- package/lib/module/components/frame/index.js.map +1 -1
- package/lib/module/components/input-group/index.js +3 -2
- package/lib/module/components/input-group/index.js.map +1 -1
- package/lib/module/components/item/index.js +9 -9
- package/lib/module/components/item/index.js.map +1 -1
- package/lib/module/components/label/index.js +4 -4
- package/lib/module/components/label/index.js.map +1 -1
- package/lib/module/components/line-chart/index.js +167 -44
- package/lib/module/components/line-chart/index.js.map +1 -1
- package/lib/module/components/map/index.js +7 -7
- package/lib/module/components/map/index.js.map +1 -1
- package/lib/module/components/marker/index.js +3 -3
- package/lib/module/components/marker/index.js.map +1 -1
- package/lib/module/components/menu/index.js +714 -0
- package/lib/module/components/menu/index.js.map +1 -0
- package/lib/module/components/message/index.js +7 -7
- package/lib/module/components/message/index.js.map +1 -1
- package/lib/module/components/message-scroller/index.js +5 -4
- package/lib/module/components/message-scroller/index.js.map +1 -1
- package/lib/module/components/plan/index.js +296 -0
- package/lib/module/components/plan/index.js.map +1 -0
- package/lib/module/components/popover/index.js +73 -10
- package/lib/module/components/popover/index.js.map +1 -1
- package/lib/module/components/radio-group/index.js +15 -10
- package/lib/module/components/radio-group/index.js.map +1 -1
- package/lib/module/components/reasoning/index.js +244 -0
- package/lib/module/components/reasoning/index.js.map +1 -0
- package/lib/module/components/section-rail/index.js +4 -4
- package/lib/module/components/section-rail/index.js.map +1 -1
- package/lib/module/components/select/index.js +10 -4
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/sources/index.js +221 -0
- package/lib/module/components/sources/index.js.map +1 -0
- package/lib/module/components/steps/index.js +4 -4
- package/lib/module/components/steps/index.js.map +1 -1
- package/lib/module/components/tabs/index.js +7 -7
- package/lib/module/components/tabs/index.js.map +1 -1
- package/lib/module/components/task/index.js +300 -0
- package/lib/module/components/task/index.js.map +1 -0
- package/lib/module/components/textarea/index.js +295 -0
- package/lib/module/components/textarea/index.js.map +1 -0
- package/lib/module/components/timeline/index.js +4 -4
- package/lib/module/components/timeline/index.js.map +1 -1
- package/lib/module/components/toast/index.js +2 -2
- package/lib/module/components/toast/index.js.map +1 -1
- package/lib/module/components/toggle-button/index.js +5 -5
- package/lib/module/components/toggle-button/index.js.map +1 -1
- package/lib/module/components/tooltip/index.js +648 -0
- package/lib/module/components/tooltip/index.js.map +1 -0
- package/lib/module/components/typography/index.js +2 -2
- package/lib/module/components/typography/index.js.map +1 -1
- package/lib/module/hooks/index.js +1 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/use-back-handler.js +37 -0
- package/lib/module/hooks/use-back-handler.js.map +1 -0
- package/lib/module/icons/index.js +202 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +13 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/collapse.js +112 -0
- package/lib/module/primitives/collapse.js.map +1 -0
- package/lib/module/primitives/keyboard-avoider.js +2 -1
- package/lib/module/primitives/keyboard-avoider.js.map +1 -1
- package/lib/module/primitives/text.js +25 -1
- package/lib/module/primitives/text.js.map +1 -1
- package/lib/module/utils/date.js +386 -0
- package/lib/module/utils/date.js.map +1 -0
- package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
- package/lib/typescript/src/components/alert/index.d.ts.map +1 -1
- package/lib/typescript/src/components/area-chart/index.d.ts +41 -1
- package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/attachment/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bar-chart/index.d.ts +44 -2
- package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/breadcrumb/index.d.ts.map +1 -1
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/calendar/index.d.ts +173 -0
- package/lib/typescript/src/components/calendar/index.d.ts.map +1 -0
- package/lib/typescript/src/components/carousel/index.d.ts +179 -0
- package/lib/typescript/src/components/carousel/index.d.ts.map +1 -0
- package/lib/typescript/src/components/chip/index.d.ts.map +1 -1
- package/lib/typescript/src/components/code-block/highlight.d.ts +39 -0
- package/lib/typescript/src/components/code-block/highlight.d.ts.map +1 -0
- package/lib/typescript/src/components/code-block/index.d.ts +113 -0
- package/lib/typescript/src/components/code-block/index.d.ts.map +1 -0
- package/lib/typescript/src/components/date-picker/index.d.ts +97 -0
- package/lib/typescript/src/components/date-picker/index.d.ts.map +1 -0
- package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
- package/lib/typescript/src/components/direction/index.d.ts.map +1 -1
- package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
- package/lib/typescript/src/components/field/index.d.ts.map +1 -1
- package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
- package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
- package/lib/typescript/src/components/item/index.d.ts.map +1 -1
- package/lib/typescript/src/components/label/index.d.ts.map +1 -1
- package/lib/typescript/src/components/line-chart/index.d.ts +41 -2
- package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/map/index.d.ts.map +1 -1
- package/lib/typescript/src/components/marker/index.d.ts.map +1 -1
- package/lib/typescript/src/components/menu/index.d.ts +261 -0
- package/lib/typescript/src/components/menu/index.d.ts.map +1 -0
- package/lib/typescript/src/components/message/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -1
- package/lib/typescript/src/components/plan/index.d.ts +127 -0
- package/lib/typescript/src/components/plan/index.d.ts.map +1 -0
- package/lib/typescript/src/components/popover/index.d.ts +35 -1
- package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
- package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
- package/lib/typescript/src/components/reasoning/index.d.ts +97 -0
- package/lib/typescript/src/components/reasoning/index.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sources/index.d.ts +85 -0
- package/lib/typescript/src/components/sources/index.d.ts.map +1 -0
- package/lib/typescript/src/components/steps/index.d.ts.map +1 -1
- package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
- package/lib/typescript/src/components/task/index.d.ts +103 -0
- package/lib/typescript/src/components/task/index.d.ts.map +1 -0
- package/lib/typescript/src/components/textarea/index.d.ts +175 -0
- package/lib/typescript/src/components/textarea/index.d.ts.map +1 -0
- package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
- package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
- package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/tooltip/index.d.ts +180 -0
- package/lib/typescript/src/components/tooltip/index.d.ts.map +1 -0
- package/lib/typescript/src/components/typography/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/index.d.ts +1 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/use-back-handler.d.ts +19 -0
- package/lib/typescript/src/hooks/use-back-handler.d.ts.map +1 -0
- package/lib/typescript/src/icons/index.d.ts +17 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +16 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/collapse.d.ts +42 -0
- package/lib/typescript/src/primitives/collapse.d.ts.map +1 -0
- package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
- package/lib/typescript/src/primitives/text.d.ts +20 -0
- package/lib/typescript/src/primitives/text.d.ts.map +1 -1
- package/lib/typescript/src/utils/date.d.ts +116 -0
- package/lib/typescript/src/utils/date.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/accordion/index.tsx +8 -12
- package/src/components/alert/index.tsx +2 -2
- package/src/components/area-chart/index.tsx +208 -55
- package/src/components/attachment/index.tsx +2 -2
- package/src/components/avatar/index.tsx +3 -3
- package/src/components/badge/index.tsx +6 -6
- package/src/components/bar-chart/index.tsx +214 -54
- package/src/components/bottom-sheet/index.tsx +17 -16
- package/src/components/breadcrumb/index.tsx +6 -8
- package/src/components/button/index.tsx +12 -8
- package/src/components/calendar/index.tsx +970 -0
- package/src/components/carousel/index.tsx +788 -0
- package/src/components/chip/index.tsx +4 -6
- package/src/components/code-block/highlight.ts +278 -0
- package/src/components/code-block/index.tsx +341 -0
- package/src/components/date-picker/index.tsx +255 -0
- package/src/components/dialog/index.tsx +7 -2
- package/src/components/direction/index.tsx +2 -1
- package/src/components/empty-state/index.tsx +2 -2
- package/src/components/field/index.tsx +3 -5
- package/src/components/flow/index.tsx +3 -3
- package/src/components/frame/index.tsx +5 -7
- package/src/components/input-group/index.tsx +3 -2
- package/src/components/item/index.tsx +9 -9
- package/src/components/label/index.tsx +2 -2
- package/src/components/line-chart/index.tsx +189 -50
- package/src/components/map/index.tsx +7 -9
- package/src/components/marker/index.tsx +3 -3
- package/src/components/menu/index.tsx +812 -0
- package/src/components/message/index.tsx +7 -7
- package/src/components/message-scroller/index.tsx +5 -4
- package/src/components/plan/index.tsx +325 -0
- package/src/components/popover/index.tsx +111 -8
- package/src/components/radio-group/index.tsx +13 -4
- package/src/components/reasoning/index.tsx +297 -0
- package/src/components/section-rail/index.tsx +4 -4
- package/src/components/select/index.tsx +10 -4
- package/src/components/sources/index.tsx +278 -0
- package/src/components/steps/index.tsx +4 -4
- package/src/components/tabs/index.tsx +7 -9
- package/src/components/task/index.tsx +329 -0
- package/src/components/textarea/index.tsx +381 -0
- package/src/components/timeline/index.tsx +4 -4
- package/src/components/toast/index.tsx +2 -2
- package/src/components/toggle-button/index.tsx +5 -7
- package/src/components/tooltip/index.tsx +793 -0
- package/src/components/typography/index.tsx +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-back-handler.ts +37 -0
- package/src/icons/index.tsx +147 -0
- package/src/index.ts +116 -0
- package/src/primitives/collapse.tsx +128 -0
- package/src/primitives/keyboard-avoider.tsx +2 -1
- package/src/primitives/text.tsx +28 -1
- package/src/utils/date.ts +446 -0
- package/theme.css +112 -0
|
@@ -40,7 +40,7 @@ import Animated, {
|
|
|
40
40
|
withSpring,
|
|
41
41
|
} from 'react-native-reanimated';
|
|
42
42
|
import { tv } from 'tailwind-variants';
|
|
43
|
-
import { Text } from '../../primitives/text';
|
|
43
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
44
44
|
import { cn } from '../../utils/cn';
|
|
45
45
|
|
|
46
46
|
const SPRING = { damping: 24, stiffness: 300, mass: 0.7 } as const;
|
|
@@ -197,7 +197,7 @@ function TabsRoot({
|
|
|
197
197
|
return (
|
|
198
198
|
<TabsContext.Provider value={context}>
|
|
199
199
|
<View className={cn('gap-3', className)} {...props}>
|
|
200
|
-
{children}
|
|
200
|
+
{textChildren(children)}
|
|
201
201
|
</View>
|
|
202
202
|
</TabsContext.Provider>
|
|
203
203
|
);
|
|
@@ -274,7 +274,7 @@ function TabsList({ className, scrollable = false, children, ...props }: TabsLis
|
|
|
274
274
|
const row = (
|
|
275
275
|
<View accessibilityRole="tablist" className={cn(list(), className)} {...props}>
|
|
276
276
|
<TabsIndicator />
|
|
277
|
-
{children}
|
|
277
|
+
{textChildren(children)}
|
|
278
278
|
</View>
|
|
279
279
|
);
|
|
280
280
|
|
|
@@ -341,13 +341,11 @@ function TabsTrigger({
|
|
|
341
341
|
className={cn(slots.trigger(), (icon || badge) && 'flex-row gap-1.5', className)}
|
|
342
342
|
>
|
|
343
343
|
{icon}
|
|
344
|
-
{
|
|
344
|
+
{textChildren(children, (text) => (
|
|
345
345
|
<Text size="sm" weight="medium" className={slots.label()}>
|
|
346
|
-
{
|
|
346
|
+
{text}
|
|
347
347
|
</Text>
|
|
348
|
-
)
|
|
349
|
-
children
|
|
350
|
-
)}
|
|
348
|
+
))}
|
|
351
349
|
{badge}
|
|
352
350
|
</Pressable>
|
|
353
351
|
);
|
|
@@ -384,7 +382,7 @@ function TabsContent({ className, value, children, style, ...props }: TabsConten
|
|
|
384
382
|
className={className}
|
|
385
383
|
{...props}
|
|
386
384
|
>
|
|
387
|
-
{children}
|
|
385
|
+
{textChildren(children)}
|
|
388
386
|
</Animated.View>
|
|
389
387
|
);
|
|
390
388
|
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task — one step an agent took, and what it did while it was there.
|
|
3
|
+
*
|
|
4
|
+
* The header is the step; the body is the detail nobody reads unless something
|
|
5
|
+
* went wrong. Open by default, because a task that is running is the thing the
|
|
6
|
+
* reader is watching — and it stays open afterwards rather than folding itself
|
|
7
|
+
* away, because unlike a reasoning trace the steps are the record of what
|
|
8
|
+
* happened and are worth scrolling back through.
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <Task status="running">
|
|
12
|
+
* <Task.Trigger title="Searching the codebase" />
|
|
13
|
+
* <Task.Content>
|
|
14
|
+
* <Task.Item>
|
|
15
|
+
* Read <Task.File>calendar/index.tsx</Task.File>
|
|
16
|
+
* </Task.Item>
|
|
17
|
+
* </Task.Content>
|
|
18
|
+
* </Task>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ## Where the props come from
|
|
22
|
+
*
|
|
23
|
+
* With the AI SDK a task is a tool-call part: `part.type` is `tool-<name>` and
|
|
24
|
+
* `part.state` runs `input-streaming` → `input-available` → `output-available`
|
|
25
|
+
* or `output-error`. Those map onto `status` as pending, running, complete and
|
|
26
|
+
* error; `part.input` is usually what the body should say.
|
|
27
|
+
*/
|
|
28
|
+
import {
|
|
29
|
+
createContext,
|
|
30
|
+
useCallback,
|
|
31
|
+
useContext,
|
|
32
|
+
useEffect,
|
|
33
|
+
useMemo,
|
|
34
|
+
useState,
|
|
35
|
+
type ReactNode,
|
|
36
|
+
} from 'react';
|
|
37
|
+
import { Pressable, View, type PressableProps, type ViewProps } from 'react-native';
|
|
38
|
+
import Animated, {
|
|
39
|
+
useAnimatedStyle,
|
|
40
|
+
useReducedMotion,
|
|
41
|
+
useSharedValue,
|
|
42
|
+
withTiming,
|
|
43
|
+
} from 'react-native-reanimated';
|
|
44
|
+
import { tv } from 'tailwind-variants';
|
|
45
|
+
import { useCSSVariable } from 'uniwind';
|
|
46
|
+
import {
|
|
47
|
+
AlertTriangleIcon,
|
|
48
|
+
CheckCircleIcon,
|
|
49
|
+
ChevronDownIcon,
|
|
50
|
+
CircleIcon,
|
|
51
|
+
SearchIcon,
|
|
52
|
+
} from '../../icons';
|
|
53
|
+
import { Collapse } from '../../primitives/collapse';
|
|
54
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
55
|
+
import { cn } from '../../utils/cn';
|
|
56
|
+
import { Shimmer } from '../shimmer';
|
|
57
|
+
|
|
58
|
+
export type TaskStatus = 'pending' | 'running' | 'complete' | 'error';
|
|
59
|
+
|
|
60
|
+
const taskVariants = tv({
|
|
61
|
+
slots: {
|
|
62
|
+
root: 'w-full gap-2',
|
|
63
|
+
trigger: 'flex-row items-center gap-2 py-0.5',
|
|
64
|
+
title: 'flex-1 text-sm text-muted-foreground',
|
|
65
|
+
/*
|
|
66
|
+
* Indented behind a rule rather than merely padded. The rule is what says
|
|
67
|
+
* these lines belong to the step above them instead of being the next few
|
|
68
|
+
* steps, which matters as soon as there is more than one task in a row.
|
|
69
|
+
*/
|
|
70
|
+
content: 'ms-2 gap-1.5 border-s border-border ps-4',
|
|
71
|
+
item: 'text-sm leading-relaxed text-muted-foreground',
|
|
72
|
+
file: 'flex-row items-center gap-1 self-start rounded-md border border-border bg-muted px-1.5 py-0.5',
|
|
73
|
+
fileLabel: 'font-mono text-xs text-foreground',
|
|
74
|
+
},
|
|
75
|
+
variants: {
|
|
76
|
+
status: {
|
|
77
|
+
pending: { title: 'text-muted-foreground/60' },
|
|
78
|
+
running: {},
|
|
79
|
+
complete: {},
|
|
80
|
+
error: { title: 'text-destructive' },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
defaultVariants: {
|
|
84
|
+
status: 'complete',
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
interface TaskContextValue {
|
|
89
|
+
status: TaskStatus;
|
|
90
|
+
open: boolean;
|
|
91
|
+
setOpen: (open: boolean) => void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const TaskContext = createContext<TaskContextValue | null>(null);
|
|
95
|
+
|
|
96
|
+
function useTask(component: string): TaskContextValue {
|
|
97
|
+
const context = useContext(TaskContext);
|
|
98
|
+
if (!context) {
|
|
99
|
+
throw new Error(`${component} must be used within a <Task>`);
|
|
100
|
+
}
|
|
101
|
+
return context;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface TaskProps extends Omit<ViewProps, 'children'> {
|
|
105
|
+
className?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Where the step has got to. Drives the leading glyph, and puts a shimmer on
|
|
108
|
+
* the title while it is `running`.
|
|
109
|
+
*/
|
|
110
|
+
status?: TaskStatus;
|
|
111
|
+
/** Controlled open state. */
|
|
112
|
+
open?: boolean;
|
|
113
|
+
/** Initial state when uncontrolled. Open — the steps are the record. */
|
|
114
|
+
defaultOpen?: boolean;
|
|
115
|
+
onOpenChange?: (open: boolean) => void;
|
|
116
|
+
children?: ReactNode;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function TaskRoot({
|
|
120
|
+
className,
|
|
121
|
+
status = 'complete',
|
|
122
|
+
open: openProp,
|
|
123
|
+
defaultOpen = true,
|
|
124
|
+
onOpenChange,
|
|
125
|
+
children,
|
|
126
|
+
...props
|
|
127
|
+
}: TaskProps) {
|
|
128
|
+
const { root } = taskVariants({ status });
|
|
129
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
130
|
+
const isControlled = openProp !== undefined;
|
|
131
|
+
const open = isControlled ? openProp : internalOpen;
|
|
132
|
+
|
|
133
|
+
const setOpen = useCallback(
|
|
134
|
+
(next: boolean) => {
|
|
135
|
+
if (!isControlled) setInternalOpen(next);
|
|
136
|
+
onOpenChange?.(next);
|
|
137
|
+
},
|
|
138
|
+
[isControlled, onOpenChange]
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const context = useMemo(() => ({ status, open, setOpen }), [status, open, setOpen]);
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<TaskContext.Provider value={context}>
|
|
145
|
+
<View {...props} className={cn(root(), className)}>
|
|
146
|
+
{children}
|
|
147
|
+
</View>
|
|
148
|
+
</TaskContext.Provider>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
TaskRoot.displayName = 'Task';
|
|
152
|
+
|
|
153
|
+
export interface TaskTriggerProps extends Omit<PressableProps, 'children' | 'style'> {
|
|
154
|
+
className?: string;
|
|
155
|
+
/** What the step is. Shimmers while the status is `running`. */
|
|
156
|
+
title?: string;
|
|
157
|
+
/** Leading glyph. Derived from `status` when not given. */
|
|
158
|
+
icon?: ReactNode;
|
|
159
|
+
/** Replaces the whole row. */
|
|
160
|
+
children?: ReactNode;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function TaskTrigger({
|
|
164
|
+
className,
|
|
165
|
+
title,
|
|
166
|
+
icon,
|
|
167
|
+
children,
|
|
168
|
+
onPress,
|
|
169
|
+
...props
|
|
170
|
+
}: TaskTriggerProps) {
|
|
171
|
+
const { status, open, setOpen } = useTask('Task.Trigger');
|
|
172
|
+
const slots = taskVariants({ status });
|
|
173
|
+
const reducedMotion = useReducedMotion();
|
|
174
|
+
const progress = useSharedValue(open ? 1 : 0);
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
progress.value = reducedMotion
|
|
178
|
+
? open
|
|
179
|
+
? 1
|
|
180
|
+
: 0
|
|
181
|
+
: withTiming(open ? 1 : 0, { duration: 180 });
|
|
182
|
+
}, [open, reducedMotion, progress]);
|
|
183
|
+
|
|
184
|
+
const chevronStyle = useAnimatedStyle(() => ({
|
|
185
|
+
transform: [{ rotate: `${progress.value * 180}deg` }],
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<Pressable
|
|
190
|
+
accessibilityRole="button"
|
|
191
|
+
accessibilityState={{ expanded: open }}
|
|
192
|
+
onPress={(event) => {
|
|
193
|
+
onPress?.(event);
|
|
194
|
+
setOpen(!open);
|
|
195
|
+
}}
|
|
196
|
+
className={cn(slots.trigger(), className)}
|
|
197
|
+
{...props}
|
|
198
|
+
>
|
|
199
|
+
{children ?? (
|
|
200
|
+
<>
|
|
201
|
+
{icon ?? <TaskStatusIcon status={status} />}
|
|
202
|
+
{status === 'running' && title ? (
|
|
203
|
+
<View className="flex-1">
|
|
204
|
+
<Shimmer textClassName={slots.title()}>{title}</Shimmer>
|
|
205
|
+
</View>
|
|
206
|
+
) : (
|
|
207
|
+
<Text numberOfLines={1} className={slots.title()}>
|
|
208
|
+
{title}
|
|
209
|
+
</Text>
|
|
210
|
+
)}
|
|
211
|
+
<Animated.View style={chevronStyle}>
|
|
212
|
+
<ChevronDownIcon size={16} />
|
|
213
|
+
</Animated.View>
|
|
214
|
+
</>
|
|
215
|
+
)}
|
|
216
|
+
</Pressable>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The glyph for each status. A magnifier while running: a step is a search.
|
|
222
|
+
*
|
|
223
|
+
* Every one is given an explicit colour. The filled status icons fall back to
|
|
224
|
+
* `currentColor`, which React Native's SVG does not resolve — it paints black,
|
|
225
|
+
* which on a dark theme is a black disc floating in the row. They are built to
|
|
226
|
+
* take their colour from an enclosing `IconColorProvider`, and a task row is
|
|
227
|
+
* not one, so the tint is resolved here.
|
|
228
|
+
*/
|
|
229
|
+
function TaskStatusIcon({ status }: { status: TaskStatus }) {
|
|
230
|
+
const muted = useTint('--color-muted-foreground');
|
|
231
|
+
const success = useTint('--color-success');
|
|
232
|
+
const destructive = useTint('--color-destructive');
|
|
233
|
+
|
|
234
|
+
switch (status) {
|
|
235
|
+
case 'pending':
|
|
236
|
+
return <CircleIcon size={16} color={muted} />;
|
|
237
|
+
case 'error':
|
|
238
|
+
return <AlertTriangleIcon size={16} color={destructive} />;
|
|
239
|
+
case 'complete':
|
|
240
|
+
return <CheckCircleIcon size={16} color={success} />;
|
|
241
|
+
default:
|
|
242
|
+
return <SearchIcon size={16} color={muted} />;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* A theme token as a colour an icon will accept.
|
|
248
|
+
*
|
|
249
|
+
* `useCSSVariable` answers with whatever the token holds, which for a length or
|
|
250
|
+
* a number is not a colour at all — so anything that is not a string is dropped
|
|
251
|
+
* and the icon falls back to what it would have used anyway.
|
|
252
|
+
*/
|
|
253
|
+
function useTint(variable: string): string | undefined {
|
|
254
|
+
const raw = useCSSVariable(variable);
|
|
255
|
+
return typeof raw === 'string' ? raw : undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface TaskContentProps extends Omit<ViewProps, 'children'> {
|
|
259
|
+
className?: string;
|
|
260
|
+
children?: ReactNode;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function TaskContent({ className, children, ...props }: TaskContentProps) {
|
|
264
|
+
const { open } = useTask('Task.Content');
|
|
265
|
+
const { content } = taskVariants();
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<Collapse open={open} className={cn(content(), className)} {...props}>
|
|
269
|
+
{children}
|
|
270
|
+
</Collapse>
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export interface TaskItemProps extends Omit<ViewProps, 'children'> {
|
|
275
|
+
className?: string;
|
|
276
|
+
children?: ReactNode;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** One line of what the step did. */
|
|
280
|
+
function TaskItem({ className, children, ...props }: TaskItemProps) {
|
|
281
|
+
const { item } = taskVariants();
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<View {...props} className={cn('flex-row flex-wrap items-center gap-1', className)}>
|
|
285
|
+
{textChildren(children, (text) => (
|
|
286
|
+
<Text className={item()}>{text}</Text>
|
|
287
|
+
))}
|
|
288
|
+
</View>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface TaskFileProps extends Omit<ViewProps, 'children'> {
|
|
293
|
+
className?: string;
|
|
294
|
+
/** A glyph for the file's kind, drawn before the name. */
|
|
295
|
+
icon?: ReactNode;
|
|
296
|
+
children?: ReactNode;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* A filename inside a line, drawn as a chip.
|
|
301
|
+
*
|
|
302
|
+
* Bordered rather than merely monospaced, because a path in the middle of a
|
|
303
|
+
* sentence is otherwise indistinguishable from the sentence — and the paths
|
|
304
|
+
* are the part of a task line anyone actually scans for.
|
|
305
|
+
*/
|
|
306
|
+
function TaskFile({ className, icon, children, ...props }: TaskFileProps) {
|
|
307
|
+
const { file, fileLabel } = taskVariants();
|
|
308
|
+
|
|
309
|
+
return (
|
|
310
|
+
<View {...props} className={cn(file(), className)}>
|
|
311
|
+
{icon}
|
|
312
|
+
{textChildren(children, (text) => (
|
|
313
|
+
<Text className={fileLabel()}>{text}</Text>
|
|
314
|
+
))}
|
|
315
|
+
</View>
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
TaskTrigger.displayName = 'Task.Trigger';
|
|
320
|
+
TaskContent.displayName = 'Task.Content';
|
|
321
|
+
TaskItem.displayName = 'Task.Item';
|
|
322
|
+
TaskFile.displayName = 'Task.File';
|
|
323
|
+
|
|
324
|
+
export const Task = Object.assign(TaskRoot, {
|
|
325
|
+
Trigger: TaskTrigger,
|
|
326
|
+
Content: TaskContent,
|
|
327
|
+
Item: TaskItem,
|
|
328
|
+
File: TaskFile,
|
|
329
|
+
});
|