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.
- package/lib/module/components/card/index.js +1 -1
- package/lib/module/components/card/index.js.map +1 -1
- package/lib/module/components/planner/index.js +8 -1
- package/lib/module/components/planner/index.js.map +1 -1
- package/lib/module/components/sankey-chart/index.js +801 -165
- package/lib/module/components/sankey-chart/index.js.map +1 -1
- package/lib/module/components/sankey-chart/sankey-layout.js +226 -0
- package/lib/module/components/sankey-chart/sankey-layout.js.map +1 -1
- package/lib/module/components/spinner/index.js +13 -3
- package/lib/module/components/spinner/index.js.map +1 -1
- package/lib/module/components/support/index.js +842 -0
- package/lib/module/components/support/index.js.map +1 -0
- package/lib/module/components/typography/index.js +10 -2
- package/lib/module/components/typography/index.js.map +1 -1
- package/lib/module/icons/index.js +40 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/chart.js +24 -0
- package/lib/module/utils/chart.js.map +1 -1
- package/lib/typescript/src/components/planner/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sankey-chart/index.d.ts +131 -5
- package/lib/typescript/src/components/sankey-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sankey-chart/sankey-layout.d.ts +49 -6
- package/lib/typescript/src/components/sankey-chart/sankey-layout.d.ts.map +1 -1
- package/lib/typescript/src/components/spinner/index.d.ts +18 -1
- package/lib/typescript/src/components/spinner/index.d.ts.map +1 -1
- package/lib/typescript/src/components/support/index.d.ts +376 -0
- package/lib/typescript/src/components/support/index.d.ts.map +1 -0
- package/lib/typescript/src/components/typography/index.d.ts +0 -3
- package/lib/typescript/src/components/typography/index.d.ts.map +1 -1
- package/lib/typescript/src/icons/index.d.ts +8 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/chart.d.ts +11 -0
- package/lib/typescript/src/utils/chart.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/card/index.tsx +1 -1
- package/src/components/planner/index.tsx +8 -1
- package/src/components/sankey-chart/index.tsx +935 -172
- package/src/components/sankey-chart/sankey-layout.ts +276 -2
- package/src/components/spinner/index.tsx +27 -1
- package/src/components/support/index.tsx +877 -0
- package/src/components/typography/index.tsx +10 -2
- package/src/icons/index.tsx +16 -0
- package/src/index.ts +35 -0
- 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
|