panelui-native 0.101.0 → 0.102.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.
Files changed (48) hide show
  1. package/lib/module/components/card/index.js +1 -1
  2. package/lib/module/components/card/index.js.map +1 -1
  3. package/lib/module/components/planner/index.js +8 -1
  4. package/lib/module/components/planner/index.js.map +1 -1
  5. package/lib/module/components/sankey-chart/index.js +801 -165
  6. package/lib/module/components/sankey-chart/index.js.map +1 -1
  7. package/lib/module/components/sankey-chart/sankey-layout.js +226 -0
  8. package/lib/module/components/sankey-chart/sankey-layout.js.map +1 -1
  9. package/lib/module/components/spinner/index.js +13 -3
  10. package/lib/module/components/spinner/index.js.map +1 -1
  11. package/lib/module/components/support/index.js +842 -0
  12. package/lib/module/components/support/index.js.map +1 -0
  13. package/lib/module/components/typography/index.js +10 -2
  14. package/lib/module/components/typography/index.js.map +1 -1
  15. package/lib/module/icons/index.js +40 -0
  16. package/lib/module/icons/index.js.map +1 -1
  17. package/lib/module/index.js +2 -1
  18. package/lib/module/index.js.map +1 -1
  19. package/lib/module/utils/chart.js +24 -0
  20. package/lib/module/utils/chart.js.map +1 -1
  21. package/lib/typescript/src/components/planner/index.d.ts.map +1 -1
  22. package/lib/typescript/src/components/sankey-chart/index.d.ts +131 -5
  23. package/lib/typescript/src/components/sankey-chart/index.d.ts.map +1 -1
  24. package/lib/typescript/src/components/sankey-chart/sankey-layout.d.ts +49 -6
  25. package/lib/typescript/src/components/sankey-chart/sankey-layout.d.ts.map +1 -1
  26. package/lib/typescript/src/components/spinner/index.d.ts +18 -1
  27. package/lib/typescript/src/components/spinner/index.d.ts.map +1 -1
  28. package/lib/typescript/src/components/support/index.d.ts +376 -0
  29. package/lib/typescript/src/components/support/index.d.ts.map +1 -0
  30. package/lib/typescript/src/components/typography/index.d.ts +0 -3
  31. package/lib/typescript/src/components/typography/index.d.ts.map +1 -1
  32. package/lib/typescript/src/icons/index.d.ts +8 -0
  33. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  34. package/lib/typescript/src/index.d.ts +3 -2
  35. package/lib/typescript/src/index.d.ts.map +1 -1
  36. package/lib/typescript/src/utils/chart.d.ts +11 -0
  37. package/lib/typescript/src/utils/chart.d.ts.map +1 -1
  38. package/package.json +1 -1
  39. package/src/components/card/index.tsx +1 -1
  40. package/src/components/planner/index.tsx +8 -1
  41. package/src/components/sankey-chart/index.tsx +935 -172
  42. package/src/components/sankey-chart/sankey-layout.ts +276 -2
  43. package/src/components/spinner/index.tsx +27 -1
  44. package/src/components/support/index.tsx +877 -0
  45. package/src/components/typography/index.tsx +10 -2
  46. package/src/icons/index.tsx +16 -0
  47. package/src/index.ts +35 -0
  48. package/src/utils/chart.ts +40 -0
