@mediansh/widget 0.6.0 → 0.8.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 +52 -3
- package/dist/{chunk-3KEM4W7J.js → chunk-3ZXE5RBN.js} +2 -2
- package/dist/chunk-77KIJLPP.js +43 -0
- package/dist/{chunk-W6NPKKCE.js → chunk-HLALDSPM.js} +1 -39
- package/dist/{chunk-W6NPKKCE.js.map → chunk-HLALDSPM.js.map} +1 -1
- package/dist/{chunk-DVQ7V3LR.js → chunk-R3S6Y434.js} +9 -7
- package/dist/{chunk-DVQ7V3LR.js.map → chunk-R3S6Y434.js.map} +1 -1
- package/dist/dist-VC6ZVTA2.js +1658 -0
- package/dist/dist-VC6ZVTA2.js.map +1 -0
- package/dist/{highlighted-body-OFNGDK62-DW3EMPTG.js → highlighted-body-OFNGDK62-T25BCWKJ.js} +4 -3
- package/dist/highlighted-body-OFNGDK62-T25BCWKJ.js.map +1 -0
- package/dist/index.d.ts +407 -21
- package/dist/index.js +3387 -1510
- package/dist/index.js.map +1 -1
- package/dist/mermaid-GHXKKRXX-U6EYEPWB.js +11 -0
- package/dist/mermaid-GHXKKRXX-U6EYEPWB.js.map +1 -0
- package/dist/{message-markdown-LOE74LBE.js → message-markdown-KQVNAD42.js} +5 -4
- package/dist/{message-markdown-LOE74LBE.js.map → message-markdown-KQVNAD42.js.map} +1 -1
- package/dist/widget.css +1 -1
- package/package.json +20 -5
- package/dist/highlighted-body-OFNGDK62-DW3EMPTG.js.map +0 -1
- package/dist/mermaid-GHXKKRXX-N3BSVIR6.js +0 -10
- /package/dist/{chunk-3KEM4W7J.js.map → chunk-3ZXE5RBN.js.map} +0 -0
- /package/dist/{mermaid-GHXKKRXX-N3BSVIR6.js.map → chunk-77KIJLPP.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -79,6 +79,18 @@ type MedianSupportOptions = {
|
|
|
79
79
|
* first reply asking. Pass `false` and none of it is read at all.
|
|
80
80
|
*/
|
|
81
81
|
telemetry?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Whether the agent may take a picture of this page when it asks to see
|
|
84
|
+
* it. Drawn from the page itself rather than recorded off the screen, so
|
|
85
|
+
* nobody is asked for permission to share anything, and only when the
|
|
86
|
+
* agent asks: it says it is taking a look, and the picture lands in the
|
|
87
|
+
* thread where the visitor can see what was sent. On by default. Pass
|
|
88
|
+
* `false` on a page showing somebody else's data and the agent is told no
|
|
89
|
+
* picture is coming.
|
|
90
|
+
*
|
|
91
|
+
* Never the panel itself or anything else Median renders.
|
|
92
|
+
*/
|
|
93
|
+
screenshot?: boolean;
|
|
82
94
|
/**
|
|
83
95
|
* Take questions from signed in people only.
|
|
84
96
|
*
|
|
@@ -134,6 +146,17 @@ type MedianSupportOptions = {
|
|
|
134
146
|
* either side saying no is enough to keep the card away.
|
|
135
147
|
*/
|
|
136
148
|
messagePreview?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Put the unread count in the tab's title, as `(1) Your page`, while a
|
|
151
|
+
* reply is waiting. On by default: it is the one part of your page a
|
|
152
|
+
* visitor can see from another tab. Your own title is kept and put back
|
|
153
|
+
* once the reply has been read.
|
|
154
|
+
*
|
|
155
|
+
* <MedianSupport apiKey="median_pk_..." titleCount={false} />
|
|
156
|
+
*
|
|
157
|
+
* Pass `false` and the title is never touched.
|
|
158
|
+
*/
|
|
159
|
+
titleCount?: boolean;
|
|
137
160
|
/**
|
|
138
161
|
* Watch what goes wrong on the page, so a bug report arrives with the
|
|
139
162
|
* error already attached instead of after four messages of asking.
|
|
@@ -260,19 +283,26 @@ type MedianSupportProps = MedianSupportOptions & ({
|
|
|
260
283
|
declare function MedianSupport(props: MedianSupportProps): react.JSX.Element;
|
|
261
284
|
|
|
262
285
|
/**
|
|
263
|
-
* What a mounted
|
|
264
|
-
* no re-render to do for them. Everything else goes through
|
|
265
|
-
* same as anywhere.
|
|
286
|
+
* What a mounted component hands back: the two things a host without React
|
|
287
|
+
* has no re-render to do for them. Everything else goes through the
|
|
288
|
+
* component's own control, same as anywhere.
|
|
266
289
|
*/
|
|
267
|
-
type
|
|
290
|
+
type MedianMountInstance<Options> = {
|
|
268
291
|
/**
|
|
269
292
|
* Change any option after mount. Only the keys passed change, so
|
|
270
293
|
* `update({ user })` when somebody signs in leaves the rest alone.
|
|
271
294
|
*/
|
|
272
|
-
update: (options: Partial<
|
|
273
|
-
/** Take
|
|
295
|
+
update: (options: Partial<Options>) => void;
|
|
296
|
+
/** Take it off the page: the component, its container, its connection. */
|
|
274
297
|
unmount: () => void;
|
|
275
298
|
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* What a mounted widget hands back: the two things a host without React has
|
|
302
|
+
* no re-render to do for them. Everything else goes through `medianSupport`,
|
|
303
|
+
* same as anywhere.
|
|
304
|
+
*/
|
|
305
|
+
type MedianSupportInstance = MedianMountInstance<MedianSupportProps>;
|
|
276
306
|
/**
|
|
277
307
|
* The same widget, for a page that has never heard of React: Vue, Svelte,
|
|
278
308
|
* Rails, a script on plain HTML. One call puts the launcher in the corner,
|
|
@@ -293,6 +323,43 @@ type MedianSupportInstance = {
|
|
|
293
323
|
*/
|
|
294
324
|
declare function mountMedianSupport(options: MedianSupportProps): MedianSupportInstance;
|
|
295
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Every prop the widget takes, unchanged. The modal is the widget in a
|
|
328
|
+
* different place, not a different widget.
|
|
329
|
+
*/
|
|
330
|
+
type MedianSupportModalProps = MedianSupportProps;
|
|
331
|
+
/**
|
|
332
|
+
* The support widget as a modal: the same button in the corner, and a panel
|
|
333
|
+
* that opens in the middle of the screen over a scrim rather than out of
|
|
334
|
+
* the corner.
|
|
335
|
+
*
|
|
336
|
+
* <MedianSupportModal apiKey="median_pk_..." />
|
|
337
|
+
*
|
|
338
|
+
* Everything else is the widget's. Same props, same thread, same inbox on
|
|
339
|
+
* the other side, same `useMedianSupport()` to open it from your own nav,
|
|
340
|
+
* same sheet on a phone. Pick this for a site where a conversation deserves
|
|
341
|
+
* the room, or where a panel floating over the page would be in the way of
|
|
342
|
+
* the page.
|
|
343
|
+
*
|
|
344
|
+
* One or the other. Mounting both shares one open state, and the console
|
|
345
|
+
* says so.
|
|
346
|
+
*/
|
|
347
|
+
declare function MedianSupportModal(props: MedianSupportModalProps): react.JSX.Element;
|
|
348
|
+
|
|
349
|
+
type MedianSupportModalInstance = MedianMountInstance<MedianSupportModalProps>;
|
|
350
|
+
/**
|
|
351
|
+
* The modal, for a page that has never heard of React: Vue, Svelte, Rails,
|
|
352
|
+
* a script on plain HTML.
|
|
353
|
+
*
|
|
354
|
+
* const support = mountMedianSupportModal({ apiKey: "median_pk_..." });
|
|
355
|
+
*
|
|
356
|
+
* It takes the component's props as one options object, and the rest of the
|
|
357
|
+
* SDK does not know the difference: `medianSupport.open()` opens this modal
|
|
358
|
+
* exactly as it opens the component. `update` and `unmount` are the same two
|
|
359
|
+
* `mountMedianSupport` hands back.
|
|
360
|
+
*/
|
|
361
|
+
declare function mountMedianSupportModal(options: MedianSupportModalProps): MedianSupportModalInstance;
|
|
362
|
+
|
|
296
363
|
/**
|
|
297
364
|
* Filing the crash the visitor is looking at.
|
|
298
365
|
*
|
|
@@ -334,6 +401,12 @@ type MedianErrorReportOptions = {
|
|
|
334
401
|
attach?: Record<string, unknown>;
|
|
335
402
|
/** Whether the report carries what the browser knows. On by default. */
|
|
336
403
|
telemetry?: boolean;
|
|
404
|
+
/**
|
|
405
|
+
* Whether the report carries a picture of the screen it was filed from. On
|
|
406
|
+
* by default: what a crash screen actually looks like is the one thing the
|
|
407
|
+
* stack does not say. Pass `false` and no picture is taken.
|
|
408
|
+
*/
|
|
409
|
+
screenshot?: boolean;
|
|
337
410
|
};
|
|
338
411
|
/** Where the report went, or why it did not go. */
|
|
339
412
|
type MedianErrorReportOutcome = {
|
|
@@ -358,12 +431,14 @@ declare function useCanReportError(): boolean;
|
|
|
358
431
|
/**
|
|
359
432
|
* The widget from anywhere, React or not: the same shape the hook hands
|
|
360
433
|
* back, for a plain `onclick` or a shortcut listener that never sees a
|
|
361
|
-
* component. `isOpen`
|
|
362
|
-
* is for that.
|
|
434
|
+
* component. `isOpen` and `unreadCount` read live but do not re-render
|
|
435
|
+
* anything; the hook is for that.
|
|
363
436
|
*/
|
|
364
437
|
declare const medianSupport: {
|
|
365
438
|
/** What the panel is doing right now. */
|
|
366
439
|
readonly isOpen: boolean;
|
|
440
|
+
/** Replies the visitor has not read. Zero while nothing is mounted. */
|
|
441
|
+
readonly unreadCount: number;
|
|
367
442
|
open(): void;
|
|
368
443
|
close(): void;
|
|
369
444
|
toggle(): void;
|
|
@@ -396,6 +471,13 @@ declare const medianSupport: {
|
|
|
396
471
|
type MedianSupportControl = {
|
|
397
472
|
/** Whether the panel is open. */
|
|
398
473
|
isOpen: boolean;
|
|
474
|
+
/**
|
|
475
|
+
* Replies the visitor has not read: the same count the closed button
|
|
476
|
+
* wears and the tab's title carries. For a badge on a button of your own,
|
|
477
|
+
* on a page where the launcher is hidden. Zero while the panel is open,
|
|
478
|
+
* once it has been looked at, and whenever no panel is mounted.
|
|
479
|
+
*/
|
|
480
|
+
unreadCount: number;
|
|
399
481
|
open: () => void;
|
|
400
482
|
close: () => void;
|
|
401
483
|
toggle: () => void;
|
|
@@ -411,10 +493,15 @@ type MedianSupportControl = {
|
|
|
411
493
|
*
|
|
412
494
|
* const support = useMedianSupport();
|
|
413
495
|
*
|
|
414
|
-
* <button onClick={support.open}>
|
|
496
|
+
* <button onClick={support.open}>
|
|
497
|
+
* Contact us
|
|
498
|
+
* {support.unreadCount > 0 && <span>{support.unreadCount}</span>}
|
|
499
|
+
* </button>
|
|
415
500
|
*
|
|
416
501
|
* `isOpen` follows the panel however it was opened, so a trigger can render
|
|
417
502
|
* itself as pressed, or step out of the way while the panel is up.
|
|
503
|
+
* `unreadCount` follows the thread, so the trigger can say a reply is
|
|
504
|
+
* waiting where the corner button would have.
|
|
418
505
|
*/
|
|
419
506
|
declare function useMedianSupport(): MedianSupportControl;
|
|
420
507
|
|
|
@@ -459,6 +546,17 @@ type MedianFeedbackOptions = {
|
|
|
459
546
|
* read at all.
|
|
460
547
|
*/
|
|
461
548
|
telemetry?: boolean;
|
|
549
|
+
/**
|
|
550
|
+
* Whether a note carries a picture of the page it was written on, drawn
|
|
551
|
+
* from the page itself rather than recorded off the screen, so nobody is
|
|
552
|
+
* asked for permission to share anything. On by default: a bug report with
|
|
553
|
+
* the screen on it is one nobody has to describe. Pass `false` and no
|
|
554
|
+
* picture is taken.
|
|
555
|
+
*
|
|
556
|
+
* The panel itself is never in the picture, and neither is anything else
|
|
557
|
+
* Median renders.
|
|
558
|
+
*/
|
|
559
|
+
screenshot?: boolean;
|
|
462
560
|
/**
|
|
463
561
|
* Watch what goes wrong on the page, so a bug filed from a note arrives
|
|
464
562
|
* with the error already attached. The same switch `<MedianSupport>`
|
|
@@ -522,8 +620,8 @@ type MedianFeedbackMountOptions = Omit<MedianFeedbackOptions, "children"> & ({
|
|
|
522
620
|
* <MenuItem>Share feedback</MenuItem>
|
|
523
621
|
* </MedianFeedback>
|
|
524
622
|
*
|
|
525
|
-
* The page they were on rides along on its own,
|
|
526
|
-
*
|
|
623
|
+
* The page they were on rides along on its own, and so does a picture of it.
|
|
624
|
+
* `screenshot={false}` leaves the picture behind.
|
|
527
625
|
*
|
|
528
626
|
* It brings its own connection, so it works on pages that have never heard
|
|
529
627
|
* of Convex, and it is independent of `<MedianSupport>`: mount either, both,
|
|
@@ -537,15 +635,7 @@ declare function MedianFeedback(props: MedianFeedbackProps): react.JSX.Element;
|
|
|
537
635
|
* no re-render to do for them. Opening and closing go through
|
|
538
636
|
* `medianFeedback`, same as anywhere.
|
|
539
637
|
*/
|
|
540
|
-
type MedianFeedbackInstance =
|
|
541
|
-
/**
|
|
542
|
-
* Change any option after mount. Only the keys passed change, so
|
|
543
|
-
* `update({ user })` when somebody signs in leaves the rest alone.
|
|
544
|
-
*/
|
|
545
|
-
update: (options: Partial<MedianFeedbackProps>) => void;
|
|
546
|
-
/** Take the panel off the page. */
|
|
547
|
-
unmount: () => void;
|
|
548
|
-
};
|
|
638
|
+
type MedianFeedbackInstance = MedianMountInstance<MedianFeedbackProps>;
|
|
549
639
|
/**
|
|
550
640
|
* The same panel, for a page that has never heard of React: Vue, Svelte,
|
|
551
641
|
* Rails, a script on plain HTML.
|
|
@@ -587,4 +677,300 @@ type MedianFeedbackControl = {
|
|
|
587
677
|
*/
|
|
588
678
|
declare function useMedianFeedback(): MedianFeedbackControl;
|
|
589
679
|
|
|
590
|
-
|
|
680
|
+
/**
|
|
681
|
+
* What a host can put on the contact form, and what the form always has.
|
|
682
|
+
*
|
|
683
|
+
* Two fields are on every form whatever the host says: an email, because a
|
|
684
|
+
* message nobody can reply to is a message nobody sent, and the message
|
|
685
|
+
* itself. Everything else is the host's to add: a name, a topic, an order
|
|
686
|
+
* number, whatever their team wants to know before they read.
|
|
687
|
+
*/
|
|
688
|
+
/** A line, a paragraph, or one of a list. */
|
|
689
|
+
type MedianContactFieldKind = "text" | "textarea" | "select";
|
|
690
|
+
/**
|
|
691
|
+
* One field a host adds to the form.
|
|
692
|
+
*
|
|
693
|
+
* { name: "topic", label: "Topic", type: "select", options: ["Billing", "A bug"] }
|
|
694
|
+
*
|
|
695
|
+
* Three names are reserved. `email` and `message` are the two the form always
|
|
696
|
+
* has, and naming either here only changes its label and placeholder. `name`
|
|
697
|
+
* lands on the customer record beside the email rather than in the message,
|
|
698
|
+
* so the team sees who wrote rather than a line saying so.
|
|
699
|
+
*/
|
|
700
|
+
type MedianContactField = {
|
|
701
|
+
/** Its key. Rides the message as the label on its line. */
|
|
702
|
+
name: string;
|
|
703
|
+
/** Shown above the box. Made from `name` when left out. */
|
|
704
|
+
label?: string;
|
|
705
|
+
/** `text` by default. Ignored on `email` and `message`, which know their shape. */
|
|
706
|
+
type?: MedianContactFieldKind;
|
|
707
|
+
/** What a `select` offers. A select with none falls back to a text box. */
|
|
708
|
+
options?: string[];
|
|
709
|
+
placeholder?: string;
|
|
710
|
+
/** Off by default. `email` and `message` are required whatever this says. */
|
|
711
|
+
required?: boolean;
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
type MedianContactFormOptions = {
|
|
715
|
+
/**
|
|
716
|
+
* What the form asks, beyond an email and a message, which it always asks:
|
|
717
|
+
*
|
|
718
|
+
* <MedianContactForm
|
|
719
|
+
* apiKey="median_pk_..."
|
|
720
|
+
* fields={[
|
|
721
|
+
* { name: "name", label: "Name", required: true },
|
|
722
|
+
* { name: "topic", type: "select", options: ["Billing", "A bug", "Something else"] },
|
|
723
|
+
* ]}
|
|
724
|
+
* />
|
|
725
|
+
*
|
|
726
|
+
* Shown in this order. Email goes first, or right after a `name` field,
|
|
727
|
+
* and the message goes last, unless either is placed here by name. A
|
|
728
|
+
* `name` field lands on the customer record; every other answer goes
|
|
729
|
+
* above the message as a line of its own.
|
|
730
|
+
*/
|
|
731
|
+
fields?: MedianContactField[];
|
|
732
|
+
/**
|
|
733
|
+
* Who is signed in on your site, if anyone. Their email and name fill the
|
|
734
|
+
* boxes in, and the rest is shown to your team.
|
|
735
|
+
*/
|
|
736
|
+
user?: MedianUser;
|
|
737
|
+
/**
|
|
738
|
+
* Whether the message carries what the browser already knows: time zone,
|
|
739
|
+
* language, browser, OS, device, screen, and the page it was sent from.
|
|
740
|
+
* On by default. Pass `false` and none of it is read at all.
|
|
741
|
+
*/
|
|
742
|
+
telemetry?: boolean;
|
|
743
|
+
/**
|
|
744
|
+
* Watch what goes wrong on the page, so a bug report filed from the
|
|
745
|
+
* message arrives with the error already attached. The same switch
|
|
746
|
+
* `<MedianSupport>` takes, and the same buffer behind it.
|
|
747
|
+
*/
|
|
748
|
+
diagnostics?: MedianDiagnostics;
|
|
749
|
+
/**
|
|
750
|
+
* Anything about your own app worth having next to a bug report: a build,
|
|
751
|
+
* a route, a flag. Read when the form is sent.
|
|
752
|
+
*/
|
|
753
|
+
appState?: Record<string, string | number | boolean>;
|
|
754
|
+
/** The heading, for a page that calls this something else. */
|
|
755
|
+
title?: string;
|
|
756
|
+
/** The line under it. */
|
|
757
|
+
description?: string;
|
|
758
|
+
/**
|
|
759
|
+
* The message landed. For whatever your page does next: a thank-you of its
|
|
760
|
+
* own, a redirect, an event. The form has already said thank you itself.
|
|
761
|
+
*/
|
|
762
|
+
onSent?: () => void;
|
|
763
|
+
};
|
|
764
|
+
/**
|
|
765
|
+
* Two ways in, the same two `<MedianSupport>` takes.
|
|
766
|
+
*
|
|
767
|
+
* `apiKey` is the publishable id on its own. `identity` is the path to a
|
|
768
|
+
* route built with `medianIdentity`, which answers with the key and with
|
|
769
|
+
* whoever is signed in, already signed. Pass both and the form is up on the
|
|
770
|
+
* key from the prop while the route is still answering.
|
|
771
|
+
*/
|
|
772
|
+
type MedianContactFormProps = MedianContactFormOptions & ({
|
|
773
|
+
apiKey: string;
|
|
774
|
+
identity?: string;
|
|
775
|
+
} | {
|
|
776
|
+
apiKey?: string;
|
|
777
|
+
identity: string;
|
|
778
|
+
});
|
|
779
|
+
/**
|
|
780
|
+
* A contact form, for the page where a chat panel is the wrong shape.
|
|
781
|
+
*
|
|
782
|
+
* <MedianContactForm apiKey="median_pk_..." />
|
|
783
|
+
*
|
|
784
|
+
* An email and a message, on a card the shape of the support panel, with
|
|
785
|
+
* whatever else your team wants asked first. What is sent starts a
|
|
786
|
+
* conversation in your inbox exactly as the widget would: the agent answers
|
|
787
|
+
* first, your team picks it up, and the reply goes to the email given.
|
|
788
|
+
*
|
|
789
|
+
* Built on `useMedianContact`, which is also what a form of your own uses.
|
|
790
|
+
* It needs no connection of its own, and it is independent of
|
|
791
|
+
* `<MedianSupport>`: mount either, both, or neither. Mounted together they
|
|
792
|
+
* share a visitor, so somebody who writes here and later opens the widget
|
|
793
|
+
* finds the same thread.
|
|
794
|
+
*/
|
|
795
|
+
declare function MedianContactForm(props: MedianContactFormProps): react.JSX.Element;
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* The component's props, plus where on the page the form goes.
|
|
799
|
+
*
|
|
800
|
+
* Spelled out rather than `Omit`ped off the props, because omitting a key
|
|
801
|
+
* from a union of two shapes flattens it into one and loses the "either,
|
|
802
|
+
* but not neither" the union is there to say.
|
|
803
|
+
*/
|
|
804
|
+
type MedianContactFormMountOptions = MedianContactFormProps & {
|
|
805
|
+
/**
|
|
806
|
+
* The element the form is rendered into, or a selector for it:
|
|
807
|
+
*
|
|
808
|
+
* mountMedianContactForm({ target: "#contact", apiKey: "median_pk_..." });
|
|
809
|
+
*
|
|
810
|
+
* Unlike the widget, a form has no corner to go to, so this is required.
|
|
811
|
+
*/
|
|
812
|
+
target: string | Element;
|
|
813
|
+
};
|
|
814
|
+
type MedianContactFormInstance = MedianMountInstance<MedianContactFormProps>;
|
|
815
|
+
/**
|
|
816
|
+
* The same form, for a page that has never heard of React: Vue, Svelte,
|
|
817
|
+
* Rails, a script on plain HTML.
|
|
818
|
+
*
|
|
819
|
+
* const form = mountMedianContactForm({
|
|
820
|
+
* target: "#contact",
|
|
821
|
+
* apiKey: "median_pk_...",
|
|
822
|
+
* fields: [{ name: "name", label: "Name" }],
|
|
823
|
+
* });
|
|
824
|
+
*
|
|
825
|
+
* It takes the component's props as one options object, plus `target`, and
|
|
826
|
+
* renders into a container of its own inside that element with the
|
|
827
|
+
* package's copy of React. Whatever else the element holds is left alone.
|
|
828
|
+
*/
|
|
829
|
+
declare function mountMedianContactForm({ target, ...options }: MedianContactFormMountOptions): MedianContactFormInstance;
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* What a contact form hands over, ours or a host's own.
|
|
833
|
+
*
|
|
834
|
+
* The shape is deliberately small: the two things a message needs to be
|
|
835
|
+
* answered, who wrote it if they said, and whatever else the form asked as
|
|
836
|
+
* label to answer. Building one from a `<form>` of your own is a few lines.
|
|
837
|
+
*/
|
|
838
|
+
type MedianContactMessage = {
|
|
839
|
+
/** Where the reply goes. */
|
|
840
|
+
email: string;
|
|
841
|
+
/** What they wrote. */
|
|
842
|
+
message: string;
|
|
843
|
+
/** Lands on the customer record beside the email. */
|
|
844
|
+
name?: string;
|
|
845
|
+
/**
|
|
846
|
+
* Everything else the form asked, as label to answer. Each goes above the
|
|
847
|
+
* message as a line of its own, so the team reads the form the way it was
|
|
848
|
+
* filled in:
|
|
849
|
+
*
|
|
850
|
+
* { Topic: "Billing", "Order number": "4821" }
|
|
851
|
+
*
|
|
852
|
+
* Empty answers are left off.
|
|
853
|
+
*/
|
|
854
|
+
fields?: Record<string, string>;
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Sending a contact message, for a form of the host's own.
|
|
859
|
+
*
|
|
860
|
+
* The same door the widget's composer uses, on the same session token, so
|
|
861
|
+
* what a host's form sends starts the thread the corner would have started:
|
|
862
|
+
* the team answers it from the inbox, the agent goes first, and with no
|
|
863
|
+
* panel open to watch, the reply goes to the email given. Somebody who
|
|
864
|
+
* writes here and later opens the widget finds their own conversation.
|
|
865
|
+
*
|
|
866
|
+
* A stateless HTTP client rather than the subscribing one, because nothing
|
|
867
|
+
* is read back: a form is a thing you hand over, not a thread you watch.
|
|
868
|
+
*/
|
|
869
|
+
/** What a send is told about who is sending and from where. */
|
|
870
|
+
type MedianContactOptions = {
|
|
871
|
+
/** The browser-safe median_pk_ id. */
|
|
872
|
+
apiKey: string;
|
|
873
|
+
/**
|
|
874
|
+
* Who is signed in on your site, if anyone. What the form says about the
|
|
875
|
+
* email and the name wins over this; the rest is shown to your team.
|
|
876
|
+
*/
|
|
877
|
+
user?: MedianUser;
|
|
878
|
+
/**
|
|
879
|
+
* Whether the message carries what the browser already knows: time zone,
|
|
880
|
+
* language, browser, OS, device, screen, and the page it was sent from.
|
|
881
|
+
* On by default. Pass `false` and none of it is read at all.
|
|
882
|
+
*/
|
|
883
|
+
telemetry?: boolean;
|
|
884
|
+
};
|
|
885
|
+
/**
|
|
886
|
+
* Send a contact message from a form of your own, on any page in the
|
|
887
|
+
* browser:
|
|
888
|
+
*
|
|
889
|
+
* await sendMedianContact(
|
|
890
|
+
* { apiKey: "median_pk_..." },
|
|
891
|
+
* { email, message, name, fields: { Topic: topic } },
|
|
892
|
+
* );
|
|
893
|
+
*
|
|
894
|
+
* It resolves once the message is in your inbox and rejects with an `Error`
|
|
895
|
+
* whose `message` is worth showing above your button. Nothing about the
|
|
896
|
+
* form is ours: any `<form>`, any framework, any styling.
|
|
897
|
+
*
|
|
898
|
+
* In React, `useMedianContact()` is the same call with `isSending` and
|
|
899
|
+
* `error` kept for you, and an identity route resolved.
|
|
900
|
+
*/
|
|
901
|
+
declare function sendMedianContact(options: MedianContactOptions, message: MedianContactMessage): Promise<void>;
|
|
902
|
+
|
|
903
|
+
type MedianContactHookOptions = {
|
|
904
|
+
/** Who is signed in on your site, if anyone. */
|
|
905
|
+
user?: MedianUser;
|
|
906
|
+
/** Browser context on the message. On by default. */
|
|
907
|
+
telemetry?: boolean;
|
|
908
|
+
/**
|
|
909
|
+
* Watch what goes wrong on the page, so a bug report filed from the
|
|
910
|
+
* message arrives with the error already attached. The same switch
|
|
911
|
+
* `<MedianSupport>` takes, and the same buffer behind it.
|
|
912
|
+
*/
|
|
913
|
+
diagnostics?: MedianDiagnostics;
|
|
914
|
+
/** Anything about your own app worth having next to a bug report. */
|
|
915
|
+
appState?: Record<string, string | number | boolean>;
|
|
916
|
+
};
|
|
917
|
+
/**
|
|
918
|
+
* Two ways in, the same two every component takes: the publishable key, or
|
|
919
|
+
* the path of a route built with `medianIdentity`, which answers with the
|
|
920
|
+
* key and whoever is signed in.
|
|
921
|
+
*/
|
|
922
|
+
type UseMedianContactOptions = MedianContactHookOptions & ({
|
|
923
|
+
apiKey: string;
|
|
924
|
+
identity?: string;
|
|
925
|
+
} | {
|
|
926
|
+
apiKey?: string;
|
|
927
|
+
identity: string;
|
|
928
|
+
});
|
|
929
|
+
/** What the hook hands back: one call, and the state around it. */
|
|
930
|
+
type MedianContactControl = {
|
|
931
|
+
showBranding: boolean;
|
|
932
|
+
/**
|
|
933
|
+
* Send what the form holds. Resolves once the message is in the inbox.
|
|
934
|
+
* Rejects with an `Error` whose `message` is worth showing, and `error`
|
|
935
|
+
* holds the same words until the next send.
|
|
936
|
+
*/
|
|
937
|
+
send: (message: MedianContactMessage) => Promise<void>;
|
|
938
|
+
/** A send is in flight. Hold the button. */
|
|
939
|
+
isSending: boolean;
|
|
940
|
+
/** Why the last send failed, or null. Cleared by the next send. */
|
|
941
|
+
error: string | null;
|
|
942
|
+
/**
|
|
943
|
+
* Whether a send has somewhere to go. False on the server, and for the
|
|
944
|
+
* beat before an identity route has answered with the key.
|
|
945
|
+
*/
|
|
946
|
+
isReady: boolean;
|
|
947
|
+
/**
|
|
948
|
+
* Who is typing, as far as the page knows: what you passed, what the
|
|
949
|
+
* identity route said, and the email the widget's own question was
|
|
950
|
+
* answered with on this browser. For filling the boxes in.
|
|
951
|
+
*/
|
|
952
|
+
user: MedianUser | undefined;
|
|
953
|
+
};
|
|
954
|
+
/**
|
|
955
|
+
* A contact form of your own, on Median's inbox:
|
|
956
|
+
*
|
|
957
|
+
* const contact = useMedianContact({ apiKey: "median_pk_..." });
|
|
958
|
+
*
|
|
959
|
+
* <form
|
|
960
|
+
* onSubmit={async (event) => {
|
|
961
|
+
* event.preventDefault();
|
|
962
|
+
* await contact.send({ email, message });
|
|
963
|
+
* }}
|
|
964
|
+
* >
|
|
965
|
+
* ...
|
|
966
|
+
* {contact.error && <p>{contact.error}</p>}
|
|
967
|
+
* <button disabled={contact.isSending}>Send</button>
|
|
968
|
+
* </form>
|
|
969
|
+
*
|
|
970
|
+
* Everything about the form is yours. What is sent starts a conversation in
|
|
971
|
+
* your inbox exactly as `<MedianContactForm>` and the widget do, and the
|
|
972
|
+
* reply goes to the email given. No provider, no connection to manage.
|
|
973
|
+
*/
|
|
974
|
+
declare function useMedianContact(options: UseMedianContactOptions): MedianContactControl;
|
|
975
|
+
|
|
976
|
+
export { type MedianContactControl, type MedianContactField, type MedianContactFieldKind, MedianContactForm, type MedianContactFormInstance, type MedianContactFormMountOptions, type MedianContactFormProps, type MedianContactMessage, type MedianContactOptions, type MedianDiagnostics, type MedianErrorReportOptions, type MedianErrorReportOutcome, MedianFeedback, type MedianFeedbackControl, type MedianFeedbackInstance, type MedianFeedbackProps, MedianSupport, type MedianSupportControl, type MedianSupportInstance, MedianSupportModal, type MedianSupportModalInstance, type MedianSupportModalProps, type MedianSupportProps, type MedianUser, type MedianDiagnostics as PortalDiagnostics, type MedianErrorReportOptions as PortalErrorReportOptions, type MedianErrorReportOutcome as PortalErrorReportOutcome, MedianFeedback as PortalFeedback, type MedianFeedbackControl as PortalFeedbackControl, type MedianFeedbackInstance as PortalFeedbackInstance, type MedianFeedbackProps as PortalFeedbackProps, MedianSupport as PortalSupport, type MedianSupportControl as PortalSupportControl, type MedianSupportInstance as PortalSupportInstance, type MedianSupportProps as PortalSupportProps, type MedianUser as PortalUser, type SupportLauncherKind, type UseMedianContactOptions, medianFeedback, medianSupport, mountMedianContactForm, mountMedianFeedback, mountMedianSupport, mountMedianSupportModal, mountMedianFeedback as mountPortalFeedback, mountMedianSupport as mountPortalSupport, medianFeedback as portalFeedback, medianSupport as portalSupport, reportError, sendMedianContact, useCanReportError, useMedianContact, useMedianFeedback, useMedianSupport, useMedianFeedback as usePortalFeedback, useMedianSupport as usePortalSupport };
|