@revvue/embed 0.0.0-beta.3 → 0.0.0-beta.5
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/dist/browser/css/dialog.css +1 -1
- package/dist/browser/css/drawer.css +1 -1
- package/dist/browser/css/popover.css +1 -1
- package/dist/browser/embed.js +2 -2
- package/dist/package/css/dialog.css +1 -1
- package/dist/package/css/drawer.css +1 -1
- package/dist/package/css/popover.css +1 -1
- package/dist/package/package.cjs +278 -105
- package/dist/package/package.mjs +278 -106
- package/dist/package/types/core/app-options.d.ts +3 -2
- package/dist/package/types/core/app-options.d.ts.map +1 -1
- package/dist/package/types/core/button-options.d.ts +13 -0
- package/dist/package/types/core/button-options.d.ts.map +1 -1
- package/dist/package/types/core/common.d.ts +2 -0
- package/dist/package/types/core/common.d.ts.map +1 -1
- package/dist/package/types/core/create-iframe.d.ts +3 -1
- package/dist/package/types/core/create-iframe.d.ts.map +1 -1
- package/dist/package/types/core/embed-types.d.ts +12 -0
- package/dist/package/types/core/embed-types.d.ts.map +1 -1
- package/dist/package/types/core/iframe-messages.d.ts +6 -0
- package/dist/package/types/core/iframe-messages.d.ts.map +1 -0
- package/dist/package/types/factories/create-dialog/create-dialog.d.ts +2 -1
- package/dist/package/types/factories/create-dialog/create-dialog.d.ts.map +1 -1
- package/dist/package/types/factories/create-drawer/create-drawer.d.ts +2 -2
- package/dist/package/types/factories/create-drawer/create-drawer.d.ts.map +1 -1
- package/dist/package/types/factories/create-popover/create-popover.d.ts +2 -1
- package/dist/package/types/factories/create-popover/create-popover.d.ts.map +1 -1
- package/dist/package/types/factories/create-widget/create-widget.d.ts +2 -1
- package/dist/package/types/factories/create-widget/create-widget.d.ts.map +1 -1
- package/dist/package/types/package.d.ts +1 -0
- package/dist/package/types/package.d.ts.map +1 -1
- package/dist/package/types/utils/brand-types.d.ts +7 -0
- package/dist/package/types/utils/brand-types.d.ts.map +1 -1
- package/dist/package/types/utils/built-button/built-button.d.ts.map +1 -1
- package/dist/package/types/utils/create-closing-guard.d.ts +6 -0
- package/dist/package/types/utils/create-closing-guard.d.ts.map +1 -0
- package/dist/package/types/utils/icons.d.ts +3 -0
- package/dist/package/types/utils/icons.d.ts.map +1 -0
- package/dist/package/types/utils/open-state-store/index.d.ts +2 -0
- package/dist/package/types/utils/open-state-store/index.d.ts.map +1 -0
- package/dist/package/types/utils/open-state-store/open-state-store.d.ts +18 -0
- package/dist/package/types/utils/open-state-store/open-state-store.d.ts.map +1 -0
- package/dist/package/types/utils/open-state-store/open-state-store.spec.d.ts +2 -0
- package/dist/package/types/utils/open-state-store/open-state-store.spec.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/package/package.mjs
CHANGED
|
@@ -2,6 +2,51 @@
|
|
|
2
2
|
var tenantId = (id) => id;
|
|
3
3
|
var formId = (id) => id;
|
|
4
4
|
var embedId = (id) => id;
|
|
5
|
+
var integrationProfileId = (id) => id;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/utils/create-env.ts
|
|
8
|
+
function createEnv(schema, source = {}) {
|
|
9
|
+
const result = {};
|
|
10
|
+
for (const key in schema) {
|
|
11
|
+
const field = schema[key];
|
|
12
|
+
const raw = source[key];
|
|
13
|
+
if (raw !== void 0) result[key] = field.parse ? field.parse(raw) : raw;
|
|
14
|
+
else if (field.default !== void 0) result[key] = field.default;
|
|
15
|
+
else if (field.required) throw new Error(`[embed] Missing required env variable: ${key}`);
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/config/env.ts
|
|
21
|
+
var removeTrailingSlash = (url) => url.replace(/\/$/, "");
|
|
22
|
+
var env = createEnv({
|
|
23
|
+
CHAT_URL: {
|
|
24
|
+
default: "https://app.revvue.ai/chat",
|
|
25
|
+
parse: removeTrailingSlash
|
|
26
|
+
},
|
|
27
|
+
FORM_URL: {
|
|
28
|
+
default: "https://app.revvue.ai/survey",
|
|
29
|
+
parse: removeTrailingSlash
|
|
30
|
+
},
|
|
31
|
+
CDN_URL: {
|
|
32
|
+
default: "https://cdn.revvue.ai/v1",
|
|
33
|
+
parse: removeTrailingSlash
|
|
34
|
+
},
|
|
35
|
+
EMBED_LOOKUP_URL: {
|
|
36
|
+
default: "https://app.revvue.ai/api/v1/embeds",
|
|
37
|
+
parse: removeTrailingSlash
|
|
38
|
+
},
|
|
39
|
+
DEBUG: {
|
|
40
|
+
default: false,
|
|
41
|
+
parse: (v) => v === "true"
|
|
42
|
+
}
|
|
43
|
+
}, {
|
|
44
|
+
"BASE_URL": "/",
|
|
45
|
+
"DEV": false,
|
|
46
|
+
"MODE": "production",
|
|
47
|
+
"PROD": true,
|
|
48
|
+
"SSR": false
|
|
49
|
+
});
|
|
5
50
|
//#endregion
|
|
6
51
|
//#region src/utils/refresh-iframe.ts
|
|
7
52
|
function refreshIframe(iframe) {
|
|
@@ -16,12 +61,21 @@ function refreshIframe(iframe) {
|
|
|
16
61
|
}
|
|
17
62
|
}
|
|
18
63
|
//#endregion
|
|
64
|
+
//#region src/core/iframe-messages.ts
|
|
65
|
+
var IFRAME_MESSAGES = {
|
|
66
|
+
close: "rvv-embed-close",
|
|
67
|
+
focus: "rvv-embed-focus"
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
19
70
|
//#region src/core/create-iframe.ts
|
|
20
|
-
function getIframeSrc() {
|
|
21
|
-
|
|
71
|
+
function getIframeSrc(options) {
|
|
72
|
+
const base = options.app === "chat" ? env.CHAT_URL : env.FORM_URL;
|
|
73
|
+
const params = new URLSearchParams({ tenant_id: options.tenantId });
|
|
74
|
+
if (options.app === "chat") params.set("integration_profile_id", options.integrationProfileId);
|
|
75
|
+
return `${base}?${params}`;
|
|
22
76
|
}
|
|
23
|
-
function createIframe(
|
|
24
|
-
const src = getIframeSrc();
|
|
77
|
+
function createIframe(options) {
|
|
78
|
+
const src = getIframeSrc(options);
|
|
25
79
|
const embedId = crypto.randomUUID();
|
|
26
80
|
const iframe = document.createElement("iframe");
|
|
27
81
|
iframe.src = src;
|
|
@@ -31,13 +85,52 @@ function createIframe(_options) {
|
|
|
31
85
|
iframe.id = embedId;
|
|
32
86
|
const refresh = () => refreshIframe(iframe);
|
|
33
87
|
const focus = () => {
|
|
34
|
-
iframe.contentWindow?.postMessage(
|
|
88
|
+
iframe.contentWindow?.postMessage(IFRAME_MESSAGES.focus, "*");
|
|
89
|
+
};
|
|
90
|
+
const onMessage = (handler) => {
|
|
91
|
+
const listener = (event) => {
|
|
92
|
+
if (event.source !== iframe.contentWindow) return;
|
|
93
|
+
handler(event.data);
|
|
94
|
+
};
|
|
95
|
+
window.addEventListener("message", listener);
|
|
96
|
+
return () => window.removeEventListener("message", listener);
|
|
35
97
|
};
|
|
36
98
|
return {
|
|
37
99
|
iframe,
|
|
38
100
|
focus,
|
|
39
101
|
refresh,
|
|
40
|
-
embedId
|
|
102
|
+
embedId,
|
|
103
|
+
onMessage
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/utils/create-closing-guard.ts
|
|
108
|
+
function createClosingGuard() {
|
|
109
|
+
let cancelClose = null;
|
|
110
|
+
function isClosing() {
|
|
111
|
+
return cancelClose !== null;
|
|
112
|
+
}
|
|
113
|
+
function scheduleClose(element, onDone) {
|
|
114
|
+
const abortController = new AbortController();
|
|
115
|
+
element.addEventListener("transitionend", () => {
|
|
116
|
+
cancelClose = null;
|
|
117
|
+
onDone();
|
|
118
|
+
}, {
|
|
119
|
+
signal: abortController.signal,
|
|
120
|
+
once: true
|
|
121
|
+
});
|
|
122
|
+
cancelClose = () => {
|
|
123
|
+
abortController.abort();
|
|
124
|
+
cancelClose = null;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function cancelPendingClose() {
|
|
128
|
+
cancelClose?.();
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
isClosing,
|
|
132
|
+
scheduleClose,
|
|
133
|
+
cancelPendingClose
|
|
41
134
|
};
|
|
42
135
|
}
|
|
43
136
|
//#endregion
|
|
@@ -72,6 +165,26 @@ function onEscape(callback) {
|
|
|
72
165
|
});
|
|
73
166
|
}
|
|
74
167
|
//#endregion
|
|
168
|
+
//#region src/utils/open-state-store/open-state-store.ts
|
|
169
|
+
function createOpenStateStore(initial = false) {
|
|
170
|
+
let state = initial;
|
|
171
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
172
|
+
return {
|
|
173
|
+
getState: () => state,
|
|
174
|
+
setState(next) {
|
|
175
|
+
if (state === next) return;
|
|
176
|
+
state = next;
|
|
177
|
+
for (const listener of listeners) listener();
|
|
178
|
+
},
|
|
179
|
+
subscribe(listener) {
|
|
180
|
+
listeners.add(listener);
|
|
181
|
+
return () => {
|
|
182
|
+
listeners.delete(listener);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
75
188
|
//#region src/utils/set-element-size.ts
|
|
76
189
|
var getValueWithUnits = (value) => {
|
|
77
190
|
if (typeof value === "string" && !value.match(/^[0-9]+$/)) return value;
|
|
@@ -84,6 +197,7 @@ var setElementSize = (element, { width, height }) => {
|
|
|
84
197
|
};
|
|
85
198
|
//#endregion
|
|
86
199
|
//#region src/factories/create-dialog/create-dialog.ts
|
|
200
|
+
var noop$3 = () => {};
|
|
87
201
|
function createDialogElement() {
|
|
88
202
|
const container = document.createElement("dialog");
|
|
89
203
|
container.classList.add("rvv-dialog");
|
|
@@ -98,15 +212,18 @@ function unmountElement$2(element) {
|
|
|
98
212
|
element.remove();
|
|
99
213
|
}
|
|
100
214
|
function createDialog(options, element) {
|
|
215
|
+
const store = createOpenStateStore();
|
|
101
216
|
if (!is.browser()) return {
|
|
102
|
-
toggle:
|
|
103
|
-
open:
|
|
104
|
-
close:
|
|
105
|
-
unmount:
|
|
106
|
-
refresh:
|
|
107
|
-
focus:
|
|
217
|
+
toggle: noop$3,
|
|
218
|
+
open: noop$3,
|
|
219
|
+
close: noop$3,
|
|
220
|
+
unmount: noop$3,
|
|
221
|
+
refresh: noop$3,
|
|
222
|
+
focus: noop$3,
|
|
223
|
+
isOpen: store.getState,
|
|
224
|
+
subscribe: store.subscribe
|
|
108
225
|
};
|
|
109
|
-
const { iframe, refresh, focus } = createIframe(options);
|
|
226
|
+
const { iframe, refresh, focus, onMessage } = createIframe(options);
|
|
110
227
|
const container = element ?? document.body;
|
|
111
228
|
const dialog = createDialogElement();
|
|
112
229
|
const wrapper = createDialogWrapper();
|
|
@@ -122,21 +239,35 @@ function createDialog(options, element) {
|
|
|
122
239
|
onEscape(close);
|
|
123
240
|
}
|
|
124
241
|
};
|
|
242
|
+
const guard = createClosingGuard();
|
|
125
243
|
function open() {
|
|
126
|
-
if (is.open(wrapper))
|
|
244
|
+
if (is.open(wrapper)) {
|
|
245
|
+
if (guard.isClosing()) {
|
|
246
|
+
guard.cancelPendingClose();
|
|
247
|
+
store.setState(true);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
127
252
|
dialog.append(wrapper);
|
|
128
253
|
dialog.showModal();
|
|
254
|
+
store.setState(true);
|
|
129
255
|
}
|
|
130
256
|
function close() {
|
|
131
257
|
if (!is.open(wrapper)) return;
|
|
132
258
|
dialog.close();
|
|
133
|
-
unmountElement$2(wrapper);
|
|
259
|
+
guard.scheduleClose(dialog, () => unmountElement$2(wrapper));
|
|
260
|
+
store.setState(false);
|
|
134
261
|
}
|
|
135
262
|
function toggle() {
|
|
136
263
|
is.open(wrapper) ? close() : open();
|
|
137
264
|
}
|
|
265
|
+
const removeOnMessageHandler = onMessage((msg) => {
|
|
266
|
+
if (msg === IFRAME_MESSAGES.close) close();
|
|
267
|
+
});
|
|
138
268
|
function unmount() {
|
|
139
269
|
unmountElement$2(dialog);
|
|
270
|
+
removeOnMessageHandler();
|
|
140
271
|
}
|
|
141
272
|
return {
|
|
142
273
|
toggle,
|
|
@@ -144,59 +275,14 @@ function createDialog(options, element) {
|
|
|
144
275
|
close,
|
|
145
276
|
unmount,
|
|
146
277
|
refresh,
|
|
147
|
-
focus
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
//#endregion
|
|
151
|
-
//#region src/utils/built-button/built-button.ts
|
|
152
|
-
var defaultIcon = `
|
|
153
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-square-icon lucide-message-square"><path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/></svg>`;
|
|
154
|
-
var closeIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>`;
|
|
155
|
-
function buildDefaultIcons() {
|
|
156
|
-
const openEl = document.createElement("span");
|
|
157
|
-
openEl.classList.add("rvv-button-icon--open");
|
|
158
|
-
openEl.innerHTML = defaultIcon;
|
|
159
|
-
const closeEl = document.createElement("span");
|
|
160
|
-
closeEl.classList.add("rvv-button-icon--close");
|
|
161
|
-
closeEl.innerHTML = closeIcon;
|
|
162
|
-
return {
|
|
163
|
-
openEl,
|
|
164
|
-
closeEl
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
function buildButtonElement(options) {
|
|
168
|
-
const button = document.createElement("button");
|
|
169
|
-
button.classList.add("rvv-button", "rvv-button--trigger");
|
|
170
|
-
button.setAttribute("type", "button");
|
|
171
|
-
button.dataset.position = options.position ?? "right";
|
|
172
|
-
button.dataset.open = "false";
|
|
173
|
-
if (options.color) button.style.setProperty("--rvv-button-color", options.color);
|
|
174
|
-
if (options.textColor) button.style.setProperty("--rvv-button-text-color", options.textColor);
|
|
175
|
-
const iconWrapper = document.createElement("span");
|
|
176
|
-
iconWrapper.classList.add("rvv-button-icon");
|
|
177
|
-
iconWrapper.setAttribute("aria-hidden", "true");
|
|
178
|
-
if (options.label) {
|
|
179
|
-
const labelEl = document.createElement("span");
|
|
180
|
-
labelEl.classList.add("rvv-button-label");
|
|
181
|
-
labelEl.textContent = options.label;
|
|
182
|
-
button.append(labelEl);
|
|
183
|
-
}
|
|
184
|
-
if (options.icon) iconWrapper.innerHTML = options.icon;
|
|
185
|
-
else if (!options.label) {
|
|
186
|
-
const { openEl, closeEl } = buildDefaultIcons();
|
|
187
|
-
iconWrapper.append(openEl, closeEl);
|
|
188
|
-
}
|
|
189
|
-
if (iconWrapper.childNodes.length > 0) button.append(iconWrapper);
|
|
190
|
-
function setOpen(isOpen) {
|
|
191
|
-
button.dataset.open = String(isOpen);
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
el: button,
|
|
195
|
-
setOpen
|
|
278
|
+
focus,
|
|
279
|
+
isOpen: store.getState,
|
|
280
|
+
subscribe: store.subscribe
|
|
196
281
|
};
|
|
197
282
|
}
|
|
198
283
|
//#endregion
|
|
199
284
|
//#region src/factories/create-drawer/create-drawer.ts
|
|
285
|
+
var noop$2 = () => {};
|
|
200
286
|
function createDrawerElement() {
|
|
201
287
|
const container = document.createElement("div");
|
|
202
288
|
container.classList.add("rvv-drawer");
|
|
@@ -211,15 +297,18 @@ function unmountElement$1(element) {
|
|
|
211
297
|
element.remove();
|
|
212
298
|
}
|
|
213
299
|
function createDrawer(options, element) {
|
|
300
|
+
const store = createOpenStateStore();
|
|
214
301
|
if (!is.browser()) return {
|
|
215
|
-
toggle:
|
|
216
|
-
open:
|
|
217
|
-
close:
|
|
218
|
-
unmount:
|
|
219
|
-
refresh:
|
|
220
|
-
focus:
|
|
302
|
+
toggle: noop$2,
|
|
303
|
+
open: noop$2,
|
|
304
|
+
close: noop$2,
|
|
305
|
+
unmount: noop$2,
|
|
306
|
+
refresh: noop$2,
|
|
307
|
+
focus: noop$2,
|
|
308
|
+
isOpen: store.getState,
|
|
309
|
+
subscribe: store.subscribe
|
|
221
310
|
};
|
|
222
|
-
const { iframe, refresh, focus } = createIframe(options);
|
|
311
|
+
const { iframe, refresh, focus, onMessage } = createIframe(options);
|
|
223
312
|
const container = element ?? document.body;
|
|
224
313
|
const drawer = createDrawerElement();
|
|
225
314
|
const wrapper = createDrawerWrapper();
|
|
@@ -229,49 +318,106 @@ function createDrawer(options, element) {
|
|
|
229
318
|
});
|
|
230
319
|
container.append(drawer);
|
|
231
320
|
wrapper.append(iframe);
|
|
232
|
-
const { autoOpen = false, autoOpenDelay = 0 } = options;
|
|
233
|
-
let setButtonOpen = () => {};
|
|
234
|
-
const { el: buttonEl, setOpen } = buildButtonElement(options);
|
|
235
|
-
setButtonOpen = setOpen;
|
|
236
|
-
buttonEl.addEventListener("click", () => toggle());
|
|
237
|
-
document.body.append(buttonEl);
|
|
238
321
|
iframe.onload = (event) => {
|
|
239
322
|
if (event?.isTrusted) {
|
|
240
323
|
drawer.classList.add("open");
|
|
241
324
|
onEscape(close);
|
|
242
325
|
}
|
|
243
326
|
};
|
|
327
|
+
const guard = createClosingGuard();
|
|
244
328
|
function open() {
|
|
245
|
-
if (is.open(wrapper))
|
|
329
|
+
if (is.open(wrapper)) {
|
|
330
|
+
if (guard.isClosing()) {
|
|
331
|
+
guard.cancelPendingClose();
|
|
332
|
+
drawer.classList.add("open");
|
|
333
|
+
store.setState(true);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
246
338
|
drawer.append(wrapper);
|
|
247
|
-
|
|
339
|
+
store.setState(true);
|
|
248
340
|
}
|
|
249
341
|
function close() {
|
|
250
342
|
if (!is.open(wrapper)) return;
|
|
251
|
-
unmountElement$1(wrapper);
|
|
252
343
|
drawer.classList.remove("open");
|
|
253
|
-
|
|
344
|
+
store.setState(false);
|
|
345
|
+
guard.scheduleClose(drawer, () => unmountElement$1(wrapper));
|
|
254
346
|
}
|
|
255
347
|
function toggle() {
|
|
256
348
|
is.open(wrapper) ? close() : open();
|
|
257
349
|
}
|
|
350
|
+
const removeOnMessageHandler = onMessage((msg) => {
|
|
351
|
+
if (msg === IFRAME_MESSAGES.close) close();
|
|
352
|
+
});
|
|
258
353
|
function unmount() {
|
|
259
|
-
buttonEl?.remove();
|
|
260
354
|
unmountElement$1(drawer);
|
|
355
|
+
removeOnMessageHandler();
|
|
261
356
|
}
|
|
262
|
-
if (autoOpen) if (autoOpenDelay > 0) setTimeout(() => open(), autoOpenDelay);
|
|
263
|
-
else open();
|
|
264
357
|
return {
|
|
265
358
|
toggle,
|
|
266
359
|
open,
|
|
267
360
|
close,
|
|
268
361
|
unmount,
|
|
269
362
|
refresh,
|
|
270
|
-
focus
|
|
363
|
+
focus,
|
|
364
|
+
isOpen: store.getState,
|
|
365
|
+
subscribe: store.subscribe
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/utils/icons.ts
|
|
370
|
+
var chatIcon = `
|
|
371
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-square-icon lucide-message-square"><path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/></svg>`;
|
|
372
|
+
var closeIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>`;
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/utils/built-button/built-button.ts
|
|
375
|
+
function buildDefaultIcons() {
|
|
376
|
+
const openEl = document.createElement("span");
|
|
377
|
+
openEl.classList.add("rvv-button-icon--open");
|
|
378
|
+
openEl.innerHTML = chatIcon;
|
|
379
|
+
const closeEl = document.createElement("span");
|
|
380
|
+
closeEl.classList.add("rvv-button-icon--close");
|
|
381
|
+
closeEl.innerHTML = closeIcon;
|
|
382
|
+
return {
|
|
383
|
+
openEl,
|
|
384
|
+
closeEl
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function buildButtonElement(options) {
|
|
388
|
+
const button = document.createElement("button");
|
|
389
|
+
button.classList.add("rvv-button", "rvv-button--trigger");
|
|
390
|
+
button.setAttribute("type", "button");
|
|
391
|
+
button.dataset.position = options.position ?? "right";
|
|
392
|
+
button.dataset.open = "false";
|
|
393
|
+
if (options.color) button.style.setProperty("--rvv-button-color", options.color);
|
|
394
|
+
if (options.textColor) button.style.setProperty("--rvv-button-text-color", options.textColor);
|
|
395
|
+
const iconWrapper = document.createElement("span");
|
|
396
|
+
iconWrapper.classList.add("rvv-button-icon");
|
|
397
|
+
iconWrapper.setAttribute("aria-hidden", "true");
|
|
398
|
+
if (options.label) {
|
|
399
|
+
const labelEl = document.createElement("span");
|
|
400
|
+
labelEl.classList.add("rvv-button-label");
|
|
401
|
+
labelEl.textContent = options.label;
|
|
402
|
+
button.append(labelEl);
|
|
403
|
+
}
|
|
404
|
+
if (options.icon) iconWrapper.innerHTML = options.icon;
|
|
405
|
+
else if (!options.label) {
|
|
406
|
+
const { openEl, closeEl } = buildDefaultIcons();
|
|
407
|
+
iconWrapper.append(openEl, closeEl);
|
|
408
|
+
}
|
|
409
|
+
if (iconWrapper.childNodes.length > 0) button.append(iconWrapper);
|
|
410
|
+
function setOpen(isOpen) {
|
|
411
|
+
button.dataset.open = String(isOpen);
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
el: button,
|
|
415
|
+
setOpen
|
|
271
416
|
};
|
|
272
417
|
}
|
|
273
418
|
//#endregion
|
|
274
419
|
//#region src/factories/create-popover/create-popover.ts
|
|
420
|
+
var noop$1 = () => {};
|
|
275
421
|
function createPopoverElement() {
|
|
276
422
|
const container = document.createElement("div");
|
|
277
423
|
container.classList.add("rvv-popover");
|
|
@@ -286,15 +432,18 @@ function unmountElement(element) {
|
|
|
286
432
|
element.remove();
|
|
287
433
|
}
|
|
288
434
|
function createPopover(options, element) {
|
|
435
|
+
const store = createOpenStateStore();
|
|
289
436
|
if (!is.browser()) return {
|
|
290
|
-
toggle:
|
|
291
|
-
close:
|
|
292
|
-
open:
|
|
293
|
-
unmount:
|
|
294
|
-
refresh:
|
|
295
|
-
focus:
|
|
437
|
+
toggle: noop$1,
|
|
438
|
+
close: noop$1,
|
|
439
|
+
open: noop$1,
|
|
440
|
+
unmount: noop$1,
|
|
441
|
+
refresh: noop$1,
|
|
442
|
+
focus: noop$1,
|
|
443
|
+
isOpen: store.getState,
|
|
444
|
+
subscribe: store.subscribe
|
|
296
445
|
};
|
|
297
|
-
const { iframe, refresh, focus } = createIframe(options);
|
|
446
|
+
const { iframe, refresh, focus, onMessage } = createIframe(options);
|
|
298
447
|
const container = element ?? document.body;
|
|
299
448
|
const popover = createPopoverElement();
|
|
300
449
|
const wrapper = createPopoverWrapper();
|
|
@@ -304,12 +453,17 @@ function createPopover(options, element) {
|
|
|
304
453
|
});
|
|
305
454
|
container.append(popover);
|
|
306
455
|
wrapper.append(iframe);
|
|
307
|
-
const { autoOpen = false, autoOpenDelay = 0 } = options;
|
|
308
|
-
let setButtonOpen =
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
456
|
+
const { autoOpen = false, autoOpenDelay = 0, trigger = "default" } = options;
|
|
457
|
+
let setButtonOpen = noop$1;
|
|
458
|
+
let unmountButton = noop$1;
|
|
459
|
+
if (trigger === "default") {
|
|
460
|
+
const { el: buttonEl, setOpen } = buildButtonElement(options);
|
|
461
|
+
buttonEl.classList.add("rvv-button--trigger-popover");
|
|
462
|
+
setButtonOpen = setOpen;
|
|
463
|
+
buttonEl.addEventListener("click", () => toggle());
|
|
464
|
+
document.body.append(buttonEl);
|
|
465
|
+
unmountButton = () => buttonEl.remove();
|
|
466
|
+
}
|
|
313
467
|
function toggle() {
|
|
314
468
|
is.open(wrapper) ? close() : open();
|
|
315
469
|
}
|
|
@@ -319,20 +473,35 @@ function createPopover(options, element) {
|
|
|
319
473
|
onEscape(close);
|
|
320
474
|
}
|
|
321
475
|
};
|
|
476
|
+
const guard = createClosingGuard();
|
|
322
477
|
function open() {
|
|
323
|
-
if (is.open(wrapper))
|
|
478
|
+
if (is.open(wrapper)) {
|
|
479
|
+
if (guard.isClosing()) {
|
|
480
|
+
guard.cancelPendingClose();
|
|
481
|
+
popover.classList.add("open");
|
|
482
|
+
store.setState(true);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
324
487
|
popover.append(wrapper);
|
|
325
488
|
setButtonOpen(true);
|
|
489
|
+
store.setState(true);
|
|
326
490
|
}
|
|
327
491
|
function close() {
|
|
328
492
|
if (!is.open(wrapper)) return;
|
|
329
493
|
popover.classList.remove("open");
|
|
330
494
|
setButtonOpen(false);
|
|
331
|
-
|
|
495
|
+
store.setState(false);
|
|
496
|
+
guard.scheduleClose(popover, () => unmountElement(wrapper));
|
|
332
497
|
}
|
|
498
|
+
const removeOnMessageHandler = onMessage((msg) => {
|
|
499
|
+
if (msg === IFRAME_MESSAGES.close) close();
|
|
500
|
+
});
|
|
333
501
|
function unmount() {
|
|
334
|
-
|
|
502
|
+
unmountButton();
|
|
335
503
|
unmountElement(popover);
|
|
504
|
+
removeOnMessageHandler();
|
|
336
505
|
}
|
|
337
506
|
if (autoOpen) if (autoOpenDelay > 0) setTimeout(() => open(), autoOpenDelay);
|
|
338
507
|
else open();
|
|
@@ -342,16 +511,19 @@ function createPopover(options, element) {
|
|
|
342
511
|
open,
|
|
343
512
|
unmount,
|
|
344
513
|
refresh,
|
|
345
|
-
focus
|
|
514
|
+
focus,
|
|
515
|
+
isOpen: store.getState,
|
|
516
|
+
subscribe: store.subscribe
|
|
346
517
|
};
|
|
347
518
|
}
|
|
348
519
|
//#endregion
|
|
349
520
|
//#region src/factories/create-widget/create-widget.ts
|
|
521
|
+
var noop = () => {};
|
|
350
522
|
function createWidget(options, element) {
|
|
351
523
|
if (!is.browser()) return {
|
|
352
|
-
unmount:
|
|
353
|
-
refresh:
|
|
354
|
-
focus:
|
|
524
|
+
unmount: noop,
|
|
525
|
+
refresh: noop,
|
|
526
|
+
focus: noop
|
|
355
527
|
};
|
|
356
528
|
const { iframe, refresh, focus } = createIframe(options);
|
|
357
529
|
const container = element ?? document.body;
|
|
@@ -373,4 +545,4 @@ function createWidget(options, element) {
|
|
|
373
545
|
};
|
|
374
546
|
}
|
|
375
547
|
//#endregion
|
|
376
|
-
export { createDialog, createDrawer, createPopover, createWidget, embedId, formId, tenantId };
|
|
548
|
+
export { createDialog, createDrawer, createPopover, createWidget, embedId, formId, integrationProfileId, tenantId };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { AppearanceOptions } from './appearance-options';
|
|
2
|
-
import { TenantId } from './common';
|
|
2
|
+
import { IntegrationProfileId, TenantId } from './common';
|
|
3
3
|
import { AppKind } from './embed-apps';
|
|
4
4
|
import { EmbedType } from './embed-types';
|
|
5
5
|
export interface BaseEmbedOptions {
|
|
6
|
-
|
|
6
|
+
tenantId: TenantId;
|
|
7
7
|
type: EmbedType;
|
|
8
8
|
app: AppKind;
|
|
9
9
|
}
|
|
10
10
|
export interface ChatOptions extends BaseEmbedOptions, AppearanceOptions {
|
|
11
11
|
app: "chat";
|
|
12
|
+
integrationProfileId: IntegrationProfileId;
|
|
12
13
|
}
|
|
13
14
|
export interface FormOptions extends BaseEmbedOptions, AppearanceOptions {
|
|
14
15
|
app: "form";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-options.d.ts","sourceRoot":"","sources":["../../../../src/core/app-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"app-options.d.ts","sourceRoot":"","sources":["../../../../src/core/app-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB,EAAE,iBAAiB;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB,EAAE,oBAAoB,CAAC;CAC5C;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB,EAAE,iBAAiB;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC"}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
export interface ButtonOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Controls whether the factory mounts its own default trigger button.
|
|
4
|
+
*
|
|
5
|
+
* - `"default"` (default): the factory builds and appends a styled `<button>`
|
|
6
|
+
* to `document.body`. This is the right choice for vanilla CDN consumers.
|
|
7
|
+
* - `"none"`: the factory skips button creation entirely. The consumer is
|
|
8
|
+
* responsible for rendering their own trigger and wiring it to
|
|
9
|
+
* `open()` / `close()` / `toggle()`. Use this in React or any framework
|
|
10
|
+
* that wants to own the trigger element.
|
|
11
|
+
*
|
|
12
|
+
* @default "default"
|
|
13
|
+
*/
|
|
14
|
+
trigger?: "default" | "none";
|
|
2
15
|
/**
|
|
3
16
|
* Text label displayed inside the button.
|
|
4
17
|
* @default "Open"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button-options.d.ts","sourceRoot":"","sources":["../../../../src/core/button-options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE5B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
1
|
+
{"version":3,"file":"button-options.d.ts","sourceRoot":"","sources":["../../../../src/core/button-options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAE7B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE5B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -2,7 +2,9 @@ import { Brand } from '../utils/brand-types';
|
|
|
2
2
|
export type TenantId = Brand<string, "TenantId">;
|
|
3
3
|
export type FormId = Brand<string, "FormId">;
|
|
4
4
|
export type EmbedId = Brand<string, "EmbedId">;
|
|
5
|
+
export type IntegrationProfileId = Brand<string, "IntegrationProfileId">;
|
|
5
6
|
export declare const tenantId: (id: string) => TenantId;
|
|
6
7
|
export declare const formId: (id: string) => FormId;
|
|
7
8
|
export declare const embedId: (id: string) => EmbedId;
|
|
9
|
+
export declare const integrationProfileId: (id: string) => IntegrationProfileId;
|
|
8
10
|
//# sourceMappingURL=common.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../src/core/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACjD,MAAM,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC7C,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../src/core/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACjD,MAAM,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC7C,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC/C,MAAM,MAAM,oBAAoB,GAAG,KAAK,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;AAEzE,eAAO,MAAM,QAAQ,GAAI,IAAI,MAAM,KAAG,QAA0B,CAAC;AACjE,eAAO,MAAM,MAAM,GAAI,IAAI,MAAM,KAAG,MAAsB,CAAC;AAC3D,eAAO,MAAM,OAAO,GAAI,IAAI,MAAM,KAAG,OAAwB,CAAC;AAC9D,eAAO,MAAM,oBAAoB,GAAI,IAAI,MAAM,KAAG,oBAAkD,CAAC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { EmbedOptions } from './app-options';
|
|
2
|
+
import { IframeMessage } from './iframe-messages';
|
|
2
3
|
type CreateIframeOptions = {} & EmbedOptions;
|
|
3
|
-
export declare function createIframe(
|
|
4
|
+
export declare function createIframe(options: CreateIframeOptions): {
|
|
4
5
|
iframe: HTMLIFrameElement;
|
|
5
6
|
focus: () => void;
|
|
6
7
|
refresh: () => void;
|
|
7
8
|
embedId: `${string}-${string}-${string}-${string}-${string}`;
|
|
9
|
+
onMessage: (handler: (message: IframeMessage) => void) => (() => void);
|
|
8
10
|
};
|
|
9
11
|
export {};
|
|
10
12
|
//# sourceMappingURL=create-iframe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-iframe.d.ts","sourceRoot":"","sources":["../../../../src/core/create-iframe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-iframe.d.ts","sourceRoot":"","sources":["../../../../src/core/create-iframe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAExE,KAAK,mBAAmB,GAAG,EAAE,GAAG,YAAY,CAAC;AAW7C,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB;;;;;yBAmB3B,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC;EAU5E"}
|
|
@@ -4,9 +4,21 @@ export type EmbedWidget = {
|
|
|
4
4
|
refresh: () => void;
|
|
5
5
|
focus: () => void;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Subscriber callback signature compatible with React's `useSyncExternalStore`.
|
|
9
|
+
* The store calls every registered listener whenever open state flips.
|
|
10
|
+
*/
|
|
11
|
+
export type EmbedStateListener = () => void;
|
|
7
12
|
export type EmbedFloating = EmbedWidget & {
|
|
8
13
|
open: () => void;
|
|
9
14
|
close: () => void;
|
|
10
15
|
toggle: () => void;
|
|
16
|
+
/** Returns the current open state synchronously. Stable reference. */
|
|
17
|
+
isOpen: () => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Register a listener that fires after every open/close transition.
|
|
20
|
+
* Returns an unsubscribe function. Compatible with `useSyncExternalStore`.
|
|
21
|
+
*/
|
|
22
|
+
subscribe: (listener: EmbedStateListener) => () => void;
|
|
11
23
|
};
|
|
12
24
|
//# sourceMappingURL=embed-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed-types.d.ts","sourceRoot":"","sources":["../../../../src/core/embed-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG;IACxC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"embed-types.d.ts","sourceRoot":"","sources":["../../../../src/core/embed-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC;AAE5C,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG;IACxC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,sEAAsE;IACtE,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,MAAM,IAAI,CAAC;CACzD,CAAC"}
|