@@ -0,0 +1,842 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Support — the screen a person arrives on when they need help.
5
+ *
6
+ * It is the front of a support section, not the conversation itself. What a
7
+ * reader needs here is four answers, in this order: is anyone there, how do I
8
+ * reach them, what is this about, and what happened to the thing I already
9
+ * asked. Each is a part, because an app that has no help centre should not
10
+ * have to pass `articles={null}` to say so.
11
+ *
12
+ * The transcript is deliberately somewhere else. A support thread is a chat
13
+ * transcript with a name on it, and this library already has the pieces —
14
+ * compose `MessageScroller`, `Message` and `AIInput` behind whichever channel
15
+ * the reader picks, rather than growing a second set of bubbles in here that
16
+ * would drift away from the first.
17
+ *
18
+ * `availability` is the one thing the root decides, and everything downstream
19
+ * reads it from context: the dot beside the status line, the wording it falls
20
+ * back to, and whether a channel that needs someone at the other end presents
21
+ * itself as open.
22
+ *
23
+ * ```tsx
24
+ * <Support availability="online">
25
+ * <Support.Header title="Support" />
26
+ * <Support.Status replyTime="Typically replies in under an hour" />
27
+ * <Support.Channels>
28
+ * <Support.Channel icon={<MessageCircleIcon />} label="Message us" />
29
+ * </Support.Channels>
30
+ * </Support>
31
+ * ```
32
+ */
33
+ import { createContext, forwardRef, useContext, useMemo, useState } from 'react';
34
+ import { View } from 'react-native';
35
+ import { tv } from 'tailwind-variants';
36
+ import { AnimatedPressable } from "../../primitives/animated-pressable.js";
37
+ import { Text, textChildren } from "../../primitives/text.js";
38
+ import { cn } from "../../utils/cn.js";
39
+
40
+ /** Whether anyone is at the other end. */
41
+
42
+ /**
43
+ * Where a request has got to, in the words the person who made it sees.
44
+ *
45
+ * Shorter than the set a support desk runs internally, and deliberately: the
46
+ * states a helpdesk distinguishes for its own routing are not distinctions the
47
+ * person waiting can act on, and offering them invites a question about the
48
+ * difference that nobody wants to answer.
49
+ */
50
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
51
+ const supportVariants = tv({
52
+ slots: {
53
+ root: 'w-full gap-5',
54
+ header: 'w-full flex-row items-center justify-between gap-3',
55
+ headerText: 'shrink gap-0.5',
56
+ status: 'w-full flex-row items-center gap-2 rounded-xl bg-muted px-3 py-2.5',
57
+ statusDot: 'size-2 rounded-full',
58
+ group: 'w-full gap-2',
59
+ groupTitle: 'text-xs font-medium text-muted-foreground',
60
+ channel: 'w-full flex-row items-center gap-3 rounded-xl border border-border bg-card px-3.5 py-3',
61
+ channelIcon: 'size-9 items-center justify-center rounded-lg bg-muted',
62
+ channelText: 'shrink grow gap-0.5',
63
+ topic: 'w-full flex-row items-center gap-3 rounded-xl border px-3.5 py-3',
64
+ topicText: 'shrink grow gap-0.5',
65
+ conversation: 'w-full flex-row items-start gap-3 rounded-xl border border-border bg-card px-3.5 py-3',
66
+ article: 'w-full flex-row items-center gap-3 rounded-xl bg-muted px-3.5 py-3',
67
+ badge: 'rounded-full px-2 py-0.5',
68
+ agent: 'w-full flex-row items-center gap-3',
69
+ ticket: 'w-full flex-row items-center justify-between gap-2 rounded-lg bg-muted px-3 py-2',
70
+ note: 'w-full text-center',
71
+ handoff: 'w-full flex-row items-center gap-2 rounded-xl bg-muted px-3 py-2.5',
72
+ replies: 'w-full flex-row flex-wrap items-center gap-2',
73
+ reply: 'rounded-full border border-border bg-card px-3 py-1.5',
74
+ resolution: 'w-full items-center gap-2 rounded-xl border border-border bg-card px-3.5 py-3.5'
75
+ },
76
+ variants: {
77
+ availability: {
78
+ online: {
79
+ statusDot: 'bg-success'
80
+ },
81
+ away: {
82
+ statusDot: 'bg-warning'
83
+ },
84
+ offline: {
85
+ statusDot: 'bg-muted-foreground'
86
+ }
87
+ },
88
+ selected: {
89
+ true: {
90
+ topic: 'border-primary bg-primary/10'
91
+ },
92
+ false: {
93
+ topic: 'border-border bg-card'
94
+ }
95
+ },
96
+ disabled: {
97
+ true: {
98
+ channel: 'opacity-50',
99
+ topic: 'opacity-50'
100
+ }
101
+ }
102
+ },
103
+ defaultVariants: {
104
+ availability: 'online',
105
+ selected: false
106
+ }
107
+ });
108
+
109
+ /** What a status badge says and how it is coloured, per state. */
110
+ const STATUS_STYLE = {
111
+ open: {
112
+ label: 'Open',
113
+ className: 'bg-info/15',
114
+ textClassName: 'text-info'
115
+ },
116
+ pending: {
117
+ label: 'Waiting on you',
118
+ className: 'bg-warning/15',
119
+ textClassName: 'text-warning'
120
+ },
121
+ solved: {
122
+ label: 'Solved',
123
+ className: 'bg-success/15',
124
+ textClassName: 'text-success'
125
+ },
126
+ closed: {
127
+ label: 'Closed',
128
+ className: 'bg-muted',
129
+ textClassName: 'text-muted-foreground'
130
+ }
131
+ };
132
+ const SupportContext = /*#__PURE__*/createContext({
133
+ availability: 'online'
134
+ });
135
+
136
+ /** The availability set by the nearest Support. */
137
+ export function useSupport() {
138
+ return useContext(SupportContext);
139
+ }
140
+ const TopicsContext = /*#__PURE__*/createContext(null);
141
+ const SupportRoot = /*#__PURE__*/forwardRef(function SupportRoot({
142
+ className,
143
+ availability = 'online',
144
+ children,
145
+ ...props
146
+ }, ref) {
147
+ const {
148
+ root
149
+ } = supportVariants();
150
+ const context = useMemo(() => ({
151
+ availability
152
+ }), [availability]);
153
+ return /*#__PURE__*/_jsx(SupportContext.Provider, {
154
+ value: context,
155
+ children: /*#__PURE__*/_jsx(View, {
156
+ ref: ref,
157
+ className: root({
158
+ className
159
+ }),
160
+ ...props,
161
+ children: textChildren(children)
162
+ })
163
+ });
164
+ });
165
+ SupportRoot.displayName = 'Support';
166
+ /** The screen's title, and room beside it for whoever is answering. */
167
+ const SupportHeader = /*#__PURE__*/forwardRef(function SupportHeader({
168
+ className,
169
+ title,
170
+ description,
171
+ children,
172
+ ...props
173
+ }, ref) {
174
+ const {
175
+ header,
176
+ headerText
177
+ } = supportVariants();
178
+ return /*#__PURE__*/_jsxs(View, {
179
+ ref: ref,
180
+ className: header({
181
+ className
182
+ }),
183
+ ...props,
184
+ children: [/*#__PURE__*/_jsxs(View, {
185
+ className: headerText(),
186
+ children: [title ? /*#__PURE__*/_jsx(Text, {
187
+ size: "xl",
188
+ weight: "bold",
189
+ numberOfLines: 1,
190
+ children: title
191
+ }) : null, description ? /*#__PURE__*/_jsx(Text, {
192
+ size: "sm",
193
+ muted: true,
194
+ numberOfLines: 2,
195
+ children: description
196
+ }) : null]
197
+ }), children ? /*#__PURE__*/_jsx(View, {
198
+ className: "shrink-0",
199
+ children: textChildren(children)
200
+ }) : null]
201
+ });
202
+ });
203
+ SupportHeader.displayName = 'Support.Header';
204
+ /** Whether anyone is there, and how long an answer takes. */
205
+ const SupportStatus = /*#__PURE__*/forwardRef(function SupportStatus({
206
+ className,
207
+ availability: availabilityProp,
208
+ replyTime,
209
+ children,
210
+ ...props
211
+ }, ref) {
212
+ const {
213
+ availability: inherited
214
+ } = useSupport();
215
+ const availability = availabilityProp ?? inherited;
216
+ const {
217
+ status,
218
+ statusDot
219
+ } = supportVariants({
220
+ availability
221
+ });
222
+ const fallback = availability === 'online' ? 'Someone is here now' : availability === 'away' ? 'Away at the moment' : 'Nobody is here right now';
223
+ return /*#__PURE__*/_jsxs(View, {
224
+ ref: ref,
225
+ className: status({
226
+ className
227
+ }),
228
+ ...props,
229
+ children: [/*#__PURE__*/_jsx(View, {
230
+ className: statusDot()
231
+ }), children ? textChildren(children) : /*#__PURE__*/_jsx(Text, {
232
+ size: "sm",
233
+ numberOfLines: 2,
234
+ className: "shrink",
235
+ children: replyTime ?? fallback
236
+ })]
237
+ });
238
+ });
239
+ SupportStatus.displayName = 'Support.Status';
240
+ /** A titled run of rows. Shared by Channels, Conversations and Articles. */
241
+ function group(name) {
242
+ const Group = /*#__PURE__*/forwardRef(function Group({
243
+ className,
244
+ title,
245
+ children,
246
+ ...props
247
+ }, ref) {
248
+ const {
249
+ group: groupClass,
250
+ groupTitle
251
+ } = supportVariants();
252
+ return /*#__PURE__*/_jsxs(View, {
253
+ ref: ref,
254
+ className: groupClass({
255
+ className
256
+ }),
257
+ ...props,
258
+ children: [title ? /*#__PURE__*/_jsx(Text, {
259
+ className: groupTitle(),
260
+ children: title
261
+ }) : null, textChildren(children)]
262
+ });
263
+ });
264
+ Group.displayName = name;
265
+ return Group;
266
+ }
267
+ const SupportChannels = group('Support.Channels');
268
+ const SupportConversations = group('Support.Conversations');
269
+ const SupportArticles = group('Support.Articles');
270
+ /**
271
+ * One way of reaching somebody.
272
+ *
273
+ * A row rather than a tile. Each channel is a sentence — what it is, and what
274
+ * it costs you in waiting — and a grid of icons with one word under each puts
275
+ * the reader in front of a quiz about which one is right.
276
+ */
277
+ const SupportChannel = /*#__PURE__*/forwardRef(function SupportChannel({
278
+ className,
279
+ icon,
280
+ label,
281
+ description,
282
+ detail,
283
+ disabled = false,
284
+ onPress,
285
+ ...props
286
+ }, ref) {
287
+ const {
288
+ channel,
289
+ channelIcon,
290
+ channelText
291
+ } = supportVariants({
292
+ disabled
293
+ });
294
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
295
+ ref: ref,
296
+ accessibilityRole: "button",
297
+ accessibilityState: {
298
+ disabled
299
+ },
300
+ accessibilityLabel: detail ? `${label}, ${detail}` : label,
301
+ accessibilityHint: description,
302
+ disabled: disabled || !onPress,
303
+ onPress: onPress,
304
+ className: channel({
305
+ className
306
+ }),
307
+ ...props,
308
+ children: [icon ? /*#__PURE__*/_jsx(View, {
309
+ className: channelIcon(),
310
+ children: icon
311
+ }) : null, /*#__PURE__*/_jsxs(View, {
312
+ className: channelText(),
313
+ children: [/*#__PURE__*/_jsx(Text, {
314
+ size: "sm",
315
+ weight: "medium",
316
+ numberOfLines: 1,
317
+ children: label
318
+ }), description ? /*#__PURE__*/_jsx(Text, {
319
+ size: "xs",
320
+ muted: true,
321
+ numberOfLines: 2,
322
+ children: description
323
+ }) : null]
324
+ }), detail ? /*#__PURE__*/_jsx(Text, {
325
+ size: "xs",
326
+ muted: true,
327
+ numberOfLines: 1,
328
+ className: "shrink-0",
329
+ children: detail
330
+ }) : null]
331
+ });
332
+ });
333
+ SupportChannel.displayName = 'Support.Channel';
334
+ /**
335
+ * What the problem is about, as a list of one-line choices.
336
+ *
337
+ * Optional, and meant to stay that way — plenty of support screens are better
338
+ * without one, and the ones that need it are the ones routing to different
339
+ * teams. Single-select: a request goes to one queue.
340
+ */
341
+ const SupportTopics = /*#__PURE__*/forwardRef(function SupportTopics({
342
+ className,
343
+ title,
344
+ value: valueProp,
345
+ defaultValue = null,
346
+ onValueChange,
347
+ children,
348
+ ...props
349
+ }, ref) {
350
+ const {
351
+ group: groupClass,
352
+ groupTitle
353
+ } = supportVariants();
354
+ const [internal, setInternal] = useState(defaultValue);
355
+ const controlled = valueProp !== undefined;
356
+ const value = controlled ? valueProp : internal;
357
+ const context = useMemo(() => ({
358
+ value: value ?? null,
359
+ select: next => {
360
+ if (!controlled) setInternal(next);
361
+ onValueChange?.(next);
362
+ }
363
+ }), [value, controlled, onValueChange]);
364
+ return /*#__PURE__*/_jsx(TopicsContext.Provider, {
365
+ value: context,
366
+ children: /*#__PURE__*/_jsxs(View, {
367
+ ref: ref,
368
+ accessibilityRole: "radiogroup",
369
+ className: groupClass({
370
+ className
371
+ }),
372
+ ...props,
373
+ children: [title ? /*#__PURE__*/_jsx(Text, {
374
+ className: groupTitle(),
375
+ children: title
376
+ }) : null, textChildren(children)]
377
+ })
378
+ });
379
+ });
380
+ SupportTopics.displayName = 'Support.Topics';
381
+ /** One thing the problem could be about. */
382
+ const SupportTopic = /*#__PURE__*/forwardRef(function SupportTopic({
383
+ className,
384
+ value,
385
+ icon,
386
+ label,
387
+ description,
388
+ disabled = false,
389
+ onPress,
390
+ ...props
391
+ }, ref) {
392
+ const group = useContext(TopicsContext);
393
+ const selected = group?.value === value;
394
+ const {
395
+ topic,
396
+ topicText,
397
+ channelIcon
398
+ } = supportVariants({
399
+ selected,
400
+ disabled
401
+ });
402
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
403
+ ref: ref,
404
+ accessibilityRole: "radio",
405
+ accessibilityState: {
406
+ selected,
407
+ disabled
408
+ },
409
+ accessibilityLabel: label,
410
+ accessibilityHint: description,
411
+ disabled: disabled,
412
+ onPress: () => {
413
+ group?.select(value);
414
+ onPress?.();
415
+ },
416
+ className: topic({
417
+ className
418
+ }),
419
+ ...props,
420
+ children: [icon ? /*#__PURE__*/_jsx(View, {
421
+ className: channelIcon(),
422
+ children: icon
423
+ }) : null, /*#__PURE__*/_jsxs(View, {
424
+ className: topicText(),
425
+ children: [/*#__PURE__*/_jsx(Text, {
426
+ size: "sm",
427
+ weight: "medium",
428
+ numberOfLines: 1,
429
+ children: label
430
+ }), description ? /*#__PURE__*/_jsx(Text, {
431
+ size: "xs",
432
+ muted: true,
433
+ numberOfLines: 2,
434
+ children: description
435
+ }) : null]
436
+ })]
437
+ });
438
+ });
439
+ SupportTopic.displayName = 'Support.Topic';
440
+ /** One request the reader already made, and what has happened to it. */
441
+ const SupportConversation = /*#__PURE__*/forwardRef(function SupportConversation({
442
+ className,
443
+ title,
444
+ preview,
445
+ status = 'open',
446
+ timestamp,
447
+ unread = false,
448
+ updated = false,
449
+ reference,
450
+ onPress,
451
+ ...props
452
+ }, ref) {
453
+ const {
454
+ conversation,
455
+ badge
456
+ } = supportVariants();
457
+ const tone = STATUS_STYLE[status];
458
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
459
+ ref: ref,
460
+ accessibilityRole: "button",
461
+ accessibilityLabel: [title, tone.label, unread ? 'unread' : updated ? 'updated' : null, timestamp].filter(Boolean).join(', '),
462
+ disabled: !onPress,
463
+ onPress: onPress,
464
+ className: conversation({
465
+ className
466
+ }),
467
+ ...props,
468
+ children: [unread || updated ? /*#__PURE__*/_jsx(View, {
469
+ className: cn('mt-1.5 size-2 shrink-0 rounded-full', unread ? 'bg-primary' : 'bg-muted-foreground')
470
+ }) : null, /*#__PURE__*/_jsxs(View, {
471
+ className: "shrink grow gap-1",
472
+ children: [/*#__PURE__*/_jsxs(View, {
473
+ className: "flex-row items-baseline gap-2",
474
+ children: [/*#__PURE__*/_jsx(Text, {
475
+ size: "sm",
476
+ weight: unread ? 'semibold' : 'medium',
477
+ numberOfLines: 1,
478
+ className: "shrink grow",
479
+ children: title
480
+ }), timestamp ? /*#__PURE__*/_jsx(Text, {
481
+ size: "xs",
482
+ muted: true,
483
+ numberOfLines: 1,
484
+ className: "shrink-0",
485
+ children: timestamp
486
+ }) : null]
487
+ }), preview ? /*#__PURE__*/_jsx(Text, {
488
+ size: "xs",
489
+ muted: true,
490
+ numberOfLines: 2,
491
+ children: preview
492
+ }) : null, /*#__PURE__*/_jsxs(View, {
493
+ className: "flex-row items-center gap-2 pt-0.5",
494
+ children: [/*#__PURE__*/_jsx(View, {
495
+ className: badge({
496
+ className: tone.className
497
+ }),
498
+ children: /*#__PURE__*/_jsx(Text, {
499
+ size: "xs",
500
+ weight: "medium",
501
+ className: tone.textClassName,
502
+ children: tone.label
503
+ })
504
+ }), reference ? /*#__PURE__*/_jsx(Text, {
505
+ size: "xs",
506
+ muted: true,
507
+ numberOfLines: 1,
508
+ children: reference
509
+ }) : null]
510
+ })]
511
+ })]
512
+ });
513
+ });
514
+ SupportConversation.displayName = 'Support.Conversation';
515
+ /** A page from the help centre, for the questions that have a written answer. */
516
+ const SupportArticle = /*#__PURE__*/forwardRef(function SupportArticle({
517
+ className,
518
+ icon,
519
+ title,
520
+ collection,
521
+ onPress,
522
+ ...props
523
+ }, ref) {
524
+ const {
525
+ article,
526
+ channelText
527
+ } = supportVariants();
528
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
529
+ ref: ref,
530
+ accessibilityRole: "link",
531
+ accessibilityLabel: collection ? `${title}, in ${collection}` : title,
532
+ disabled: !onPress,
533
+ onPress: onPress,
534
+ className: article({
535
+ className
536
+ }),
537
+ ...props,
538
+ children: [icon ? /*#__PURE__*/_jsx(View, {
539
+ className: "shrink-0",
540
+ children: icon
541
+ }) : null, /*#__PURE__*/_jsxs(View, {
542
+ className: channelText(),
543
+ children: [/*#__PURE__*/_jsx(Text, {
544
+ size: "sm",
545
+ numberOfLines: 2,
546
+ children: title
547
+ }), collection ? /*#__PURE__*/_jsx(Text, {
548
+ size: "xs",
549
+ muted: true,
550
+ numberOfLines: 1,
551
+ children: collection
552
+ }) : null]
553
+ })]
554
+ });
555
+ });
556
+ SupportArticle.displayName = 'Support.Article';
557
+
558
+ // `role` here is the person's job, not the accessibility role — the component
559
+ // sets that itself, so the prop it would collide with is taken off.
560
+
561
+ /**
562
+ * Who the reader is talking to, above the transcript.
563
+ *
564
+ * A support thread is the one conversation where the other end is a stranger,
565
+ * and "someone from Billing, who is here now" is a different thing to talk to
566
+ * than an unattributed queue. `typing` replaces the status line rather than
567
+ * sitting beside it, because the two answer the same question and the live one
568
+ * wins.
569
+ */
570
+ const SupportAgent = /*#__PURE__*/forwardRef(function SupportAgent({
571
+ className,
572
+ avatar,
573
+ name,
574
+ role,
575
+ availability: availabilityProp,
576
+ typing = false,
577
+ ...props
578
+ }, ref) {
579
+ const {
580
+ availability: inherited
581
+ } = useSupport();
582
+ const availability = availabilityProp ?? inherited;
583
+ const {
584
+ agent,
585
+ statusDot
586
+ } = supportVariants({
587
+ availability
588
+ });
589
+ const state = availability === 'online' ? 'Online' : availability === 'away' ? 'Away' : 'Offline';
590
+ return /*#__PURE__*/_jsxs(View, {
591
+ ref: ref,
592
+ accessibilityRole: "header",
593
+ accessibilityLabel: `${name}${role ? `, ${role}` : ''}, ${typing ? 'typing' : state}`,
594
+ className: agent({
595
+ className
596
+ }),
597
+ ...props,
598
+ children: [avatar ? /*#__PURE__*/_jsx(View, {
599
+ className: "shrink-0",
600
+ children: avatar
601
+ }) : null, /*#__PURE__*/_jsxs(View, {
602
+ className: "shrink grow gap-0.5",
603
+ children: [/*#__PURE__*/_jsx(Text, {
604
+ size: "sm",
605
+ weight: "semibold",
606
+ numberOfLines: 1,
607
+ children: name
608
+ }), /*#__PURE__*/_jsxs(View, {
609
+ className: "flex-row items-center gap-1.5",
610
+ children: [typing ? null : /*#__PURE__*/_jsx(View, {
611
+ className: statusDot()
612
+ }), /*#__PURE__*/_jsx(Text, {
613
+ size: "xs",
614
+ muted: true,
615
+ numberOfLines: 1,
616
+ children: typing ? 'Typing…' : role ? `${role} · ${state}` : state
617
+ })]
618
+ })]
619
+ })]
620
+ });
621
+ });
622
+ SupportAgent.displayName = 'Support.Agent';
623
+ /** The request this thread belongs to, pinned above it. */
624
+ const SupportTicket = /*#__PURE__*/forwardRef(function SupportTicket({
625
+ className,
626
+ reference,
627
+ subject,
628
+ status = 'open',
629
+ ...props
630
+ }, ref) {
631
+ const {
632
+ ticket,
633
+ badge
634
+ } = supportVariants();
635
+ const tone = STATUS_STYLE[status];
636
+ return /*#__PURE__*/_jsxs(View, {
637
+ ref: ref,
638
+ accessibilityLabel: [subject, reference, tone.label].filter(Boolean).join(', '),
639
+ className: ticket({
640
+ className
641
+ }),
642
+ ...props,
643
+ children: [/*#__PURE__*/_jsxs(View, {
644
+ className: "shrink grow gap-0.5",
645
+ children: [subject ? /*#__PURE__*/_jsx(Text, {
646
+ size: "xs",
647
+ weight: "medium",
648
+ numberOfLines: 1,
649
+ children: subject
650
+ }) : null, reference ? /*#__PURE__*/_jsx(Text, {
651
+ size: "xs",
652
+ muted: true,
653
+ numberOfLines: 1,
654
+ children: reference
655
+ }) : null]
656
+ }), /*#__PURE__*/_jsx(View, {
657
+ className: badge({
658
+ className: tone.className
659
+ }),
660
+ children: /*#__PURE__*/_jsx(Text, {
661
+ size: "xs",
662
+ weight: "medium",
663
+ className: tone.textClassName,
664
+ children: tone.label
665
+ })
666
+ })]
667
+ });
668
+ });
669
+ SupportTicket.displayName = 'Support.Ticket';
670
+ /**
671
+ * The moment the thread changes hands.
672
+ *
673
+ * Between two turns rather than inside either, because it is not something
674
+ * anybody said — an assistant's answer followed by a person's, with nothing
675
+ * between them, leaves the reader working out who they are talking to from the
676
+ * writing style.
677
+ */
678
+ const SupportHandoff = /*#__PURE__*/forwardRef(function SupportHandoff({
679
+ className,
680
+ icon,
681
+ children,
682
+ ...props
683
+ }, ref) {
684
+ const {
685
+ handoff
686
+ } = supportVariants();
687
+ return /*#__PURE__*/_jsxs(View, {
688
+ ref: ref,
689
+ accessibilityRole: "alert",
690
+ className: handoff({
691
+ className
692
+ }),
693
+ ...props,
694
+ children: [icon ? /*#__PURE__*/_jsx(View, {
695
+ className: "shrink-0",
696
+ children: icon
697
+ }) : null, /*#__PURE__*/_jsx(Text, {
698
+ size: "xs",
699
+ muted: true,
700
+ className: "shrink",
701
+ children: children
702
+ })]
703
+ });
704
+ });
705
+ SupportHandoff.displayName = 'Support.Handoff';
706
+ /**
707
+ * One quiet line above the composer — what the wait is, or when they are back.
708
+ *
709
+ * It belongs here rather than at the top of the screen because this is where
710
+ * somebody is deciding whether it is worth typing, and an expectation set four
711
+ * screens ago is not one they still have in mind.
712
+ */
713
+ const SupportNote = /*#__PURE__*/forwardRef(function SupportNote({
714
+ className,
715
+ children,
716
+ ...props
717
+ }, ref) {
718
+ const {
719
+ note
720
+ } = supportVariants();
721
+ return /*#__PURE__*/_jsx(View, {
722
+ ref: ref,
723
+ className: "w-full",
724
+ ...props,
725
+ children: /*#__PURE__*/_jsx(Text, {
726
+ size: "xs",
727
+ muted: true,
728
+ className: note({
729
+ className
730
+ }),
731
+ children: children
732
+ })
733
+ });
734
+ });
735
+ SupportNote.displayName = 'Support.Note';
736
+ /** The suggested answers under a turn. */
737
+ const SupportReplies = /*#__PURE__*/forwardRef(function SupportReplies({
738
+ className,
739
+ children,
740
+ ...props
741
+ }, ref) {
742
+ const {
743
+ replies
744
+ } = supportVariants();
745
+ return /*#__PURE__*/_jsx(View, {
746
+ ref: ref,
747
+ className: replies({
748
+ className
749
+ }),
750
+ ...props,
751
+ children: textChildren(children)
752
+ });
753
+ });
754
+ SupportReplies.displayName = 'Support.Replies';
755
+ /**
756
+ * One suggested answer.
757
+ *
758
+ * Worth having as a part rather than leaving to a row of buttons because of
759
+ * what goes in it: the way out to a person is the reply that has to be on the
760
+ * screen from the first turn, and a component that makes it easy to put there
761
+ * is a component that gets it put there.
762
+ */
763
+ const SupportReply = /*#__PURE__*/forwardRef(function SupportReply({
764
+ className,
765
+ value,
766
+ label,
767
+ disabled = false,
768
+ onPress,
769
+ ...props
770
+ }, ref) {
771
+ const {
772
+ reply
773
+ } = supportVariants();
774
+ return /*#__PURE__*/_jsx(AnimatedPressable, {
775
+ ref: ref,
776
+ accessibilityRole: "button",
777
+ accessibilityState: {
778
+ disabled
779
+ },
780
+ accessibilityLabel: label,
781
+ disabled: disabled,
782
+ onPress: () => onPress?.(value ?? label),
783
+ className: reply({
784
+ className
785
+ }),
786
+ ...props,
787
+ children: /*#__PURE__*/_jsx(Text, {
788
+ size: "xs",
789
+ weight: "medium",
790
+ numberOfLines: 1,
791
+ children: label
792
+ })
793
+ });
794
+ });
795
+ SupportReply.displayName = 'Support.Reply';
796
+ /** Whether it actually helped, asked at the end of a thread. */
797
+ const SupportResolution = /*#__PURE__*/forwardRef(function SupportResolution({
798
+ className,
799
+ title = 'Did this solve it?',
800
+ children,
801
+ ...props
802
+ }, ref) {
803
+ const {
804
+ resolution
805
+ } = supportVariants();
806
+ return /*#__PURE__*/_jsxs(View, {
807
+ ref: ref,
808
+ className: resolution({
809
+ className
810
+ }),
811
+ ...props,
812
+ children: [/*#__PURE__*/_jsx(Text, {
813
+ size: "sm",
814
+ weight: "medium",
815
+ children: title
816
+ }), children ? /*#__PURE__*/_jsx(View, {
817
+ className: "w-full items-center",
818
+ children: textChildren(children)
819
+ }) : null]
820
+ });
821
+ });
822
+ SupportResolution.displayName = 'Support.Resolution';
823
+ export const Support = Object.assign(SupportRoot, {
824
+ Header: SupportHeader,
825
+ Status: SupportStatus,
826
+ Channels: SupportChannels,
827
+ Channel: SupportChannel,
828
+ Topics: SupportTopics,
829
+ Topic: SupportTopic,
830
+ Conversations: SupportConversations,
831
+ Conversation: SupportConversation,
832
+ Articles: SupportArticles,
833
+ Article: SupportArticle,
834
+ Agent: SupportAgent,
835
+ Ticket: SupportTicket,
836
+ Handoff: SupportHandoff,
837
+ Note: SupportNote,
838
+ Replies: SupportReplies,
839
+ Reply: SupportReply,
840
+ Resolution: SupportResolution
841
+ });
842
+ //# sourceMappingURL=index.js.map