@chatlychat/widget-element 0.0.0-stage → 0.1.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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +180 -2
- package/dist/element.d.ts +66 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +333 -0
- package/dist/element.js.map +1 -0
- package/dist/embed.d.ts +122 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +493 -0
- package/dist/embed.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +12 -0
- package/dist/register.js.map +1 -0
- package/dist/same-value.d.ts +25 -0
- package/dist/same-value.d.ts.map +1 -0
- package/dist/same-value.js +60 -0
- package/dist/same-value.js.map +1 -0
- package/dist/types.d.ts +241 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/package.json +68 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @chatlychat/widget-element — changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — unreleased
|
|
4
|
+
|
|
5
|
+
- Initial release: `<chatly-widget>` custom element, `defineChatlyWidget()`,
|
|
6
|
+
and the refcounted embed lifecycle (`startWidget`, `controls`) that
|
|
7
|
+
`@chatlychat/widget-react` builds on.
|
|
8
|
+
- Zero dependencies. The main entry has no side effects; `/register` defines
|
|
9
|
+
the tag.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chatly Engineering
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,181 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @chatlychat/widget-element
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Chatly chat widget as a custom element. **Zero dependencies.**
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pnpm add @chatlychat/widget-element
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script type="module">
|
|
11
|
+
import '@chatlychat/widget-element/register';
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<chatly-widget public-id="acme-web" api-url="https://api.chatlychat.com"></chatly-widget>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Works in Vue, Svelte, Angular, Lit, Astro, Alpine, htmx and plain HTML —
|
|
18
|
+
anywhere a custom element works. For React, use
|
|
19
|
+
[`@chatlychat/widget-react`](../widget-react), which is built on this package's
|
|
20
|
+
lifecycle.
|
|
21
|
+
|
|
22
|
+
## Why not just paste the snippet?
|
|
23
|
+
|
|
24
|
+
If a `<script>` in your `<head>` is all you need, paste
|
|
25
|
+
[the snippet](https://chatlychat.com/docs/channel-web) and stop reading. This
|
|
26
|
+
package earns its keep when the widget's lifetime is tied to something your
|
|
27
|
+
framework owns:
|
|
28
|
+
|
|
29
|
+
- the chat should appear on some routes and not others, and your router
|
|
30
|
+
unmounts the element;
|
|
31
|
+
- the theme or the visitor's identity comes from component state;
|
|
32
|
+
- your templates bind properties and listen for events, and you would rather
|
|
33
|
+
write `<chatly-widget :theme="theme" @chatly-ready="…">` than reach into
|
|
34
|
+
`window`.
|
|
35
|
+
|
|
36
|
+
It also handles three things a hand-written integration usually does not: a
|
|
37
|
+
widget left behind when its component unmounts, a re-boot caused by a DOM
|
|
38
|
+
move, and a re-initialisation caused by a re-render that changed nothing.
|
|
39
|
+
|
|
40
|
+
## Attributes
|
|
41
|
+
|
|
42
|
+
| attribute | notes |
|
|
43
|
+
| ---------------- | ------------------------------------------------------------- |
|
|
44
|
+
| `public-id` | **Required.** The web channel's public ID. |
|
|
45
|
+
| `api-url` | Defaults to the host the loader was served from. |
|
|
46
|
+
| `realtime-url` | Rarely needed; the API reports the right one. |
|
|
47
|
+
| `loader-url` | Where `loader.js` is served from. **Self-hosting: set this.** |
|
|
48
|
+
| `locale` | Applied with `setLocale()` once the widget is up. |
|
|
49
|
+
| `css-overrides` | CSS injected into the widget's shadow root. |
|
|
50
|
+
| `inline` | Boolean. Mount the chat inside this element. |
|
|
51
|
+
| `theme` | JSON. |
|
|
52
|
+
| `behavior` | JSON. |
|
|
53
|
+
| `visitor` | JSON. |
|
|
54
|
+
| `copy` | JSON. |
|
|
55
|
+
| `copy-by-locale` | JSON. |
|
|
56
|
+
| `quick-links` | JSON. |
|
|
57
|
+
|
|
58
|
+
Attributes are live: change one and the element applies it. A changed
|
|
59
|
+
`visitor` becomes an `identify()` and a changed `locale` a `setLocale()` —
|
|
60
|
+
neither re-mounts the widget. A change to anything else re-initialises it,
|
|
61
|
+
which closes an open panel (the widget has no `setTheme`; this is the honest
|
|
62
|
+
cost, and it only happens when a value really changed).
|
|
63
|
+
|
|
64
|
+
### A malformed JSON attribute does not stop the chat
|
|
65
|
+
|
|
66
|
+
It is dropped, `console.error` says which attribute and why, and the widget
|
|
67
|
+
starts without it.
|
|
68
|
+
|
|
69
|
+
That is the opposite of what the widget does with a `mountTo` selector that
|
|
70
|
+
matches nothing, and deliberately so: a failed `mountTo` would put an
|
|
71
|
+
unexpected floating bubble on a page built to embed the chat, which reads as a
|
|
72
|
+
bug and is easy to miss, whereas a failed `theme` leaves a working chat in the
|
|
73
|
+
default colours and a named error in the console. Losing support chat on your
|
|
74
|
+
site over a trailing comma is the worse trade.
|
|
75
|
+
|
|
76
|
+
## Properties
|
|
77
|
+
|
|
78
|
+
Every JSON attribute is also a property, and the property wins:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
const chat = document.querySelector('chatly-widget');
|
|
82
|
+
chat.theme = { primaryColor: '#4f46e5', colorScheme: 'auto' };
|
|
83
|
+
chat.visitor = { externalId: 'u_42', email: 'jamie@acme.io', userHash };
|
|
84
|
+
chat.config = { behavior: { tabs: ['home', 'messages'] } }; // the whole object
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Setting a property **before** the element is defined or upgraded works too,
|
|
88
|
+
which matters because every property-binding template engine can produce that
|
|
89
|
+
ordering.
|
|
90
|
+
|
|
91
|
+
`chat.controls` is the widget's post-boot method object — `open`, `close`,
|
|
92
|
+
`toggle`, `identify`, `setUser`, `setCustomAttributes`,
|
|
93
|
+
`deleteCustomAttribute`, `setLabel`, `removeLabel`, `setLocale`, `track`,
|
|
94
|
+
`registerPushToken`, `reset` — so a reference to the element is enough to
|
|
95
|
+
drive the chat. It is also exported on its own as `controls`.
|
|
96
|
+
|
|
97
|
+
`init` and `destroy` are deliberately absent: the element owns the lifecycle,
|
|
98
|
+
and calling them behind its back leaves it believing a widget is mounted that
|
|
99
|
+
is not.
|
|
100
|
+
|
|
101
|
+
## Events
|
|
102
|
+
|
|
103
|
+
The element re-dispatches every widget event as a DOM `CustomEvent`, with the
|
|
104
|
+
widget's payload on `detail`. They bubble and are `composed`, so a listener on
|
|
105
|
+
an ancestor hears them.
|
|
106
|
+
|
|
107
|
+
`chatly-ready`, `chatly-open`, `chatly-close`, `chatly-message`,
|
|
108
|
+
`chatly-conversation`, `chatly-identified`, `chatly-reset`, `chatly-action`,
|
|
109
|
+
`chatly-error`.
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<chatly-widget public-id="acme-web"></chatly-widget>
|
|
113
|
+
<script type="module">
|
|
114
|
+
import '@chatlychat/widget-element/register';
|
|
115
|
+
document.querySelector('chatly-widget').addEventListener('chatly-message', (e) => {
|
|
116
|
+
console.log('reply from', e.detail.authorType);
|
|
117
|
+
});
|
|
118
|
+
</script>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Hyphenated, not `chatly:message`: a colon is legal in an event name but not in
|
|
122
|
+
a Vue, Angular or Svelte template binding.
|
|
123
|
+
|
|
124
|
+
## Inline mounting
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
<chatly-widget public-id="acme-web" inline style="height: 600px"></chatly-widget>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The chat fills the element instead of floating. No launcher, no corner offset,
|
|
131
|
+
and `close()` warns instead of working — hide or remove the element instead.
|
|
132
|
+
|
|
133
|
+
The element sets `display: block` on itself in this mode, because a custom
|
|
134
|
+
element is `display: inline` by default, which collapses to a zero-height box
|
|
135
|
+
and looks exactly like the widget failing to load. It also sets a 420px
|
|
136
|
+
`min-height` unless you set one.
|
|
137
|
+
|
|
138
|
+
## The main entry has no side effects
|
|
139
|
+
|
|
140
|
+
Importing `@chatlychat/widget-element` defines nothing and touches no DOM.
|
|
141
|
+
`@chatlychat/widget-element/register` is the opt-in that defines
|
|
142
|
+
`<chatly-widget>`, and `defineChatlyWidget('my-tag')` is there if you need a
|
|
143
|
+
different tag name. Calling either twice is safe.
|
|
144
|
+
|
|
145
|
+
This split is why `@chatlychat/widget-react` can depend on this package for the
|
|
146
|
+
embed lifecycle without registering an element its consumers never asked for,
|
|
147
|
+
and why nothing here crashes a server-side bundle — a top-level
|
|
148
|
+
`class X extends HTMLElement` would throw `HTMLElement is not defined` the
|
|
149
|
+
moment a Next.js server component imported so much as a type from here.
|
|
150
|
+
|
|
151
|
+
## One widget per page
|
|
152
|
+
|
|
153
|
+
`window.Chatly` is a singleton. Two connected `<chatly-widget>` elements with
|
|
154
|
+
different attributes is a misconfiguration: the first owns the configuration,
|
|
155
|
+
the second's attributes are ignored (its events still fire), and a console
|
|
156
|
+
warning says so. Two with the same configuration is harmless — which is what
|
|
157
|
+
makes an element inside a template that re-renders safe.
|
|
158
|
+
|
|
159
|
+
Moving the element in the DOM, or removing and re-adding it in the same task,
|
|
160
|
+
does **not** re-boot the widget. A `disconnectedCallback` is not necessarily
|
|
161
|
+
an unmount: `appendChild` elsewhere fires disconnect then connect, and so does
|
|
162
|
+
a framework re-keying a list.
|
|
163
|
+
|
|
164
|
+
## Composing with the snippet
|
|
165
|
+
|
|
166
|
+
If the page already has the snippet, this package does not fetch a second
|
|
167
|
+
loader — it queues its `init` onto the shim the snippet installed and lets that
|
|
168
|
+
loader replay it. The element's configuration wins. You do not need both, but
|
|
169
|
+
having both is not broken.
|
|
170
|
+
|
|
171
|
+
## Self-hosting
|
|
172
|
+
|
|
173
|
+
Set `loader-url`. `GET /v1/channels/:id` returns the right value for your
|
|
174
|
+
deployment as `embed.loaderUrl`; read it from there rather than typing a host.
|
|
175
|
+
The same response lists every origin a running widget connects to
|
|
176
|
+
(`connectOrigins`) — there are three, and a CSP built from the script host
|
|
177
|
+
alone lets the launcher paint and then blocks every request it makes.
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<chatly-widget>` — the widget as a custom element.
|
|
3
|
+
*
|
|
4
|
+
* ── Why the class is built inside a function ────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* `class X extends HTMLElement {}` is evaluated when its MODULE is evaluated,
|
|
7
|
+
* and `HTMLElement` does not exist in Node. A top-level class would therefore
|
|
8
|
+
* throw `ReferenceError: HTMLElement is not defined` the moment a Next.js
|
|
9
|
+
* server component, a Remix loader or a Vitest node-environment test imported
|
|
10
|
+
* anything from this package — including just a type. That is not a
|
|
11
|
+
* theoretical risk: it is the single most common way a web-component package
|
|
12
|
+
* breaks an SSR build, and the stack trace points at the framework rather
|
|
13
|
+
* than at us.
|
|
14
|
+
*
|
|
15
|
+
* So the class is created lazily by `defineChatlyWidget()`, the main entry has
|
|
16
|
+
* no side effects at all, and `@chatlychat/widget-element/register` is the
|
|
17
|
+
* opt-in that defines the tag. A React consumer pulling this package in for
|
|
18
|
+
* the embed lifecycle never registers an element they did not ask for.
|
|
19
|
+
*
|
|
20
|
+
* ── Attributes vs properties ────────────────────────────────────────────
|
|
21
|
+
*
|
|
22
|
+
* HTML attributes are strings. `theme`, `behavior`, `visitor`, `copy`,
|
|
23
|
+
* `copy-by-locale` and `quick-links` are objects, so each is accepted BOTH as
|
|
24
|
+
* a JSON attribute (for a page that is really just HTML) and as a property
|
|
25
|
+
* (for a framework template that has a real object to hand). The property
|
|
26
|
+
* wins when both are set, because a framework binding is the more specific
|
|
27
|
+
* statement.
|
|
28
|
+
*/
|
|
29
|
+
import { controls } from './embed.js';
|
|
30
|
+
import type { ChatlyBehavior, ChatlyCopy, ChatlyEmbedOptions, ChatlyIdentity, ChatlyQuickLink, ChatlyTheme } from './types.js';
|
|
31
|
+
/** The default tag name. Overridable in `defineChatlyWidget`. */
|
|
32
|
+
export declare const CHATLY_WIDGET_TAG = "chatly-widget";
|
|
33
|
+
/**
|
|
34
|
+
* The events the element re-dispatches, and the handler each comes from.
|
|
35
|
+
*
|
|
36
|
+
* Prefixed `chatly-` rather than `chatly:` — a colon is legal in an event
|
|
37
|
+
* name but not in a Vue/Angular/Svelte template binding, which is most of the
|
|
38
|
+
* audience for a custom element. They bubble and are `composed` so a listener
|
|
39
|
+
* on an ancestor (or outside a shadow root the host page put us in) hears them.
|
|
40
|
+
*/
|
|
41
|
+
export declare const ELEMENT_EVENTS: readonly ["ready", "open", "close", "message", "conversation", "identified", "reset", "action", "error"];
|
|
42
|
+
/** `chatly-ready`, `chatly-message`, … — the DOM event names, without prefix. */
|
|
43
|
+
export type ChatlyElementEvent = (typeof ELEMENT_EVENTS)[number];
|
|
44
|
+
/** What `document.querySelector<ChatlyWidgetElement>` gets you. */
|
|
45
|
+
export interface ChatlyWidgetElement extends HTMLElement {
|
|
46
|
+
theme?: ChatlyTheme;
|
|
47
|
+
behavior?: ChatlyBehavior;
|
|
48
|
+
visitor?: ChatlyIdentity;
|
|
49
|
+
copy?: ChatlyCopy;
|
|
50
|
+
copyByLocale?: Record<string, ChatlyCopy>;
|
|
51
|
+
quickLinks?: ChatlyQuickLink[];
|
|
52
|
+
/** The full option object, for a host that would rather set one thing. */
|
|
53
|
+
config?: Partial<ChatlyEmbedOptions>;
|
|
54
|
+
/** `Chatly.open()` and friends, so a reference to the element is enough. */
|
|
55
|
+
readonly controls: typeof controls;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Define the element, once.
|
|
59
|
+
*
|
|
60
|
+
* Idempotent and safe to call from anywhere: a second call with a tag that is
|
|
61
|
+
* already registered returns quietly instead of throwing
|
|
62
|
+
* `NotSupportedError: the name "chatly-widget" has already been used`, which
|
|
63
|
+
* is what two bundles each importing `/register` would otherwise produce.
|
|
64
|
+
*/
|
|
65
|
+
export declare function defineChatlyWidget(tagName?: string): void;
|
|
66
|
+
//# sourceMappingURL=element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,QAAQ,EAAuC,MAAM,YAAY,CAAC;AAE3E,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EAEV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAqCjD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,0GAUjB,CAAC;AAEX,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAejE,mEAAmE;AACnE,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,OAAO,QAAQ,CAAC;CACpC;AA+CD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,MAA0B,GAAG,IAAI,CAS5E"}
|
package/dist/element.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<chatly-widget>` — the widget as a custom element.
|
|
3
|
+
*
|
|
4
|
+
* ── Why the class is built inside a function ────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* `class X extends HTMLElement {}` is evaluated when its MODULE is evaluated,
|
|
7
|
+
* and `HTMLElement` does not exist in Node. A top-level class would therefore
|
|
8
|
+
* throw `ReferenceError: HTMLElement is not defined` the moment a Next.js
|
|
9
|
+
* server component, a Remix loader or a Vitest node-environment test imported
|
|
10
|
+
* anything from this package — including just a type. That is not a
|
|
11
|
+
* theoretical risk: it is the single most common way a web-component package
|
|
12
|
+
* breaks an SSR build, and the stack trace points at the framework rather
|
|
13
|
+
* than at us.
|
|
14
|
+
*
|
|
15
|
+
* So the class is created lazily by `defineChatlyWidget()`, the main entry has
|
|
16
|
+
* no side effects at all, and `@chatlychat/widget-element/register` is the
|
|
17
|
+
* opt-in that defines the tag. A React consumer pulling this package in for
|
|
18
|
+
* the embed lifecycle never registers an element they did not ask for.
|
|
19
|
+
*
|
|
20
|
+
* ── Attributes vs properties ────────────────────────────────────────────
|
|
21
|
+
*
|
|
22
|
+
* HTML attributes are strings. `theme`, `behavior`, `visitor`, `copy`,
|
|
23
|
+
* `copy-by-locale` and `quick-links` are objects, so each is accepted BOTH as
|
|
24
|
+
* a JSON attribute (for a page that is really just HTML) and as a property
|
|
25
|
+
* (for a framework template that has a real object to hand). The property
|
|
26
|
+
* wins when both are set, because a framework binding is the more specific
|
|
27
|
+
* statement.
|
|
28
|
+
*/
|
|
29
|
+
import { controls, startWidget } from './embed.js';
|
|
30
|
+
/** The default tag name. Overridable in `defineChatlyWidget`. */
|
|
31
|
+
export const CHATLY_WIDGET_TAG = 'chatly-widget';
|
|
32
|
+
/**
|
|
33
|
+
* Attribute names, and the option each one sets.
|
|
34
|
+
*
|
|
35
|
+
* Kebab-case on the outside because that is what HTML authors expect and what
|
|
36
|
+
* `attributeChangedCallback` reports; camelCase on the inside because that is
|
|
37
|
+
* the widget's own option name. `json: true` marks the ones parsed rather
|
|
38
|
+
* than passed through.
|
|
39
|
+
*/
|
|
40
|
+
const ATTRIBUTES = [
|
|
41
|
+
{ attribute: 'public-id', option: 'publicId' },
|
|
42
|
+
{ attribute: 'api-url', option: 'apiUrl' },
|
|
43
|
+
{ attribute: 'realtime-url', option: 'realtimeUrl' },
|
|
44
|
+
{ attribute: 'loader-url', option: 'loaderUrl' },
|
|
45
|
+
{ attribute: 'locale', option: 'locale' },
|
|
46
|
+
{ attribute: 'css-overrides', option: 'cssOverrides' },
|
|
47
|
+
{ attribute: 'theme', option: 'theme', json: true },
|
|
48
|
+
{ attribute: 'behavior', option: 'behavior', json: true },
|
|
49
|
+
{ attribute: 'visitor', option: 'visitor', json: true },
|
|
50
|
+
{ attribute: 'copy', option: 'copy', json: true },
|
|
51
|
+
{ attribute: 'copy-by-locale', option: 'copyByLocale', json: true },
|
|
52
|
+
{ attribute: 'quick-links', option: 'quickLinks', json: true },
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* `inline` is handled separately: it is boolean (present/absent) and it does
|
|
56
|
+
* not carry a value, it decides whether `mountTo` is this element.
|
|
57
|
+
*/
|
|
58
|
+
const INLINE_ATTRIBUTE = 'inline';
|
|
59
|
+
const OBSERVED = [...ATTRIBUTES.map((a) => a.attribute), INLINE_ATTRIBUTE];
|
|
60
|
+
/**
|
|
61
|
+
* The events the element re-dispatches, and the handler each comes from.
|
|
62
|
+
*
|
|
63
|
+
* Prefixed `chatly-` rather than `chatly:` — a colon is legal in an event
|
|
64
|
+
* name but not in a Vue/Angular/Svelte template binding, which is most of the
|
|
65
|
+
* audience for a custom element. They bubble and are `composed` so a listener
|
|
66
|
+
* on an ancestor (or outside a shadow root the host page put us in) hears them.
|
|
67
|
+
*/
|
|
68
|
+
export const ELEMENT_EVENTS = [
|
|
69
|
+
'ready',
|
|
70
|
+
'open',
|
|
71
|
+
'close',
|
|
72
|
+
'message',
|
|
73
|
+
'conversation',
|
|
74
|
+
'identified',
|
|
75
|
+
'reset',
|
|
76
|
+
'action',
|
|
77
|
+
'error',
|
|
78
|
+
];
|
|
79
|
+
/**
|
|
80
|
+
* The object-valued properties, for the pre-upgrade dance in the constructor.
|
|
81
|
+
*
|
|
82
|
+
* Derived from `ATTRIBUTES` plus `config` so a new JSON attribute cannot be
|
|
83
|
+
* added without also being rescued on upgrade — the failure mode there is
|
|
84
|
+
* silent, and a list maintained by hand beside another list is how it would
|
|
85
|
+
* happen.
|
|
86
|
+
*/
|
|
87
|
+
const PROPERTY_NAMES = [
|
|
88
|
+
...ATTRIBUTES.filter((a) => a.json === true).map((a) => a.option),
|
|
89
|
+
'config',
|
|
90
|
+
];
|
|
91
|
+
/**
|
|
92
|
+
* Parse a JSON attribute, or drop it.
|
|
93
|
+
*
|
|
94
|
+
* ── Why a malformed attribute does not stop the widget ──────────────────
|
|
95
|
+
*
|
|
96
|
+
* A broken `theme` attribute could either (a) refuse to mount, the way the
|
|
97
|
+
* widget refuses a `mountTo` selector that matches nothing, or (b) drop the
|
|
98
|
+
* attribute, say so, and start anyway. (b), because the two cases are not
|
|
99
|
+
* alike: a failed `mountTo` would put an unexpected floating bubble on a page
|
|
100
|
+
* built to embed the chat, which reads as a bug and is easy to miss, whereas a
|
|
101
|
+
* failed `theme` leaves a WORKING chat in the default colours plus a named
|
|
102
|
+
* error in the console. Losing support chat on a customer's site over a
|
|
103
|
+
* trailing comma is the worse trade.
|
|
104
|
+
*
|
|
105
|
+
* ── Why not zod ─────────────────────────────────────────────────────────
|
|
106
|
+
*
|
|
107
|
+
* This package ships to a customer's page with zero dependencies, and zod
|
|
108
|
+
* measured ~11KB gzipped when it reached the widget. There is also nothing
|
|
109
|
+
* for it to be the source of truth ABOUT: the widget's `InitOptions` has no
|
|
110
|
+
* runtime schema on either side of this boundary — it is a typed object
|
|
111
|
+
* literal from the host page — and the server validates what actually reaches
|
|
112
|
+
* it (`widgetInitSchema`). So the boundary asserts what it can honestly
|
|
113
|
+
* assert: this parsed, and it is an object rather than an array or a number.
|
|
114
|
+
*/
|
|
115
|
+
function parseJsonAttribute(element, attribute, raw) {
|
|
116
|
+
let parsed;
|
|
117
|
+
try {
|
|
118
|
+
parsed = JSON.parse(raw);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.error(`[Chatly] <${element.localName}> ignored the ${attribute} attribute — it is not valid ` +
|
|
122
|
+
`JSON. The widget still started, without it. ${String(err)}`);
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
126
|
+
console.error(`[Chatly] <${element.localName}> ignored the ${attribute} attribute — JSON parsed to ` +
|
|
127
|
+
`${typeof parsed}, and this attribute must be an object or array.`);
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Define the element, once.
|
|
134
|
+
*
|
|
135
|
+
* Idempotent and safe to call from anywhere: a second call with a tag that is
|
|
136
|
+
* already registered returns quietly instead of throwing
|
|
137
|
+
* `NotSupportedError: the name "chatly-widget" has already been used`, which
|
|
138
|
+
* is what two bundles each importing `/register` would otherwise produce.
|
|
139
|
+
*/
|
|
140
|
+
export function defineChatlyWidget(tagName = CHATLY_WIDGET_TAG) {
|
|
141
|
+
if (typeof window === 'undefined' || typeof customElements === 'undefined') {
|
|
142
|
+
// SSR, or a DOM-less test. Not an error — see the file header.
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (customElements.get(tagName) !== undefined) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
customElements.define(tagName, buildElementClass());
|
|
149
|
+
}
|
|
150
|
+
function buildElementClass() {
|
|
151
|
+
return class ChatlyWidget extends HTMLElement {
|
|
152
|
+
static get observedAttributes() {
|
|
153
|
+
return OBSERVED;
|
|
154
|
+
}
|
|
155
|
+
controls = controls;
|
|
156
|
+
/*
|
|
157
|
+
* Object props are held in a private map rather than as class fields.
|
|
158
|
+
*
|
|
159
|
+
* `useDefineForClassFields` is on in this repo's tsconfig, so a declared
|
|
160
|
+
* field is installed with `Object.defineProperty` in the constructor —
|
|
161
|
+
* which would CLOBBER a value a framework set on the element before it was
|
|
162
|
+
* upgraded (`el.theme = {…}` then `document.body.append(el)`). Accessors
|
|
163
|
+
* on the prototype plus a private store keep the pre-upgrade value.
|
|
164
|
+
*/
|
|
165
|
+
#props = new Map();
|
|
166
|
+
#handle = null;
|
|
167
|
+
constructor() {
|
|
168
|
+
super();
|
|
169
|
+
/*
|
|
170
|
+
* The pre-upgrade property dance.
|
|
171
|
+
*
|
|
172
|
+
* A framework that does `el.theme = {…}` before the element is defined
|
|
173
|
+
* (or before this module loads) creates an OWN data property, which
|
|
174
|
+
* shadows the prototype accessor for good: the setter never runs, the
|
|
175
|
+
* private store stays empty, and the theme is silently dropped. Every
|
|
176
|
+
* template engine that binds properties — Vue, Angular, Lit, Svelte —
|
|
177
|
+
* can produce that ordering, and so can plain `createElement` +
|
|
178
|
+
* `append` on a page whose bundle is still loading.
|
|
179
|
+
*
|
|
180
|
+
* So on upgrade, each own property is lifted off the instance and
|
|
181
|
+
* re-assigned, which this time reaches the accessor.
|
|
182
|
+
*/
|
|
183
|
+
for (const key of PROPERTY_NAMES) {
|
|
184
|
+
if (!Object.prototype.hasOwnProperty.call(this, key)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const value = this[key];
|
|
188
|
+
delete this[key];
|
|
189
|
+
this[key] = value;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
get theme() {
|
|
193
|
+
return this.#props.get('theme');
|
|
194
|
+
}
|
|
195
|
+
set theme(value) {
|
|
196
|
+
this.#setProp('theme', value);
|
|
197
|
+
}
|
|
198
|
+
get behavior() {
|
|
199
|
+
return this.#props.get('behavior');
|
|
200
|
+
}
|
|
201
|
+
set behavior(value) {
|
|
202
|
+
this.#setProp('behavior', value);
|
|
203
|
+
}
|
|
204
|
+
get visitor() {
|
|
205
|
+
return this.#props.get('visitor');
|
|
206
|
+
}
|
|
207
|
+
set visitor(value) {
|
|
208
|
+
this.#setProp('visitor', value);
|
|
209
|
+
}
|
|
210
|
+
get copy() {
|
|
211
|
+
return this.#props.get('copy');
|
|
212
|
+
}
|
|
213
|
+
set copy(value) {
|
|
214
|
+
this.#setProp('copy', value);
|
|
215
|
+
}
|
|
216
|
+
get copyByLocale() {
|
|
217
|
+
return this.#props.get('copyByLocale');
|
|
218
|
+
}
|
|
219
|
+
set copyByLocale(value) {
|
|
220
|
+
this.#setProp('copyByLocale', value);
|
|
221
|
+
}
|
|
222
|
+
get quickLinks() {
|
|
223
|
+
return this.#props.get('quickLinks');
|
|
224
|
+
}
|
|
225
|
+
set quickLinks(value) {
|
|
226
|
+
this.#setProp('quickLinks', value);
|
|
227
|
+
}
|
|
228
|
+
get config() {
|
|
229
|
+
return this.#props.get('config');
|
|
230
|
+
}
|
|
231
|
+
set config(value) {
|
|
232
|
+
this.#setProp('config', value);
|
|
233
|
+
}
|
|
234
|
+
#setProp(key, value) {
|
|
235
|
+
if (value === undefined) {
|
|
236
|
+
this.#props.delete(key);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
this.#props.set(key, value);
|
|
240
|
+
}
|
|
241
|
+
// Only if connected: a property set before the element is in the DOM is
|
|
242
|
+
// configuration, not a change — `connectedCallback` will read it.
|
|
243
|
+
if (this.#handle !== null) {
|
|
244
|
+
this.#handle.update(this.#options(), this.#handlers());
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
connectedCallback() {
|
|
248
|
+
if (this.hasAttribute(INLINE_ATTRIBUTE)) {
|
|
249
|
+
/*
|
|
250
|
+
* The element IS the container in inline mode, and the widget fills
|
|
251
|
+
* what it is given. Without `display: block` a custom element is
|
|
252
|
+
* `display: inline`, which collapses to a zero-height box and renders
|
|
253
|
+
* a chat panel nobody can see — the single most reported mistake with
|
|
254
|
+
* inline mounting, and it looks exactly like the widget not loading.
|
|
255
|
+
*/
|
|
256
|
+
this.style.display = 'block';
|
|
257
|
+
if (this.style.minHeight === '') {
|
|
258
|
+
this.style.minHeight = '420px';
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
this.#handle = startWidget(this, this.#options(), this.#handlers());
|
|
262
|
+
}
|
|
263
|
+
disconnectedCallback() {
|
|
264
|
+
/*
|
|
265
|
+
* A disconnect is not necessarily an unmount: `appendChild` elsewhere in
|
|
266
|
+
* the document fires disconnect then connect, and so does a framework
|
|
267
|
+
* re-keying its list. `startWidget`'s deferred teardown is what makes
|
|
268
|
+
* that survivable — see `release` in embed.ts.
|
|
269
|
+
*/
|
|
270
|
+
this.#handle?.stop();
|
|
271
|
+
this.#handle = null;
|
|
272
|
+
}
|
|
273
|
+
attributeChangedCallback() {
|
|
274
|
+
if (this.#handle === null) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
this.#handle.update(this.#options(), this.#handlers());
|
|
278
|
+
}
|
|
279
|
+
/** Attributes, then properties (which win), then `config` (which wins). */
|
|
280
|
+
#options() {
|
|
281
|
+
const options = {};
|
|
282
|
+
for (const { attribute, option, json } of ATTRIBUTES) {
|
|
283
|
+
const raw = this.getAttribute(attribute);
|
|
284
|
+
if (raw === null) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const value = json === true ? parseJsonAttribute(this, attribute, raw) : raw;
|
|
288
|
+
if (value !== undefined) {
|
|
289
|
+
options[option] = value;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
for (const [key, value] of this.#props) {
|
|
293
|
+
if (key !== 'config') {
|
|
294
|
+
options[key] = value;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
Object.assign(options, this.config ?? {});
|
|
298
|
+
if (this.hasAttribute(INLINE_ATTRIBUTE)) {
|
|
299
|
+
options['mountTo'] = this;
|
|
300
|
+
}
|
|
301
|
+
// `publicId` may legitimately be missing here — the element can be in
|
|
302
|
+
// the DOM before its framework has bound the attribute. `startWidget`
|
|
303
|
+
// warns and declines rather than booting a widget with no channel.
|
|
304
|
+
return options;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Re-dispatch every widget event as a DOM event on this element.
|
|
308
|
+
*
|
|
309
|
+
* Written out rather than generated from `ELEMENT_EVENTS` in a loop: the
|
|
310
|
+
* handler signatures differ (`onOpen` takes nothing, `onReady` a session),
|
|
311
|
+
* and assigning through a string index would need a cast that defeats the
|
|
312
|
+
* one thing the compiler is useful for here — noticing that a handler name
|
|
313
|
+
* in `ChatlyEmbedHandlers` has no `chatly-*` event.
|
|
314
|
+
*/
|
|
315
|
+
#handlers() {
|
|
316
|
+
const emit = (name) => (detail) => {
|
|
317
|
+
this.dispatchEvent(new CustomEvent(`chatly-${name}`, { detail, bubbles: true, composed: true }));
|
|
318
|
+
};
|
|
319
|
+
return {
|
|
320
|
+
onReady: emit('ready'),
|
|
321
|
+
onOpen: emit('open'),
|
|
322
|
+
onClose: emit('close'),
|
|
323
|
+
onMessage: emit('message'),
|
|
324
|
+
onConversation: emit('conversation'),
|
|
325
|
+
onIdentified: emit('identified'),
|
|
326
|
+
onReset: emit('reset'),
|
|
327
|
+
onAction: emit('action'),
|
|
328
|
+
onError: emit('error'),
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"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"}
|