@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.
Files changed (45) hide show
  1. package/dist/browser/css/dialog.css +1 -1
  2. package/dist/browser/css/drawer.css +1 -1
  3. package/dist/browser/css/popover.css +1 -1
  4. package/dist/browser/embed.js +2 -2
  5. package/dist/package/css/dialog.css +1 -1
  6. package/dist/package/css/drawer.css +1 -1
  7. package/dist/package/css/popover.css +1 -1
  8. package/dist/package/package.cjs +278 -105
  9. package/dist/package/package.mjs +278 -106
  10. package/dist/package/types/core/app-options.d.ts +3 -2
  11. package/dist/package/types/core/app-options.d.ts.map +1 -1
  12. package/dist/package/types/core/button-options.d.ts +13 -0
  13. package/dist/package/types/core/button-options.d.ts.map +1 -1
  14. package/dist/package/types/core/common.d.ts +2 -0
  15. package/dist/package/types/core/common.d.ts.map +1 -1
  16. package/dist/package/types/core/create-iframe.d.ts +3 -1
  17. package/dist/package/types/core/create-iframe.d.ts.map +1 -1
  18. package/dist/package/types/core/embed-types.d.ts +12 -0
  19. package/dist/package/types/core/embed-types.d.ts.map +1 -1
  20. package/dist/package/types/core/iframe-messages.d.ts +6 -0
  21. package/dist/package/types/core/iframe-messages.d.ts.map +1 -0
  22. package/dist/package/types/factories/create-dialog/create-dialog.d.ts +2 -1
  23. package/dist/package/types/factories/create-dialog/create-dialog.d.ts.map +1 -1
  24. package/dist/package/types/factories/create-drawer/create-drawer.d.ts +2 -2
  25. package/dist/package/types/factories/create-drawer/create-drawer.d.ts.map +1 -1
  26. package/dist/package/types/factories/create-popover/create-popover.d.ts +2 -1
  27. package/dist/package/types/factories/create-popover/create-popover.d.ts.map +1 -1
  28. package/dist/package/types/factories/create-widget/create-widget.d.ts +2 -1
  29. package/dist/package/types/factories/create-widget/create-widget.d.ts.map +1 -1
  30. package/dist/package/types/package.d.ts +1 -0
  31. package/dist/package/types/package.d.ts.map +1 -1
  32. package/dist/package/types/utils/brand-types.d.ts +7 -0
  33. package/dist/package/types/utils/brand-types.d.ts.map +1 -1
  34. package/dist/package/types/utils/built-button/built-button.d.ts.map +1 -1
  35. package/dist/package/types/utils/create-closing-guard.d.ts +6 -0
  36. package/dist/package/types/utils/create-closing-guard.d.ts.map +1 -0
  37. package/dist/package/types/utils/icons.d.ts +3 -0
  38. package/dist/package/types/utils/icons.d.ts.map +1 -0
  39. package/dist/package/types/utils/open-state-store/index.d.ts +2 -0
  40. package/dist/package/types/utils/open-state-store/index.d.ts.map +1 -0
  41. package/dist/package/types/utils/open-state-store/open-state-store.d.ts +18 -0
  42. package/dist/package/types/utils/open-state-store/open-state-store.d.ts.map +1 -0
  43. package/dist/package/types/utils/open-state-store/open-state-store.spec.d.ts +2 -0
  44. package/dist/package/types/utils/open-state-store/open-state-store.spec.d.ts.map +1 -0
  45. package/package.json +1 -1
@@ -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
- return "http://localhost:5173/";
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(_options) {
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("rvv-embed-focus", "*");
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)) return;
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)) return;
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
- setButtonOpen(true);
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
- setButtonOpen(false);
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
- const { el: buttonEl, setOpen } = buildButtonElement(options);
310
- setButtonOpen = setOpen;
311
- buttonEl.addEventListener("click", () => toggle());
312
- document.body.append(buttonEl);
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)) return;
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
- popover.addEventListener("transitionend", () => unmountElement(wrapper), { once: true });
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
- buttonEl?.remove();
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
- tenant: TenantId;
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;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB,EAAE,iBAAiB;IACtE,GAAG,EAAE,MAAM,CAAC;CACb;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
+ {"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;AAE/C,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"}
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(_options: CreateIframeOptions): {
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":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,KAAK,mBAAmB,GAAG,EAAE,GAAG,YAAY,CAAC;AAM7C,wBAAgB,YAAY,CAAC,QAAQ,EAAE,mBAAmB;;;;;EAoBzD"}
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;CACpB,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"}
@@ -0,0 +1,6 @@
1
+ export declare const IFRAME_MESSAGES: {
2
+ readonly close: "rvv-embed-close";
3
+ readonly focus: "rvv-embed-focus";
4
+ };
5
+ export type IframeMessage = (typeof IFRAME_MESSAGES)[keyof typeof IFRAME_MESSAGES];
6
+ //# sourceMappingURL=iframe-messages.d.ts.map