@perspective-ai/sdk 1.1.0 → 1.1.2

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/constants.ts
2
- var SDK_VERSION = "1.1.0";
2
+ var SDK_VERSION = "1.1.2";
3
3
  var FEATURES = {
4
4
  RESIZE: 1 << 0,
5
5
  // 0b0001
@@ -45,7 +45,9 @@ var DATA_ATTRS = {
45
45
  brand: "data-perspective-brand",
46
46
  brandDark: "data-perspective-brand-dark",
47
47
  theme: "data-perspective-theme",
48
- noStyle: "data-perspective-no-style"
48
+ noStyle: "data-perspective-no-style",
49
+ autoOpen: "data-perspective-auto-open",
50
+ showOnce: "data-perspective-show-once"
49
51
  };
50
52
  var MESSAGE_TYPES = {
51
53
  // SDK -> Iframe (initialization)
@@ -79,9 +81,78 @@ var THEME_VALUES = {
79
81
  system: "system"
80
82
  };
81
83
  var STORAGE_KEYS = {
82
- anonId: "perspective-anon-id"
84
+ anonId: "perspective-anon-id",
85
+ triggerShown: "perspective-trigger-shown"
83
86
  };
84
87
 
88
+ // src/triggers.ts
89
+ function parseTriggerAttr(value) {
90
+ const trimmed = value.trim();
91
+ if (trimmed.startsWith("timeout:")) {
92
+ const delay = parseInt(trimmed.slice("timeout:".length), 10);
93
+ if (isNaN(delay) || delay < 0) {
94
+ throw new Error(`Invalid timeout delay: "${value}"`);
95
+ }
96
+ return { type: "timeout", delay };
97
+ }
98
+ if (trimmed === "timeout") {
99
+ return { type: "timeout", delay: 5e3 };
100
+ }
101
+ if (trimmed === "exit-intent") {
102
+ return { type: "exit-intent" };
103
+ }
104
+ throw new Error(
105
+ `Unknown trigger type: "${value}". Expected "timeout:<ms>" or "exit-intent".`
106
+ );
107
+ }
108
+ function setupTrigger(config, callback) {
109
+ if (config.type === "timeout") {
110
+ const timer = setTimeout(callback, config.delay);
111
+ return () => clearTimeout(timer);
112
+ }
113
+ if (config.type === "exit-intent") {
114
+ const handler = (e) => {
115
+ if (e.clientY <= 0) {
116
+ callback();
117
+ document.removeEventListener("mouseleave", handler);
118
+ }
119
+ };
120
+ document.addEventListener("mouseleave", handler);
121
+ return () => document.removeEventListener("mouseleave", handler);
122
+ }
123
+ const _exhaustive = config;
124
+ throw new Error(
125
+ `Unknown trigger type: ${_exhaustive.type}`
126
+ );
127
+ }
128
+ function storageKey(researchId) {
129
+ return `${STORAGE_KEYS.triggerShown}:${researchId}`;
130
+ }
131
+ function parseShowOnceAttr(value) {
132
+ if (!value) return "session";
133
+ const trimmed = value.trim();
134
+ if (trimmed === "visitor") return "visitor";
135
+ if (trimmed === "false") return false;
136
+ return "session";
137
+ }
138
+ function shouldShow(researchId, showOnce) {
139
+ if (showOnce === false) return true;
140
+ try {
141
+ const storage = showOnce === "visitor" ? localStorage : sessionStorage;
142
+ return storage.getItem(storageKey(researchId)) === null;
143
+ } catch {
144
+ return true;
145
+ }
146
+ }
147
+ function markShown(researchId, showOnce) {
148
+ if (showOnce === false) return;
149
+ try {
150
+ const storage = showOnce === "visitor" ? localStorage : sessionStorage;
151
+ storage.setItem(storageKey(researchId), "1");
152
+ } catch {
153
+ }
154
+ }
155
+
85
156
  // src/config.ts
86
157
  var DEFAULT_HOST = "https://getperspective.ai";
87
158
  var globalConfig = {};
@@ -1559,6 +1630,7 @@ function createFullpage(config) {
1559
1630
 
1560
1631
  // src/browser.ts
1561
1632
  var instances = /* @__PURE__ */ new Map();
1633
+ var triggerCleanups = /* @__PURE__ */ new Map();
1562
1634
  var configCache = /* @__PURE__ */ new Map();
1563
1635
  var styledButtons = /* @__PURE__ */ new Map();
1564
1636
  var buttonThemeMediaQuery = null;
@@ -1738,6 +1810,8 @@ function destroy(researchId) {
1738
1810
  function destroyAll() {
1739
1811
  instances.forEach((instance) => instance.unmount());
1740
1812
  instances.clear();
1813
+ triggerCleanups.forEach((cleanup) => cleanup());
1814
+ triggerCleanups.clear();
1741
1815
  styledButtons.clear();
1742
1816
  teardownButtonThemeListener();
1743
1817
  }
@@ -1764,9 +1838,29 @@ function autoInit() {
1764
1838
  if (el.hasAttribute("data-perspective-initialized")) return;
1765
1839
  el.setAttribute("data-perspective-initialized", "true");
1766
1840
  const researchId = el.getAttribute(DATA_ATTRS.popup);
1767
- if (researchId) {
1768
- const params = parseParamsAttr(el);
1769
- const brandConfig = extractBrandConfig(el);
1841
+ if (!researchId) return;
1842
+ const params = parseParamsAttr(el);
1843
+ const brandConfig = extractBrandConfig(el);
1844
+ const autoOpenAttr = el.getAttribute(DATA_ATTRS.autoOpen);
1845
+ if (autoOpenAttr) {
1846
+ try {
1847
+ const trigger = parseTriggerAttr(autoOpenAttr);
1848
+ const showOnce = parseShowOnceAttr(
1849
+ el.getAttribute(DATA_ATTRS.showOnce)
1850
+ );
1851
+ if (shouldShow(researchId, showOnce)) {
1852
+ triggerCleanups.get(researchId)?.();
1853
+ const cleanup = setupTrigger(trigger, () => {
1854
+ triggerCleanups.delete(researchId);
1855
+ markShown(researchId, showOnce);
1856
+ init({ researchId, type: "popup", params, ...brandConfig });
1857
+ });
1858
+ triggerCleanups.set(researchId, cleanup);
1859
+ }
1860
+ } catch (e) {
1861
+ console.warn("[Perspective]", e.message);
1862
+ }
1863
+ } else {
1770
1864
  styleButton(el, DEFAULT_THEME, brandConfig);
1771
1865
  el.addEventListener("click", (e) => {
1772
1866
  e.preventDefault();