panelui-native 0.30.0 → 0.34.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 +4 -2
- package/lib/module/components/button/index.js +106 -11
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/calendar/index.js +107 -24
- package/lib/module/components/calendar/index.js.map +1 -1
- package/lib/module/components/drawer/index.js +477 -0
- package/lib/module/components/drawer/index.js.map +1 -0
- package/lib/module/components/heatmap-chart/index.js +9 -8
- package/lib/module/components/heatmap-chart/index.js.map +1 -1
- package/lib/module/components/map/index.js +50 -4
- package/lib/module/components/map/index.js.map +1 -1
- package/lib/module/components/panelside/index.js +1024 -0
- package/lib/module/components/panelside/index.js.map +1 -0
- package/lib/module/components/plan/index.js +307 -21
- package/lib/module/components/plan/index.js.map +1 -1
- package/lib/module/components/post/index.js +992 -0
- package/lib/module/components/post/index.js.map +1 -0
- package/lib/module/components/response/index.js +296 -0
- package/lib/module/components/response/index.js.map +1 -0
- package/lib/module/components/response/markdown.js +463 -0
- package/lib/module/components/response/markdown.js.map +1 -0
- package/lib/module/components/select/index.js +111 -18
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/table/index.js +632 -0
- package/lib/module/components/table/index.js.map +1 -0
- package/lib/module/icons/index.js +220 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +6 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/native/index.js +30 -0
- package/lib/module/native/index.js.map +1 -1
- package/lib/module/utils/date.js +129 -22
- package/lib/module/utils/date.js.map +1 -1
- package/lib/typescript/src/components/button/index.d.ts +22 -1
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/calendar/index.d.ts +12 -3
- package/lib/typescript/src/components/calendar/index.d.ts.map +1 -1
- package/lib/typescript/src/components/drawer/index.d.ts +146 -0
- package/lib/typescript/src/components/drawer/index.d.ts.map +1 -0
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/map/index.d.ts +8 -1
- package/lib/typescript/src/components/map/index.d.ts.map +1 -1
- package/lib/typescript/src/components/panelside/index.d.ts +354 -0
- package/lib/typescript/src/components/panelside/index.d.ts.map +1 -0
- package/lib/typescript/src/components/plan/index.d.ts +121 -10
- package/lib/typescript/src/components/plan/index.d.ts.map +1 -1
- package/lib/typescript/src/components/post/index.d.ts +358 -0
- package/lib/typescript/src/components/post/index.d.ts.map +1 -0
- package/lib/typescript/src/components/response/index.d.ts +91 -0
- package/lib/typescript/src/components/response/index.d.ts.map +1 -0
- package/lib/typescript/src/components/response/markdown.d.ts +88 -0
- package/lib/typescript/src/components/response/markdown.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts +27 -2
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/table/index.d.ts +274 -0
- package/lib/typescript/src/components/table/index.d.ts.map +1 -0
- package/lib/typescript/src/icons/index.d.ts +41 -1
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +7 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/index.d.ts +20 -0
- package/lib/typescript/src/native/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/date.d.ts +49 -5
- package/lib/typescript/src/utils/date.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/button/index.tsx +140 -8
- package/src/components/calendar/index.tsx +136 -23
- package/src/components/drawer/index.tsx +662 -0
- package/src/components/heatmap-chart/index.tsx +9 -9
- package/src/components/map/index.tsx +53 -4
- package/src/components/panelside/index.tsx +1358 -0
- package/src/components/plan/index.tsx +344 -21
- package/src/components/post/index.tsx +1116 -0
- package/src/components/response/index.tsx +390 -0
- package/src/components/response/markdown.ts +489 -0
- package/src/components/select/index.tsx +155 -15
- package/src/components/table/index.tsx +747 -0
- package/src/icons/index.tsx +176 -1
- package/src/index.ts +93 -0
- package/src/native/index.ts +51 -0
- package/src/utils/date.ts +146 -22
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post — a card carrying something somebody said, and what everyone did about it.
|
|
3
|
+
*
|
|
4
|
+
* Four shapes, because a feed is not one thing. `feed` is the full card: author,
|
|
5
|
+
* body, media and a row of counts. `vote` puts a score pill beside a headline
|
|
6
|
+
* and a thumbnail, the way a ranked community reads. `compact` drops the media
|
|
7
|
+
* and puts the name and handle on one line, for a dense timeline. `media` gives
|
|
8
|
+
* the image the whole card and lays the author over it.
|
|
9
|
+
*
|
|
10
|
+
* What they share is the anatomy — the same `Post.Header`, `Post.Body`,
|
|
11
|
+
* `Post.Footer` in every one — so moving between them is a prop rather than a
|
|
12
|
+
* rewrite. The variant decides padding, media shape and where the author sits;
|
|
13
|
+
* it does not decide which parts exist.
|
|
14
|
+
*
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <Post variant="feed">
|
|
17
|
+
* <Post.Header>
|
|
18
|
+
* <Post.Author name="Dwayne F. White" verified timestamp="3m ago" avatar={face} />
|
|
19
|
+
* <Post.Action><EllipsisIcon /></Post.Action>
|
|
20
|
+
* </Post.Header>
|
|
21
|
+
* <Post.Body>I've been paying off my credit card #FinancialFreedom</Post.Body>
|
|
22
|
+
* <Post.Media source={photo} />
|
|
23
|
+
* <Post.Footer>
|
|
24
|
+
* <Post.Stat icon={EyeIcon} value="5,874" />
|
|
25
|
+
* <Post.Stat icon={HeartIcon} value="215" tone="like" />
|
|
26
|
+
* <Post.Stat icon={MessageCircleIcon} value="11" />
|
|
27
|
+
* <Post.Stat icon={BookmarkIcon} value="Save" align="end" />
|
|
28
|
+
* </Post.Footer>
|
|
29
|
+
* </Post>
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* ## Counts change under the finger
|
|
33
|
+
*
|
|
34
|
+
* Every control here is a toggle over a number, and the number is the point: a
|
|
35
|
+
* like that lights up but leaves `215` sitting there has not told you it
|
|
36
|
+
* counted. So a stat that changes animates the old value out and the new one in
|
|
37
|
+
* along the direction of the change, and `Post.Votes` does the same with its
|
|
38
|
+
* arrows. The alternative — repainting the digits in place — is indisting-
|
|
39
|
+
* uishable from a re-render, which is exactly the doubt the animation exists to
|
|
40
|
+
* remove.
|
|
41
|
+
*/
|
|
42
|
+
import { type ComponentType, type ReactNode } from 'react';
|
|
43
|
+
import { View, type ImageSourcePropType, type PressableProps, type ViewProps } from 'react-native';
|
|
44
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
45
|
+
import { type IconProps } from '../../icons/index.js';
|
|
46
|
+
declare const postVariants: import("tailwind-variants").TVReturnType<{
|
|
47
|
+
variant: {
|
|
48
|
+
/** The full card — author, body, media, counts. */
|
|
49
|
+
feed: {
|
|
50
|
+
header: string;
|
|
51
|
+
body: string;
|
|
52
|
+
media: string;
|
|
53
|
+
footer: string;
|
|
54
|
+
};
|
|
55
|
+
/** A headline with a score beside it, the way a ranked community reads. */
|
|
56
|
+
vote: {
|
|
57
|
+
header: string;
|
|
58
|
+
body: string;
|
|
59
|
+
media: string;
|
|
60
|
+
footer: string;
|
|
61
|
+
};
|
|
62
|
+
/** No media, name and handle on one line — for a dense timeline. */
|
|
63
|
+
compact: {
|
|
64
|
+
root: string;
|
|
65
|
+
header: string;
|
|
66
|
+
body: string;
|
|
67
|
+
media: string;
|
|
68
|
+
footer: string;
|
|
69
|
+
};
|
|
70
|
+
/** The image is the card; the author is laid over it. */
|
|
71
|
+
media: {
|
|
72
|
+
header: string;
|
|
73
|
+
body: string;
|
|
74
|
+
media: string;
|
|
75
|
+
footer: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
size: {
|
|
79
|
+
default: {};
|
|
80
|
+
sm: {
|
|
81
|
+
name: string;
|
|
82
|
+
meta: string;
|
|
83
|
+
statLabel: string;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
}, {
|
|
87
|
+
root: string;
|
|
88
|
+
header: string;
|
|
89
|
+
author: string;
|
|
90
|
+
authorLine: string;
|
|
91
|
+
name: string;
|
|
92
|
+
handle: string;
|
|
93
|
+
meta: string;
|
|
94
|
+
action: string;
|
|
95
|
+
community: string;
|
|
96
|
+
communityName: string;
|
|
97
|
+
communityMeta: string;
|
|
98
|
+
title: string;
|
|
99
|
+
body: string;
|
|
100
|
+
media: string;
|
|
101
|
+
footer: string;
|
|
102
|
+
stat: string;
|
|
103
|
+
statLabel: string;
|
|
104
|
+
votes: string;
|
|
105
|
+
voteButton: string;
|
|
106
|
+
voteScore: string;
|
|
107
|
+
}, undefined, {
|
|
108
|
+
variant: {
|
|
109
|
+
/** The full card — author, body, media, counts. */
|
|
110
|
+
feed: {
|
|
111
|
+
header: string;
|
|
112
|
+
body: string;
|
|
113
|
+
media: string;
|
|
114
|
+
footer: string;
|
|
115
|
+
};
|
|
116
|
+
/** A headline with a score beside it, the way a ranked community reads. */
|
|
117
|
+
vote: {
|
|
118
|
+
header: string;
|
|
119
|
+
body: string;
|
|
120
|
+
media: string;
|
|
121
|
+
footer: string;
|
|
122
|
+
};
|
|
123
|
+
/** No media, name and handle on one line — for a dense timeline. */
|
|
124
|
+
compact: {
|
|
125
|
+
root: string;
|
|
126
|
+
header: string;
|
|
127
|
+
body: string;
|
|
128
|
+
media: string;
|
|
129
|
+
footer: string;
|
|
130
|
+
};
|
|
131
|
+
/** The image is the card; the author is laid over it. */
|
|
132
|
+
media: {
|
|
133
|
+
header: string;
|
|
134
|
+
body: string;
|
|
135
|
+
media: string;
|
|
136
|
+
footer: string;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
size: {
|
|
140
|
+
default: {};
|
|
141
|
+
sm: {
|
|
142
|
+
name: string;
|
|
143
|
+
meta: string;
|
|
144
|
+
statLabel: string;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
}, {
|
|
148
|
+
root: string;
|
|
149
|
+
header: string;
|
|
150
|
+
author: string;
|
|
151
|
+
authorLine: string;
|
|
152
|
+
name: string;
|
|
153
|
+
handle: string;
|
|
154
|
+
meta: string;
|
|
155
|
+
action: string;
|
|
156
|
+
community: string;
|
|
157
|
+
communityName: string;
|
|
158
|
+
communityMeta: string;
|
|
159
|
+
title: string;
|
|
160
|
+
body: string;
|
|
161
|
+
media: string;
|
|
162
|
+
footer: string;
|
|
163
|
+
stat: string;
|
|
164
|
+
statLabel: string;
|
|
165
|
+
votes: string;
|
|
166
|
+
voteButton: string;
|
|
167
|
+
voteScore: string;
|
|
168
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
169
|
+
variant: {
|
|
170
|
+
/** The full card — author, body, media, counts. */
|
|
171
|
+
feed: {
|
|
172
|
+
header: string;
|
|
173
|
+
body: string;
|
|
174
|
+
media: string;
|
|
175
|
+
footer: string;
|
|
176
|
+
};
|
|
177
|
+
/** A headline with a score beside it, the way a ranked community reads. */
|
|
178
|
+
vote: {
|
|
179
|
+
header: string;
|
|
180
|
+
body: string;
|
|
181
|
+
media: string;
|
|
182
|
+
footer: string;
|
|
183
|
+
};
|
|
184
|
+
/** No media, name and handle on one line — for a dense timeline. */
|
|
185
|
+
compact: {
|
|
186
|
+
root: string;
|
|
187
|
+
header: string;
|
|
188
|
+
body: string;
|
|
189
|
+
media: string;
|
|
190
|
+
footer: string;
|
|
191
|
+
};
|
|
192
|
+
/** The image is the card; the author is laid over it. */
|
|
193
|
+
media: {
|
|
194
|
+
header: string;
|
|
195
|
+
body: string;
|
|
196
|
+
media: string;
|
|
197
|
+
footer: string;
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
size: {
|
|
201
|
+
default: {};
|
|
202
|
+
sm: {
|
|
203
|
+
name: string;
|
|
204
|
+
meta: string;
|
|
205
|
+
statLabel: string;
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
}, {
|
|
209
|
+
root: string;
|
|
210
|
+
header: string;
|
|
211
|
+
author: string;
|
|
212
|
+
authorLine: string;
|
|
213
|
+
name: string;
|
|
214
|
+
handle: string;
|
|
215
|
+
meta: string;
|
|
216
|
+
action: string;
|
|
217
|
+
community: string;
|
|
218
|
+
communityName: string;
|
|
219
|
+
communityMeta: string;
|
|
220
|
+
title: string;
|
|
221
|
+
body: string;
|
|
222
|
+
media: string;
|
|
223
|
+
footer: string;
|
|
224
|
+
stat: string;
|
|
225
|
+
statLabel: string;
|
|
226
|
+
votes: string;
|
|
227
|
+
voteButton: string;
|
|
228
|
+
voteScore: string;
|
|
229
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
230
|
+
type PostVariant = 'feed' | 'vote' | 'compact' | 'media';
|
|
231
|
+
export interface PostProps extends Omit<ViewProps, 'children'>, VariantProps<typeof postVariants> {
|
|
232
|
+
className?: string;
|
|
233
|
+
/** Which of the four shapes. */
|
|
234
|
+
variant?: PostVariant;
|
|
235
|
+
/** `sm` tightens the type for a card in a sidebar or a preview. */
|
|
236
|
+
size?: 'default' | 'sm';
|
|
237
|
+
/** Opening the post itself. The parts inside keep their own presses. */
|
|
238
|
+
onPress?: PressableProps['onPress'];
|
|
239
|
+
children?: ReactNode;
|
|
240
|
+
}
|
|
241
|
+
export interface PostHeaderProps extends ViewProps {
|
|
242
|
+
className?: string;
|
|
243
|
+
children?: ReactNode;
|
|
244
|
+
}
|
|
245
|
+
export interface PostAuthorProps extends Omit<ViewProps, 'children'> {
|
|
246
|
+
className?: string;
|
|
247
|
+
/** Display name. */
|
|
248
|
+
name: string;
|
|
249
|
+
/** `@handle`, shown beside the name in `compact` and under it elsewhere. */
|
|
250
|
+
handle?: string;
|
|
251
|
+
avatar?: ImageSourcePropType;
|
|
252
|
+
/** Initials behind a missing or broken avatar. */
|
|
253
|
+
fallback?: string;
|
|
254
|
+
/** Draws the verification rosette after the name. */
|
|
255
|
+
verified?: boolean;
|
|
256
|
+
/** "Posted 3m ago" — whatever the caller wants to call the time. */
|
|
257
|
+
timestamp?: ReactNode;
|
|
258
|
+
children?: ReactNode;
|
|
259
|
+
}
|
|
260
|
+
export interface PostActionProps extends ViewProps {
|
|
261
|
+
className?: string;
|
|
262
|
+
children?: ReactNode;
|
|
263
|
+
}
|
|
264
|
+
export interface PostCommunityProps extends Omit<ViewProps, 'children'> {
|
|
265
|
+
className?: string;
|
|
266
|
+
/** The group's name — "r/reactnative", "#design". */
|
|
267
|
+
name: string;
|
|
268
|
+
avatar?: ImageSourcePropType;
|
|
269
|
+
/** How long ago, and anything else that belongs on the line. */
|
|
270
|
+
meta?: ReactNode;
|
|
271
|
+
children?: ReactNode;
|
|
272
|
+
}
|
|
273
|
+
export interface PostTitleProps extends ViewProps {
|
|
274
|
+
className?: string;
|
|
275
|
+
children?: ReactNode;
|
|
276
|
+
}
|
|
277
|
+
export interface PostBodyProps extends Omit<ViewProps, 'children'> {
|
|
278
|
+
className?: string;
|
|
279
|
+
/** How many lines before it is cut off. Unlimited by default. */
|
|
280
|
+
numberOfLines?: number;
|
|
281
|
+
/** Called with the tag, without its `#`. Makes hashtags pressable. */
|
|
282
|
+
onTagPress?: (tag: string) => void;
|
|
283
|
+
/** Called with the handle, without its `@`. */
|
|
284
|
+
onMentionPress?: (handle: string) => void;
|
|
285
|
+
children?: ReactNode;
|
|
286
|
+
}
|
|
287
|
+
export interface PostMediaProps extends Omit<ViewProps, 'children'> {
|
|
288
|
+
className?: string;
|
|
289
|
+
source: ImageSourcePropType;
|
|
290
|
+
/** Width over height. `16 / 10` by default — wide enough not to eat the feed. */
|
|
291
|
+
aspectRatio?: number;
|
|
292
|
+
/**
|
|
293
|
+
* Darkens an edge of the image so type laid over it stays legible.
|
|
294
|
+
*
|
|
295
|
+
* A gradient rather than a panel: a flat rectangle over the top of a
|
|
296
|
+
* photograph has an edge of its own, and that edge reads as a bar covering
|
|
297
|
+
* the picture rather than as shading. `media` posts default to `top`, where
|
|
298
|
+
* the author sits; everything else to `none`.
|
|
299
|
+
*/
|
|
300
|
+
scrim?: 'none' | 'top' | 'bottom' | 'both';
|
|
301
|
+
/** Laid over the image: an expand affordance, a duration, a gallery count. */
|
|
302
|
+
overlay?: ReactNode;
|
|
303
|
+
/** Described for a screen reader. An image with nothing to say is decorative. */
|
|
304
|
+
alt?: string;
|
|
305
|
+
onPress?: PressableProps['onPress'];
|
|
306
|
+
children?: ReactNode;
|
|
307
|
+
}
|
|
308
|
+
export interface PostFooterProps extends ViewProps {
|
|
309
|
+
className?: string;
|
|
310
|
+
children?: ReactNode;
|
|
311
|
+
}
|
|
312
|
+
export interface PostStatProps extends Omit<PressableProps, 'children' | 'style'> {
|
|
313
|
+
className?: string;
|
|
314
|
+
/** The icon component itself, not an element — it is re-rendered on toggle. */
|
|
315
|
+
icon?: ComponentType<IconProps & {
|
|
316
|
+
filled?: boolean;
|
|
317
|
+
}>;
|
|
318
|
+
/** The number, or a word where a number would be meaningless ("Save"). */
|
|
319
|
+
value?: ReactNode;
|
|
320
|
+
/** Lit, and filled. */
|
|
321
|
+
active?: boolean;
|
|
322
|
+
/** Which colour "lit" is. */
|
|
323
|
+
tone?: 'default' | 'like' | 'save' | 'repost';
|
|
324
|
+
/** Pushes this stat and everything after it to the trailing edge. */
|
|
325
|
+
align?: 'start' | 'end';
|
|
326
|
+
children?: ReactNode;
|
|
327
|
+
}
|
|
328
|
+
export type PostVote = 'up' | 'down' | null;
|
|
329
|
+
export interface PostVotesProps extends Omit<ViewProps, 'children'> {
|
|
330
|
+
className?: string;
|
|
331
|
+
/** The score as it stands, with the reader's own vote already in it. */
|
|
332
|
+
score: number | string;
|
|
333
|
+
/** Which way this reader voted, if either. */
|
|
334
|
+
vote?: PostVote;
|
|
335
|
+
/**
|
|
336
|
+
* Called with the new vote. Pressing the arrow already cast clears it, so
|
|
337
|
+
* `null` arrives as often as the other two — a vote you cannot take back is
|
|
338
|
+
* a vote people hesitate over.
|
|
339
|
+
*/
|
|
340
|
+
onVote?: (vote: PostVote) => void;
|
|
341
|
+
/** `vertical` stacks the arrows beside a thumbnail, the way a ranked list reads. */
|
|
342
|
+
orientation?: 'horizontal' | 'vertical';
|
|
343
|
+
disabled?: boolean;
|
|
344
|
+
}
|
|
345
|
+
export declare const Post: import("react").ForwardRefExoticComponent<PostProps & import("react").RefAttributes<View>> & {
|
|
346
|
+
Header: import("react").ForwardRefExoticComponent<PostHeaderProps & import("react").RefAttributes<View>>;
|
|
347
|
+
Author: import("react").ForwardRefExoticComponent<PostAuthorProps & import("react").RefAttributes<View>>;
|
|
348
|
+
Action: import("react").ForwardRefExoticComponent<PostActionProps & import("react").RefAttributes<View>>;
|
|
349
|
+
Community: import("react").ForwardRefExoticComponent<PostCommunityProps & import("react").RefAttributes<View>>;
|
|
350
|
+
Title: import("react").ForwardRefExoticComponent<PostTitleProps & import("react").RefAttributes<View>>;
|
|
351
|
+
Body: import("react").ForwardRefExoticComponent<PostBodyProps & import("react").RefAttributes<View>>;
|
|
352
|
+
Media: import("react").ForwardRefExoticComponent<PostMediaProps & import("react").RefAttributes<View>>;
|
|
353
|
+
Footer: import("react").ForwardRefExoticComponent<PostFooterProps & import("react").RefAttributes<View>>;
|
|
354
|
+
Stat: import("react").ForwardRefExoticComponent<PostStatProps & import("react").RefAttributes<View>>;
|
|
355
|
+
Votes: import("react").ForwardRefExoticComponent<PostVotesProps & import("react").RefAttributes<View>>;
|
|
356
|
+
};
|
|
357
|
+
export {};
|
|
358
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/post/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response — a model's answer, rendered as it arrives.
|
|
3
|
+
*
|
|
4
|
+
* An answer is markdown. It has headings and lists and fenced code in it,
|
|
5
|
+
* because that is what a model writes, and rendering it as one run of plain
|
|
6
|
+
* text throws away the structure the model went to the trouble of producing.
|
|
7
|
+
*
|
|
8
|
+
* So this reads the markdown and renders it through the library's own parts —
|
|
9
|
+
* `Typography` for prose, `CodeBlock` for fences, `Table` for tables. Nothing
|
|
10
|
+
* here draws its own type or its own colours: an answer inside a message bubble
|
|
11
|
+
* should look like the app it is in, not like a document viewer someone
|
|
12
|
+
* embedded.
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <Response isStreaming={status === 'streaming'}>{text}</Response>
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* ## Why it is a whole component and not a `<Text>`
|
|
19
|
+
*
|
|
20
|
+
* Because the text is still arriving, and that changes everything about how it
|
|
21
|
+
* has to be read. A token stream hands you every prefix of the final answer, so
|
|
22
|
+
* a renderer sees `**bo`, then `**bol`, then `**bold**` — three documents, two
|
|
23
|
+
* of which have literal asterisks in them. Render each faithfully and the
|
|
24
|
+
* answer flickers between styles on nearly every frame, which is worse than no
|
|
25
|
+
* formatting at all: the eye tracks the flicker instead of the words.
|
|
26
|
+
*
|
|
27
|
+
* `isStreaming` tells the reader to finish an unterminated construct at the end
|
|
28
|
+
* of the input rather than escaping it — an open fence is a code block that is
|
|
29
|
+
* still filling, an open `**` is bold text still being written. The rule it
|
|
30
|
+
* works to is that no word already on screen may disappear when the next token
|
|
31
|
+
* arrives; delimiters may vanish as they are recognised, words never do.
|
|
32
|
+
*
|
|
33
|
+
* ## Where the props come from
|
|
34
|
+
*
|
|
35
|
+
* With the AI SDK, `children` is the text of the assistant message's text parts
|
|
36
|
+
* joined together, and `isStreaming` is `status === 'streaming'`. Join the
|
|
37
|
+
* parts — one `Response` per part renders a heading in one component and the
|
|
38
|
+
* paragraph under it in another, and neither knows about the other.
|
|
39
|
+
*/
|
|
40
|
+
import { type ComponentType } from 'react';
|
|
41
|
+
import { type ViewProps } from 'react-native';
|
|
42
|
+
export type { Block as ResponseBlock, InlineToken as ResponseInline } from './markdown.js';
|
|
43
|
+
export interface ResponseComponents {
|
|
44
|
+
/** Replaces the whole code block — for a runnable snippet, or a diff viewer. */
|
|
45
|
+
code?: ComponentType<{
|
|
46
|
+
code: string;
|
|
47
|
+
language?: string;
|
|
48
|
+
streaming: boolean;
|
|
49
|
+
}>;
|
|
50
|
+
/** Replaces an image. Nothing is rendered for one by default. */
|
|
51
|
+
image?: ComponentType<{
|
|
52
|
+
src: string;
|
|
53
|
+
alt: string;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
export interface ResponseProps extends Omit<ViewProps, 'children'> {
|
|
57
|
+
className?: string;
|
|
58
|
+
/** The markdown. */
|
|
59
|
+
children?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Whether more is still coming. Finishes an unterminated construct at the end
|
|
62
|
+
* of the text instead of escaping it, so the answer does not flicker between
|
|
63
|
+
* styles as its delimiters arrive.
|
|
64
|
+
*/
|
|
65
|
+
isStreaming?: boolean;
|
|
66
|
+
/** Turns off speculative completion entirely, even while streaming. */
|
|
67
|
+
parseIncompleteMarkdown?: boolean;
|
|
68
|
+
/** What a link does. Opens it with the system handler by default. */
|
|
69
|
+
onLinkPress?: (href: string) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Schemes a link is allowed to open. A model can write any URL it likes, and
|
|
72
|
+
* an answer is not a trusted document — so the default list is the four that
|
|
73
|
+
* cannot do anything but navigate.
|
|
74
|
+
*/
|
|
75
|
+
allowedLinkPrefixes?: string[];
|
|
76
|
+
/** Swap out how a block is drawn. */
|
|
77
|
+
components?: ResponseComponents;
|
|
78
|
+
/** Line numbers in fenced code. */
|
|
79
|
+
showLineNumbers?: boolean;
|
|
80
|
+
}
|
|
81
|
+
declare function ResponseRoot({ className, children, isStreaming, parseIncompleteMarkdown, onLinkPress, allowedLinkPrefixes, components, showLineNumbers, ...props }: ResponseProps): import("react").JSX.Element;
|
|
82
|
+
/**
|
|
83
|
+
* Re-renders only when the text changes.
|
|
84
|
+
*
|
|
85
|
+
* A stream re-renders its parent on every token, and everything else the parent
|
|
86
|
+
* hands down — the callbacks, the overrides — is usually a fresh object each
|
|
87
|
+
* time. Comparing the one prop that actually decides the output keeps a long
|
|
88
|
+
* answer from re-parsing because a sibling moved.
|
|
89
|
+
*/
|
|
90
|
+
export declare const Response: import("react").MemoExoticComponent<typeof ResponseRoot>;
|
|
91
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/response/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,EAAiB,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAC1E,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAa7D,YAAY,EAAE,KAAK,IAAI,aAAa,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,eAAY,CAAC;AAQxF,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9E,iEAAiE;IACjE,KAAK,CAAC,EAAE,aAAa,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uEAAuE;IACvE,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qEAAqE;IACrE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,qCAAqC;IACrC,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,QAAa,EACb,WAAmB,EACnB,uBAA8B,EAC9B,WAAW,EACX,mBAA2C,EAC3C,UAAU,EACV,eAAuB,EACvB,GAAG,KAAK,EACT,EAAE,aAAa,+BAsBf;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,0DAMpB,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small Markdown reader, written for text that is still arriving.
|
|
3
|
+
*
|
|
4
|
+
* No parser library. What a chat answer actually contains is headings,
|
|
5
|
+
* paragraphs, lists, fenced code, blockquotes, tables, rules and a handful of
|
|
6
|
+
* inline marks — and every general-purpose parser worth using assumes it has
|
|
7
|
+
* been handed the whole document. That assumption is the one thing that is
|
|
8
|
+
* never true here.
|
|
9
|
+
*
|
|
10
|
+
* ## Half-arrived markdown
|
|
11
|
+
*
|
|
12
|
+
* A token stream shows you every prefix of the final text, so the reader sees
|
|
13
|
+
* `**bo`, then `**bol`, then `**bold**`. Treated naively that is three
|
|
14
|
+
* documents: two with literal asterisks in them and one with a bolded word. The
|
|
15
|
+
* text would flash between styles on nearly every frame, which is worse than no
|
|
16
|
+
* formatting at all — the eye tracks the flicker instead of the words.
|
|
17
|
+
*
|
|
18
|
+
* So an unterminated construct at the very end of the input is *completed
|
|
19
|
+
* speculatively* rather than escaped: an open fence becomes a code block that
|
|
20
|
+
* is still filling, an open `**` becomes bold text that is still being written.
|
|
21
|
+
* Anything unterminated anywhere else is literal, because a document that has
|
|
22
|
+
* stopped arriving means what it says.
|
|
23
|
+
*
|
|
24
|
+
* The two rules that follow from this:
|
|
25
|
+
*
|
|
26
|
+
* - **Only the tail is speculative.** An asterisk in the middle of a finished
|
|
27
|
+
* paragraph is an asterisk.
|
|
28
|
+
* - **A speculative construct never removes visible text.** The characters that
|
|
29
|
+
* opened it are hidden, and everything after them stays on screen. Otherwise
|
|
30
|
+
* the last word of the answer disappears and reappears as its delimiter
|
|
31
|
+
* arrives.
|
|
32
|
+
*/
|
|
33
|
+
export type Align = 'left' | 'center' | 'right';
|
|
34
|
+
export interface InlineToken {
|
|
35
|
+
kind: 'text' | 'code' | 'link' | 'image';
|
|
36
|
+
value: string;
|
|
37
|
+
/** For links and images. */
|
|
38
|
+
href?: string;
|
|
39
|
+
bold?: boolean;
|
|
40
|
+
italic?: boolean;
|
|
41
|
+
strike?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export type Block = {
|
|
44
|
+
type: 'heading';
|
|
45
|
+
level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
46
|
+
inline: InlineToken[];
|
|
47
|
+
} | {
|
|
48
|
+
type: 'paragraph';
|
|
49
|
+
inline: InlineToken[];
|
|
50
|
+
} | {
|
|
51
|
+
type: 'code';
|
|
52
|
+
code: string;
|
|
53
|
+
language?: string;
|
|
54
|
+
open: boolean;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'quote';
|
|
57
|
+
blocks: Block[];
|
|
58
|
+
} | {
|
|
59
|
+
type: 'list';
|
|
60
|
+
ordered: boolean;
|
|
61
|
+
start: number;
|
|
62
|
+
items: Block[][];
|
|
63
|
+
} | {
|
|
64
|
+
type: 'table';
|
|
65
|
+
head: InlineToken[][];
|
|
66
|
+
rows: InlineToken[][][];
|
|
67
|
+
align: (Align | null)[];
|
|
68
|
+
} | {
|
|
69
|
+
type: 'rule';
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Splits a document into blocks.
|
|
73
|
+
*
|
|
74
|
+
* `streaming` is what turns speculative completion on. With it off — a stored
|
|
75
|
+
* answer, a message that has finished — an unterminated fence is just a
|
|
76
|
+
* paragraph starting with three backticks, which is what it literally is.
|
|
77
|
+
*/
|
|
78
|
+
export declare function parseMarkdown(source: string, streaming?: boolean): Block[];
|
|
79
|
+
/**
|
|
80
|
+
* Splits a run of text into styled spans.
|
|
81
|
+
*
|
|
82
|
+
* `tail` says this run is the end of a stream, which is what licenses closing
|
|
83
|
+
* an open delimiter speculatively. It is deliberately narrow: only the *last*
|
|
84
|
+
* unterminated opener on the line is completed, and only when nothing after it
|
|
85
|
+
* could still turn out to be the closer.
|
|
86
|
+
*/
|
|
87
|
+
export declare function parseInline(source: string, tail: boolean): InlineToken[];
|
|
88
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../../src/components/response/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC;IAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAAC,KAAK,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAA;CAAE,GAC1F;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAUrB;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,KAAK,EAAE,CAGxE;AA0QD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CA+HxE"}
|
|
@@ -20,15 +20,27 @@
|
|
|
20
20
|
* <Select.Item value="eu" label="Europe" />
|
|
21
21
|
* </Select>
|
|
22
22
|
* ```
|
|
23
|
+
*
|
|
24
|
+
* Past a couple of dozen options, scrolling stops being a way of finding
|
|
25
|
+
* anything: pass `searchable` and the list gets a filter above it, matching on
|
|
26
|
+
* the option labels. The filter narrows what is *shown* — the declared options
|
|
27
|
+
* are still the source of truth, so nothing has to be lifted into state to make
|
|
28
|
+
* it work.
|
|
23
29
|
*/
|
|
24
30
|
import { type ReactNode } from 'react';
|
|
25
31
|
export type SelectPresentation = 'sheet' | 'inline' | 'overlay';
|
|
26
32
|
export interface SelectItemProps {
|
|
27
33
|
value: string;
|
|
28
34
|
label: string;
|
|
35
|
+
/**
|
|
36
|
+
* Shows the option but refuses it — a plan above the current tier, a region
|
|
37
|
+
* with nothing in stock. Kept in the list rather than dropped from it, because
|
|
38
|
+
* an option that vanishes reads as one that never existed.
|
|
39
|
+
*/
|
|
40
|
+
disabled?: boolean;
|
|
29
41
|
}
|
|
30
42
|
/** Declarative option. Rendered inside whichever surface is presenting. */
|
|
31
|
-
declare function SelectItem({ value, label }: SelectItemProps): import("react").JSX.Element;
|
|
43
|
+
declare function SelectItem({ value, label, disabled }: SelectItemProps): import("react").JSX.Element;
|
|
32
44
|
export interface SelectProps {
|
|
33
45
|
className?: string;
|
|
34
46
|
value?: string;
|
|
@@ -52,6 +64,19 @@ export interface SelectProps {
|
|
|
52
64
|
offset?: number;
|
|
53
65
|
/** Called when the options open or close. */
|
|
54
66
|
onOpenChange?: (open: boolean) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Put a filter above the options, matching case-insensitively on any part of
|
|
69
|
+
* an option's label. For a list long enough that scrolling it is not finding
|
|
70
|
+
* anything — countries, currencies, a repository's branches.
|
|
71
|
+
*
|
|
72
|
+
* The field is not focused on open: on a phone that would throw the keyboard
|
|
73
|
+
* over the very list you are trying to look at.
|
|
74
|
+
*/
|
|
75
|
+
searchable?: boolean;
|
|
76
|
+
/** Placeholder for the filter field. `searchable` only. */
|
|
77
|
+
searchPlaceholder?: string;
|
|
78
|
+
/** Shown in place of the list when the filter matches nothing. */
|
|
79
|
+
emptyMessage?: string;
|
|
55
80
|
/**
|
|
56
81
|
* Render the platform's own picker instead of the trigger-and-list pair.
|
|
57
82
|
* Requires the optional `@expo/ui` package; without it this prop does
|
|
@@ -69,7 +94,7 @@ export interface SelectProps {
|
|
|
69
94
|
nativeAppearance?: 'menu' | 'wheel';
|
|
70
95
|
children: ReactNode;
|
|
71
96
|
}
|
|
72
|
-
declare function SelectRoot({ className, value, onValueChange, placeholder, disabled, presentation, title, contentWidth, offset, onOpenChange, native, nativeAppearance, children, }: SelectProps): import("react").JSX.Element;
|
|
97
|
+
declare function SelectRoot({ className, value, onValueChange, placeholder, disabled, presentation, title, contentWidth, offset, onOpenChange, searchable, searchPlaceholder, emptyMessage, native, nativeAppearance, children, }: SelectProps): import("react").JSX.Element;
|
|
73
98
|
export declare const Select: typeof SelectRoot & {
|
|
74
99
|
Item: typeof SelectItem;
|
|
75
100
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/select/index.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/select/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA2Df,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAShE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,2EAA2E;AAC3E,iBAAS,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,eAAe,+BAgC9D;AAUD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC9C,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,KAAK,EACL,aAAa,EACb,WAAgC,EAChC,QAAQ,EACR,YAAsB,EACtB,KAAK,EACL,YAAwB,EACxB,MAAU,EACV,YAAY,EACZ,UAAkB,EAClB,iBAA4B,EAC5B,YAA2B,EAC3B,MAAM,EACN,gBAAyB,EACzB,QAAQ,GACT,EAAE,WAAW,+BA8Ub;AAED,eAAO,MAAM,MAAM;;CAEjB,CAAC"}
|