1/*! Personyze on-site components (fresh-service/webdriver-apps) */ 2(function() 3{'use strict';
4// ../../../../deno-dir/npm/registry.npmjs.org/preact/10.22.0/dist/preact.module.js 5var n; 6var l; 7var u; 8var t; 9var i; 10var o; 11var r; 12var f; 13var e; 14var c; 15var s; 16var a; 17var h = {}; 18var p = []; 19var v = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; 20var y = Array.isArray; 21function d(n2, l3) { 22 for (var u4 in l3) n2[u4] = l3[u4]; 23 return n2; 24} 25function w(n2) { 26 var l3 = n2.parentNode; 27 l3 && l3.removeChild(n2); 28} 29function _(l3, u4, t3) { 30 var i4, o3, r3, f4 = {}; 31 for (r3 in u4) "key" == r3 ? i4 = u4[r3] : "ref" == r3 ? o3 = u4[r3] : f4[r3] = u4[r3]; 32 if (arguments.length > 2 && (f4.children = arguments.length > 3 ? n.call(arguments, 2) : t3), "function" == typeof l3 && null != l3.defaultProps) for (r3 in l3.defaultProps) void 0 === f4[r3] && (f4[r3] = l3.defaultProps[r3]); 33 return g(l3, f4, i4, o3, null); 34} 35function g(n2, t3, i4, o3, r3) { 36 var f4 = { 37 type: n2, 38 props: t3, 39 key: i4, 40 ref: o3, 41 __k: null, 42 __: null, 43 __b: 0, 44 __e: null, 45 __d: void 0, 46 __c: null, 47 constructor: void 0, 48 __v: null == r3 ? ++u : r3, 49 __i: -1, 50 __u: 0 51 }; 52 return null == r3 && null != l.vnode && l.vnode(f4), f4; 53} 54function k(n2) { 55 return n2.children; 56} 57function b(n2, l3) { 58 this.props = n2, this.context = l3; 59} 60function x(n2, l3) { 61 if (null == l3) return n2.__ ? x(n2.__, n2.__i + 1) : null; 62 for (var u4; l3 < n2.__k.length; l3++) if (null != (u4 = n2.__k[l3]) && null != u4.__e) return u4.__e; 63 return "function" == typeof n2.type ? x(n2) : null; 64} 65function C(n2) { 66 var l3, u4; 67 if (null != (n2 = n2.__) && null != n2.__c) { 68 for (n2.__e = n2.__c.base = null, l3 = 0; l3 < n2.__k.length; l3++) if (null != (u4 = n2.__k[l3]) && null != u4.__e) { 69 n2.__e = n2.__c.base = u4.__e; 70 break; 71 } 72 return C(n2); 73 } 74} 75function M(n2) { 76 (!n2.__d && (n2.__d = true) && i.push(n2) && !P.__r++ || o !== l.debounceRendering) && ((o = l.debounceRendering) || r)(P); 77} 78function P() { 79 var n2, u4, t3, o3, r3, e3, c3, s3; 80 for (i.sort(f); n2 = i.shift(); ) n2.__d && (u4 = i.length, o3 = void 0, e3 = (r3 = (t3 = n2).__v).__e, c3 = [], s3 = [], t3.__P && ((o3 = d({}, r3)).__v = r3.__v + 1, l.vnode && l.vnode(o3), O(t3.__P, o3, r3, t3.__n, t3.__P.namespaceURI, 32 & r3.__u ? [ 81 e3 82 ] : null, c3, null == e3 ? x(r3) : e3, !!(32 & r3.__u), s3), o3.__v = r3.__v, o3.__.__k[o3.__i] = o3, j(c3, o3, s3), o3.__e != e3 && C(o3)), i.length > u4 && i.sort(f)); 83 P.__r = 0; 84} 85function S(n2, l3, u4, t3, i4, o3, r3, f4, e3, c3, s3) { 86 var a3, v3, y3, d3, w3, _3 = t3 && t3.__k || p, g2 = l3.length; 87 for (u4.__d = e3, $(u4, l3, _3), e3 = u4.__d, a3 = 0; a3 < g2; a3++) null != (y3 = u4.__k[a3]) && "boolean" != typeof y3 && "function" != typeof y3 && (v3 = -1 === y3.__i ? h : _3[y3.__i] || h, y3.__i = a3, O(n2, y3, v3, i4, o3, r3, f4, e3, c3, s3), d3 = y3.__e, y3.ref && v3.ref != y3.ref && (v3.ref && N(v3.ref, null, y3), s3.push(y3.ref, y3.__c || d3, y3)), null == w3 && null != d3 && (w3 = d3), 65536 & y3.__u || v3.__k === y3.__k ? (e3 && !e3.isConnected && (e3 = x(v3)), e3 = I(y3, e3, n2)) : "function" == typeof y3.type && void 0 !== y3.__d ? e3 = y3.__d : d3 && (e3 = d3.nextSibling), y3.__d = void 0, y3.__u &= -196609); 88 u4.__d = e3, u4.__e = w3; 89} 90function $(n2, l3, u4) { 91 var t3, i4, o3, r3, f4, e3 = l3.length, c3 = u4.length, s3 = c3, a3 = 0; 92 for (n2.__k = [], t3 = 0; t3 < e3; t3++) r3 = t3 + a3, null != (i4 = n2.__k[t3] = null == (i4 = l3[t3]) || "boolean" == typeof i4 || "function" == typeof i4 ? null : "string" == typeof i4 || "number" == typeof i4 || "bigint" == typeof i4 || i4.constructor == String ? g(null, i4, null, null, null) : y(i4) ? g(k, { 93 children: i4 94 }, null, null, null) : void 0 === i4.constructor && i4.__b > 0 ? g(i4.type, i4.props, i4.key, i4.ref ? i4.ref : null, i4.__v) : i4) ? (i4.__ = n2, i4.__b = n2.__b + 1, f4 = L(i4, u4, r3, s3), i4.__i = f4, o3 = null, -1 !== f4 && (s3--, (o3 = u4[f4]) && (o3.__u |= 131072)), null == o3 || null === o3.__v ? (-1 == f4 && a3--, "function" != typeof i4.type && (i4.__u |= 65536)) : f4 !== r3 && (f4 === r3 + 1 ? a3++ : f4 > r3 ? s3 > e3 - r3 ? a3 += f4 - r3 : a3-- : f4 < r3 ? f4 == r3 - 1 && (a3 = f4 - r3) : a3 = 0, f4 !== t3 + a3 && (i4.__u |= 65536))) : (o3 = u4[r3]) && null == o3.ke
vendor: 4,430 bytes, lines 94-165
94y && o3.__e && 0 == (131072 & o3.__u) && (o3.__e == n2.__d && (n2.__d = x(o3)), V(o3, o3, false), u4[r3] = null, s3--); 95 if (s3) for (t3 = 0; t3 < c3; t3++) null != (o3 = u4[t3]) && 0 == (131072 & o3.__u) && (o3.__e == n2.__d && (n2.__d = x(o3)), V(o3, o3)); 96} 97function I(n2, l3, u4) { 98 var t3, i4; 99 if ("function" == typeof n2.type) { 100 for (t3 = n2.__k, i4 = 0; t3 && i4 < t3.length; i4++) t3[i4] && (t3[i4].__ = n2, l3 = I(t3[i4], l3, u4)); 101 return l3; 102 } 103 n2.__e != l3 && (u4.insertBefore(n2.__e, l3 || null), l3 = n2.__e); 104 do { 105 l3 = l3 && l3.nextSibling; 106 } while (null != l3 && 8 === l3.nodeType); 107 return l3; 108} 109function L(n2, l3, u4, t3) { 110 var i4 = n2.key, o3 = n2.type, r3 = u4 - 1, f4 = u4 + 1, e3 = l3[u4]; 111 if (null === e3 || e3 && i4 == e3.key && o3 === e3.type && 0 == (131072 & e3.__u)) return u4; 112 if (t3 > (null != e3 && 0 == (131072 & e3.__u) ? 1 : 0)) for (; r3 >= 0 || f4 < l3.length; ) { 113 if (r3 >= 0) { 114 if ((e3 = l3[r3]) && 0 == (131072 & e3.__u) && i4 == e3.key && o3 === e3.type) return r3; 115 r3--; 116 } 117 if (f4 < l3.length) { 118 if ((e3 = l3[f4]) && 0 == (131072 & e3.__u) && i4 == e3.key && o3 === e3.type) return f4; 119 f4++; 120 } 121 } 122 return -1; 123} 124function T(n2, l3, u4) { 125 "-" === l3[0] ? n2.setProperty(l3, null == u4 ? "" : u4) : n2[l3] = null == u4 ? "" : "number" != typeof u4 || v.test(l3) ? u4 : u4 + "px"; 126} 127function A(n2, l3, u4, t3, i4) { 128 var o3; 129 n: if ("style" === l3) if ("string" == typeof u4) n2.style.cssText = u4; 130 else { 131 if ("string" == typeof t3 && (n2.style.cssText = t3 = ""), t3) for (l3 in t3) u4 && l3 in u4 || T(n2.style, l3, ""); 132 if (u4) for (l3 in u4) t3 && u4[l3] === t3[l3] || T(n2.style, l3, u4[l3]); 133 } 134 else if ("o" === l3[0] && "n" === l3[1]) o3 = l3 !== (l3 = l3.replace(/(PointerCapture)$|Capture$/i, "$1")), l3 = l3.toLowerCase() in n2 || "onFocusOut" === l3 || "onFocusIn" === l3 ? l3.toLowerCase().slice(2) : l3.slice(2), n2.l || (n2.l = {}), n2.l[l3 + o3] = u4, u4 ? t3 ? u4.u = t3.u : (u4.u = e, n2.addEventListener(l3, o3 ? s : c, o3)) : n2.removeEventListener(l3, o3 ? s : c, o3); 135 else { 136 if ("http://www.w3.org/2000/svg" == i4) l3 = l3.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s"); 137 else if ("width" != l3 && "height" != l3 && "href" != l3 && "list" != l3 && "form" != l3 && "tabIndex" != l3 && "download" != l3 && "rowSpan" != l3 && "colSpan" != l3 && "role" != l3 && l3 in n2) try { 138 n2[l3] = null == u4 ? "" : u4; 139 break n; 140 } catch (n3) { 141 } 142 "function" == typeof u4 || (null == u4 || false === u4 && "-" !== l3[4] ? n2.removeAttribute(l3) : n2.setAttribute(l3, u4)); 143 } 144} 145function F(n2) { 146 return function(u4) { 147 if (this.l) { 148 var t3 = this.l[u4.type + n2]; 149 if (null == u4.t) u4.t = e++; 150 else if (u4.t < t3.u) return; 151 return t3(l.event ? l.event(u4) : u4); 152 } 153 }; 154} 155function O(n2, u4, t3, i4, o3, r3, f4, e3, c3, s3) { 156 var a3, h3, p3, v3, w3, _3, g2, m2, x3, C3, M2, P2, $2, I2, H, L2 = u4.type; 157 if (void 0 !== u4.constructor) return null; 158 128 & t3.__u && (c3 = !!(32 & t3.__u), r3 = [ 159 e3 = u4.__e = t3.__e 160 ]), (a3 = l.__b) && a3(u4); 161 n: if ("function" == typeof L2) try { 162 if (m2 = u4.props, x3 = (a3 = L2.contextType) && i4[a3.__c], C3 = a3 ? x3 ? x3.props.value : a3.__ : i4, t3.__c ? g2 = (h3 = u4.__c = t3.__c).__ = h3.__E : ("prototype" in L2 && L2.prototype.render ? u4.__c = h3 = new L2(m2, C3) : (u4.__c = h3 = new b(m2, C3), h3.constructor = L2, h3.render = q), x3 && x3.sub(h3), h3.props = m2, h3.state || (h3.state = {}), h3.context = C3, h3.__n = i4, p3 = h3.__d = true, h3.__h = [], h3._sb = []), null == h3.__s && (h3.__s = h3.state), null != L2.getDerivedStateFromProps && (h3.__s == h3.state && (h3.__s = d({}, h3.__s)), d(h3.__s, L2.getDerivedStateFromProps(m2, h3.__s))), v3 = h3.props, w3 = h3.state, h3.__v = u4, p3) null == L2.getDerivedStateFromProps && null != h3.componentWillMount && h3.componentWillMount(), null != h3.componentDidMount && h3.__h.push(h3.componentDidMount); 163 else { 164 if (null == L2.getDerivedStateFromProps && m2 !== v3 && null != h3.componentWillReceiveProps && h3.componentWillReceiveProps(m2, C3), !h3.__e && (null != h3.shouldComponentUpdate && false === h3.shouldComponentUpdate(m2, h3.__s, C3) || u4.__v === t3.__v)) { 165 for (u4.__v !== t3.__v && (h3.props = m2, h3.state = h3.__s, h3.__d = false), u4.__e = t3.__e, u4.__k = t3.__k, u4.__k.forEac
vendor: 1,103 bytes, lines 165-181
165h(function(n3) { 166 n3 && (n3.__ = u4); 167 }), M2 = 0; M2 < h3._sb.length; M2++) h3.__h.push(h3._sb[M2]); 168 h3._sb = [], h3.__h.length && f4.push(h3); 169 break n; 170 } 171 null != h3.componentWillUpdate && h3.componentWillUpdate(m2, h3.__s, C3), null != h3.componentDidUpdate && h3.__h.push(function() { 172 h3.componentDidUpdate(v3, w3, _3); 173 }); 174 } 175 if (h3.context = C3, h3.props = m2, h3.__P = n2, h3.__e = false, P2 = l.__r, $2 = 0, "prototype" in L2 && L2.prototype.render) { 176 for (h3.state = h3.__s, h3.__d = false, P2 && P2(u4), a3 = h3.render(h3.props, h3.state, h3.context), I2 = 0; I2 < h3._sb.length; I2++) h3.__h.push(h3._sb[I2]); 177 h3._sb = []; 178 } else do { 179 h3.__d = false, P2 && P2(u4), a3 = h3.render(h3.props, h3.state, h3.context), h3.state = h3.__s; 180 } while (h3.__d && ++$2 < 25); 181 h3.state = h3.__s, null != h3.getChildContext && (i4 = d(d({}, i4), h3.getChildContext())), p3 || null == h3.getSnapshotBeforeUpdate || (_3 = h3.getSnapshotBeforeUpdate(v3, w3)), S(n2, y(H = null != a3 && a3.type === k && null == a3.ke
181y ? a3.props.children : a3) ? H : [ 182 H 183 ], u4, t3, i4, o3, r3, f4, e3, c3, s3), h3.base = u4.__e, u4.__u &= -161, h3.__h.length && f4.push(h3), g2 && (h3.__E = h3.__ = null); 184 } catch (n3) { 185 u4.__v = null, c3 || null != r3 ? (u4.__e = e3, u4.__u |= c3 ? 160 : 32, r3[r3.indexOf(e3)] = null) : (u4.__e = t3.__e, u4.__k = t3.__k), l.__e(n3, u4, t3); 186 } 187 else null == r3 && u4.__v === t3.__v ? (u4.__k = t3.__k, u4.__e = t3.__e) : u4.__e = z(t3.__e, u4, t3, i4, o3, r3, f4, c3, s3); 188 (a3 = l.diffed) && a3(u4); 189} 190function j(n2, u4, t3) { 191 u4.__d = void 0; 192 for (var i4 = 0; i4 < t3.length; i4++) N(t3[i4], t3[++i4], t3[++i4]); 193 l.__c && l.__c(u4, n2), n2.some(function(u5) { 194 try { 195 n2 = u5.__h, u5.__h = [], n2.some(function(n3) { 196 n3.call(u5); 197 }); 198 } catch (n3) { 199 l.__e(n3, u5.__v); 200 } 201 }); 202} 203function z(l3, u4, t3, i4, o3, r3, f4, e3, c3) { 204 var s3, a3, p3, v3, d3, _3, g2, m2 = t3.props, k3 = u4.props, b2 = u4.type; 205 if ("svg" === b2 ? o3 = "http://www.w3.org/2000/svg" : "math" === b2 ? o3 = "http://www.w3.org/1998/Math/MathML" : o3 || (o3 = "http://www.w3.org/1999/xhtml"), null != r3) { 206 for (s3 = 0; s3 < r3.length; s3++) if ((d3 = r3[s3]) && "setAttribute" in d3 == !!b2 && (b2 ? d3.localName === b2 : 3 === d3.nodeType)) { 207 l3 = d3, r3[s3] = null; 208 break; 209 } 210 } 211 if (null == l3) { 212 if (null === b2) return document.createTextNode(k3); 213 l3 = document.createElementNS(o3, b2, k3.is && k3), r3 = null, e3 = false; 214 } 215 if (null === b2) m2 === k3 || e3 && l3.data === k3 || (l3.data = k3); 216 else { 217 if (r3 = r3 && n.call(l3.childNodes), m2 = t3.props || h, !e3 && null != r3) for (m2 = {}, s3 = 0; s3 < l3.attributes.length; s3++) m2[(d3 = l3.attributes[s3]).name] = d3.value; 218 for (s3 in m2) if (d3 = m2[s3], "children" == s3) ; 219 else if ("dangerouslySetInnerHTML" == s3) p3 = d3; 220 else if ("key" !== s3 && !(s3 in k3)) { 221 if ("value" == s3 && "defaultValue" in k3 || "checked" == s3 && "defaultChecked" in k3) continue; 222 A(l3, s3, null, d3, o3); 223 } 224 for (s3 in k3) d3 = k3[s3], "children" == s3 ? v3 = d3 : "dangerouslySetInnerHTML" == s3 ? a3 = d3 : "value" == s3 ? _3 = d3 : "checked" == s3 ? g2 = d3 : "key" === s3 || e3 && "function" != typeof d3 || m2[s3] === d3 || A(l3, s3, d3, m2[s3], o3); 225 if (a3) e3 || p3 && (a3.__html === p3.__html || a3.__html === l3.innerHTML) || (l3.innerHTML = a3.__html), u4.__k = []; 226 else if (p3 && (l3.innerHTML = ""), S(l3, y(v3) ? v3 : [ 227 v3 228 ], u4, t3, i4, "foreignObject" === b2 ? "http://www.w3.org/1999/xhtml" : o3, r3, f4, r3 ? r3[0] : t3.__k && x(t3, 0), e3, c3), null != r3) for (s3 = r3.length; s3--; ) null != r3[s3] && w(r3[s3]); 229 e3 || (s3 = "value", void 0 !== _3 && (_3 !== l3[s3] || "progress" === b2 && !_3 || "option" === b2 && _3 !== m2[s3]) && A(l3, s3, _3, m2[s3], o3), s3 = "checked", void 0 !== g2 && g2 !== l3[s3] && A(l3, s3, g2, m2[s3], o3)); 230 } 231 return l3; 232} 233function N(n2, u4, t3) { 234 try { 235 "function" == typeof n2 ? n2(u4) : n2.current = u4; 236 } catch (n3) { 237 l.__e(n3, t3); 238 } 239} 240function V(n2, u4, t3) { 241 var i4, o3; 242 if (l.unmount && l.unmount(n2), (i4 = n2.ref) && (i4.current && i4.current !== n2.__e || N(i4, null, u4)), null != (i4 = n2.__c)) { 243 if (i4.componentWillUnmount) try { 244 i4.componentWillUnmount(); 245 } catch (n3) { 246 l.__e(n3, u4); 247 } 248 i4.base = i4.__P = null; 249 } 250 if (i4 = n2.__k) for (o3 = 0; o3 < i4.length; o3++) i4[o3] && V(i4[o3], u4, t3 || "function" != typeof n2.type); 251 t3 || null == n2.__e || w(n2.__e), n2.__c = n2.__ = n2.__e = n2.__d = void 0; 252} 253function q(n2, l3, u4) { 254 return this.constructor(n2, u4); 255} 256function B(u4, t3, i4) { 257 var o3, r3, f4, e3; 258 l.__ && l.__(u4, t3), r3 = (o3 = "function" == typeof i4) ? null : i4 && i4.__k || t3.__k, f4 = [], e3 = [], O(t3, u4 = (!o3 && i4 || t3).__k = _(k, null, [ 259 u4 260 ]), r3 || h, h, t3.namespaceURI, !o3 && i4 ? [ 261 i4 262 ] : r3 ? null : t3.firstChild ? n.call(t3.childNodes) : null, f4, !o3 && i4 ? i4 : r3 ? r3.__e : t3.firstChild, o3, e3), j(f4, u4, e3); 263} 264n = p.slice, l = { 265 __e: function(n2, l3, u4, t3) { 266 for (var i4, o3, r3; l3 = l3.__; ) if ((i4 = l3.__c) && !i4.__) try { 267 if ((o3 = i4.constructor) && null != o3.getDerivedStateFromError && (i4.setState(o3.getDerivedStateFromError(n2)), r3 = i4.__d), null != i4.componentDidCatch && (i4.componentDidCatch(n2, t3 || {}), r3 = i4.__d), r3) return i4.__E = i4; 268 } catch (l4) { 269 n2 = l4; 270 } 271 throw n2; 272 } 273}, u = 0, t = function(n2) { 274 return null != n2 && null == n2.constructor; 275}, b.prototype.setState = function(n2, l3) { 276 var u4; 277 u4 = null != this.__s && this.__s !== this.state ? this.__s : this.__s = d({}, this.state), "function" == typeof n2 && (n2 = n2(d({}, u4), this.props)), n2 && d(u4, n2), null != n2 && this.__v && (l3 && this._sb.push(l3), M(this)); 278}, b.prototype.forceUpdate = function(n2) { 279 this.__v && (this.__e = true, n2 && this.__h.push(n2), M(this)); 280}, b.prototype.render = k, i = [], r = "function" == typeof Promise ? Promise.prototype.then.bind(Prom
280ise.resolve()) : setTimeout, f = function(n2, l3) { 281 return n2.__v.__b - l3.__v.__b; 282}, P.__r = 0, e = 0, c = F(false), s = F(true), a = 0; 283
vendor: 715 bytes, lines 284-312
284// ../../../../deno-dir/npm/registry.npmjs.org/preact/10.22.0/jsx-runtime/dist/jsxRuntime.module.js 285var f2 = 0; 286var i2 = Array.isArray; 287function u2(e3, t3, n2, o3, i4, u4) { 288 t3 || (t3 = {}); 289 var a3, c3, p3 = t3; 290 if ("ref" in p3) for (c3 in p3 = {}, t3) "ref" == c3 ? a3 = t3[c3] : p3[c3] = t3[c3]; 291 var l3 = { 292 type: e3, 293 props: p3, 294 key: n2, 295 ref: a3, 296 __k: null, 297 __: null, 298 __b: 0, 299 __e: null, 300 __d: void 0, 301 __c: null, 302 constructor: void 0, 303 __v: --f2, 304 __i: -1, 305 __u: 0, 306 __source: i4, 307 __self: u4 308 }; 309 if ("function" == typeof e3 && (a3 = e3.defaultProps)) for (c3 in a3) void 0 === p3[c3] && (p3[c3] = a3[c3]); 310 return l.vnode && l.vnode(l3), l3; 311} 312
313// ../../../../deno-dir/npm/registry.npmjs.org/preact/10.22.0/hooks/dist/hooks.module.js 314var t2; 315var r2; 316var u3; 317var i3; 318var o2 = 0; 319var f3 = []; 320var c2 = []; 321var e2 = l; 322var a2 = e2.__b; 323var v2 = e2.__r; 324var l2 = e2.diffed; 325var m = e2.__c; 326var s2 = e2.unmount; 327var d2 = e2.__; 328function h2(n2, t3) { 329 e2.__h && e2.__h(r2, n2, o2 || t3), o2 = 0; 330 var u4 = r2.__H || (r2.__H = { 331 __: [], 332 __h: [] 333 }); 334 return n2 >= u4.__.length && u4.__.push({ 335 __V: c2 336 }), u4.__[n2]; 337} 338function p2(n2) { 339 return o2 = 1, y2(D, n2); 340} 341function y2(n2, u4, i4) { 342 var o3 = h2(t2++, 2); 343 if (o3.t = n2, !o3.__c && (o3.__ = [ 344 i4 ? i4(u4) : D(void 0, u4), 345 function(n3) { 346 var t3 = o3.__N ? o3.__N[0] : o3.__[0], r3 = o3.t(t3, n3); 347 t3 !== r3 && (o3.__N = [ 348 r3, 349 o3.__[1] 350 ], o3.__c.setState({})); 351 } 352 ], o3.__c = r2, !r2.u)) { 353 var f4 = function(n3, t3, r3) { 354 if (!o3.__c.__H) return true; 355 var u5 = o3.__c.__H.__.filter(function(n4) { 356 return !!n4.__c; 357 }); 358 if (u5.every(function(n4) { 359 return !n4.__N; 360 })) return !c3 || c3.call(this, n3, t3, r3); 361 var i5 = false; 362 return u5.forEach(function(n4) { 363 if (n4.__N) { 364 var t4 = n4.__[0]; 365 n4.__ = n4.__N, n4.__N = void 0, t4 !== n4.__[0] && (i5 = true); 366 } 367 }), !(!i5 && o3.__c.props === n3) && (!c3 || c3.call(this, n3, t3, r3)); 368 }; 369 r2.u = true; 370 var c3 = r2.shouldComponentUpdate, e3 = r2.componentWillUpdate; 371 r2.componentWillUpdate = function(n3, t3, r3) { 372 if (this.__e) { 373 var u5 = c3; 374 c3 = void 0, f4(n3, t3, r3), c3 = u5; 375 } 376 e3 && e3.call(this, n3, t3, r3); 377 }, r2.shouldComponentUpdate = f4; 378 } 379 return o3.__N || o3.__; 380} 381function _2(n2, u4) { 382 var i4 = h2(t2++, 3); 383 !e2.__s && C2(i4.__H, u4) && (i4.__ = n2, i4.i = u4, r2.__H.__h.push(i4)); 384} 385function F2(n2) { 386 return o2 = 5, q2(function() { 387 return { 388 current: n2 389 }; 390 }, []); 391} 392function q2(n2, r3) { 393 var u4 = h2(t2++, 7); 394 return C2(u4.__H, r3) ? (u4.__V = n2(), u4.i = r3, u4.__h = n2, u4.__V) : u4.__; 395} 396function x2(n2, t3) { 397 return o2 = 8, q2(function() { 398 return n2; 399 }, t3); 400} 401function j2() { 402 for (var n2; n2 = f3.shift(); ) if (n2.__P && n2.__H) try { 403 n2.__H.__h.forEach(z2), n2.__H.__h.forEach(B2), n2.__H.__h = []; 404 } catch (t3) { 405 n2.__H.__h = [], e2.__e(t3, n2.__v); 406 } 407} 408e2.__b = function(n2) { 409 r2 = null, a2 && a2(n2); 410}, e2.__ = function(n2, t3) { 411 n2 && t3.__k && t3.__k.__m && (n2.__m = t3.__k.__m), d2 && d2(n2, t3); 412}, e2.__r = function(n2) { 413 v2 && v2(n2), t2 = 0; 414 var i4 = (r2 = n2.__c).__H; 415 i4 && (u3 === r2 ? (i4.__h = [], r2.__h = [], i4.__.forEach(function(n3) { 416 n3.__N && (n3.__ = n3.__N), n3.__V = c2, n3.__N = n3.i = void 0; 417 })) : (i4.__h.forEach(z2), i4.__h.forEach(B2), i4.__h = [], t2 = 0)), u3 = r2; 418}, e2.diffed = function(n2) { 419 l2 && l2(n2); 420 var t3 = n2.__c; 421 t3 && t3.__H && (t3.__H.__h.length && (1 !== f3.push(t3) && i3 === e2.requestAnimationFrame || ((i3 = e2.requestAnimationFrame) || w2)(j2)), t3.__H.__.forEach(function(n3) { 422 n3.i && (n3.__H = n3.i), n3.__V !== c2 && (n3.__ = n3.__V), n3.i = void 0, n3.__V = c2; 423 })), u3 = r2 = null; 424}, e2.__c = function(n2, t3) { 425 t3.some(function(n3) { 426 try { 427 n3.__h.forEach(z2), n3.__h = n3.__h.filter(function(n4) { 428 return !n4.__ || B2(n4); 429 }); 430 } catch (r3) { 431 t3.some(function(n4) { 432 n4.__h && (n4.__h = []); 433 }), t3 = [], e2.__e(r3, n3.__v); 434 } 435 }), m && m(n2, t3); 436}, e2.unmount = function(n2) { 437 s2 && s2(n2); 438 var t3, r3 = n2.__c; 439 r3 && r3.__H && (r3.__H.__.forEach(function(n3) { 440 try { 441 z2(n3); 442 } catch (n4) { 443 t3 = n4; 444 } 445 }), r3.__H = void 0, t3 && e2.__e(t3, r3.__v)); 446}; 447var k2 = "function" == typeof requestAnimationFrame; 448function w2(n2) { 449 var t3, r3 = function() { 450 clearTimeout(u4), k2 && cancelAnimationFrame(t3), setTimeout(n2); 451 }, u4 = setTimeout(r3, 100); 452 k2 && (t3 = requestAnimationFrame(r3)); 453} 454function z2(n2) { 455 var t3 = r2, u4 = n2.__c; 456 "function" == typeof u4 && (n2.__c = void 0, u4()), r2 = t3; 457} 458function B2(n2) { 459 var t3 = r2; 460 n2.__c = n2.__(), r2 = t3; 461} 462function C2(n2, t3) { 463 return !n2 || n2.length !== t3.length || t3.some(function(t4, r3) { 464 return t4 !== n2[r3]; 465 }); 466} 467function D(n2, t3) { 468 return "function" == typeof t3 ? t3(n2) : t3; 469} 470
471// src/components/SimulatorPanel.tsx 472var PANEL_STYLE = ` .qs-panel 473 { --qs-chrome: #12182A; 474 --qs-chrome-2: #171D31; 475 --qs-chrome-3: #1E2640; 476 --qs-line: rgba(255, 255, 255, 0.08); 477 --qs-line-2: rgba(255, 255, 255, 0.14); 478 --qs-fg: #E8EDF7; 479 --qs-muted: #94A3C1; 480 --qs-muted-2: #6A7698; 481 --qs-brand: #12B886; 482 --qs-brand-soft: rgba(18, 184, 134, 0.14); 483 --qs-brand-fg: #7BDFAE; 484 --qs-danger-soft: rgba(239, 68, 68, 0.14); 485 --qs-danger-fg: #FFB4B4; 486 --qs-mono: ui-monospace, Menlo, Consolas, monospace; 487 488 position: fixed; 489 top: 0; 490 right: 0; 491 z-index: 2147483647; 492 display: flex; 493 flex-direction: column; 494 box-sizing: border-box; 495 width: 30em; 496 max-width: 85vw; 497 height: 100vh; 498 border-left: 1px solid var(--qs-line); 499 background-color: var(--qs-chrome); 500 color: var(--qs-fg); 501 direction: ltr; 502 text-align: left; 503 font: normal normal 400 13px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; 504 box-shadow: 0 0 2em rgba(0, 0, 0, 0.45); 505 } 506 .qs-panel.qs-left 507 { right: auto; 508 left: 0; 509 border-left: none; 510 border-right: 1px solid var(--qs-line); 511 } 512 513 .qs-panel * 514 { box-sizing: border-box; 515 } 516 517 /* Every icon here is an inline <svg> with a viewBox and no width/height of its own, so without 518 this it stretches to fill whatever flex line it lands on. 519 */ 520 .qs-panel svg, 521 .qs-handle svg 522 { flex: 0 0 auto; 523 width: 1.1em; 524 height: 1.1em; 525 } 526 527 /* ===== header ===== */ 528 .qs-head 529 { display: flex; 530 flex: 0 0 auto; 531 align-items: center; 532 gap: 0.5em; 533 padding: 0.7em 0.8em; 534 border-bottom: 1px solid var(--qs-line); 535 } 536 .qs-logo 537 { width: auto; 538 height: 2.2em; 539 border: none; 540 } 541 .qs-title 542 { flex: 10000 1 0; 543 min-width: 0; 544 } 545 .qs-title-main 546 { font-size: 100%; 547 font-weight: 700; 548 letter-spacing: 0.04em; 549 } 550 .qs-title-sub 551 { color: var(--qs-muted); 552 font-size: 85%; 553 } 554 .qs-icon 555 { display: flex; 556 flex: 0 0 auto; 557 align-items: center; 558 justify-content: center; 559 width: 1.9em; 560 height: 1.9em; 561 padding: 0; 562 border: none; 563 border-radius: 0.4em; 564 background: transparent; 565 color: var(--qs-muted); 566 font: inherit; 567 cursor: pointer; 568 } 569 .qs-icon:hover 570 { background-color: var(--qs-chrome-3); 571 color: var(--qs-fg); 572 } 573 574 /* ===== body ===== */ 575 .qs-body 576 { flex: 10000 1 auto; 577 overflow: auto; 578 padding: 0.9em; 579 } 580 .qs-foot 581 { display: flex; 582 flex: 0 0 auto; 583 gap: 0.6em; 584 align-items: center; 585 justify-content: flex-end; 586 padding: 0.8em; 587 border-top: 1px solid var(--qs-line); 588 } 589 590 .qs-sec + .qs-sec 591 { margin-top: 1.2em; 592 padding-top: 1.2em; 593 border-top: 1px solid var(--qs-line); 594 } 595 .qs-sec-head 596 { display: flex; 597 align-items: center; 598 gap: 0.45em; 599 margin: 0 0 0.4em; 600 font-size: 100%; 601 font-weight: 600; 602 } 603 .qs-sec-head svg 604 { color: var(--qs-brand); 605 } 606 .qs-hint 607 { margin-bottom: 0.7em; 608 color: var(--qs-muted); 609 font-size: 92%; 610 } 611 .qs-label 612 { display: block; 613 margin-bottom: 0.3em; 614 color: var(--qs-muted-2); 615 font-size: 84%; 616 font-weight: 600; 617 letter-spacing: 0.04em; 618 text-transform: uppercase; 619 } 620 621 /* ===== collapsible section ===== */ 622 .qs-fold + .qs-fold 623 { margin-top: 0.7em; 624 } 625 .qs-fold 626 { border: 1px solid var(--qs-line); 627 border-radius: 0.7em; 628 background-color: var(--qs-chrome-2); 629 overflow: hidden; 630 } 631 .qs-fold-head 632 { display: flex; 633 gap: 0.55em; 634 align-items: center; 635 width: 100%; 636 padding: 0.7em 0.8em; 637 border: none; 638 background: none; 639 color: var(--qs-fg); 640 font: inherit; 641 font-weight: 600; 642 text-align: left; 643 cursor: pointer; 644 } 645 .qs-fold-head:hover 646 { background-color: var(--qs-chrome-3); 647 } 648 .qs-fold-ico 649 { display: inline-flex; 650 flex: 0 0 auto; 651 color: var(--qs-brand); 652 } 653 .qs-fold-name 654 { flex: 10000 1 auto; 655 min-width: 0; 656 } 657 .qs-fold-meta 658 { flex: 0 1 auto; 659 overflow: hidden; 660 color: var(--qs-muted-2); 661 font-size: 86%; 662 font-weight: 600; 663 white-space: nowrap; 664 text-overflow: ellipsis; 665 } 666 .qs-fold-chev 667 { display: inline-flex; 668 flex: 0 0 auto; 669 color: var(--qs-muted-2); 670 transition: transform 0.2s; 671 } 672 .qs-fold.qs-closed .qs-fold-chev 673 { transform: rotate(-90deg); 674 } 675 .qs-fold-body 676 { padding: 0 0.8em 0.85em; 677 } 678 679 /* ===== source cards ===== */ 680 .qs-cards 681 { display: grid; 682 grid-template-columns: repeat(auto-fill, minmax(8.5em, 1fr)); 683 gap: 0.45em; 684 } 685 .qs-card 686 { display: flex; 687 flex-direction: column; 688 gap: 0.3em; 689 padding: 0.65em 0.6em; 690 border: 1px solid var(--qs-line); 691 border-radius: 0.6em; 692 background-color: var(--qs-chrome-2); 693 color: var(--qs-fg); 694 font: inherit; 695 text-align: left; 696 cursor: pointer; 697 } 698 .qs-card:hover 699 { border-color: var(--qs-line-2); 700 background-color: var(--qs-chrome-3); 701 } 702 .qs-card.qs-on 703 { border-color: var(--qs-brand); 704 background-color: var(--qs-brand-soft); 705 } 706 .qs-card-ico 707 { display: inline-flex; 708 color: var(--qs-muted-2); 709 } 710 .qs-card-ico svg 711 { width: 1.25em; 712 height: 1.25em; 713 } 714 .qs-card.qs-on .qs-card-ico 715 { color: var(--qs-brand); 716 } 717 .qs-card-t 718 { font-size: 92%; 719 font-weight: 600; 720 line-height: 1.25; 721 } 722 /* The count is the reason these are cards and not a dropdown: "this page has 12 cookies and no 723 META tags" is the answer that decides which one to open. */ 724 .qs-card-n 725 { color: var(--qs-muted-2); 726 font-size: 82%; 727 } 728 .qs-card.qs-on .qs-card-n 729 { color: var(--qs-brand-fg); 730 } 731 .qs-card-n.qs-none 732 { opacity: 0.55; 733 } 734 735 /* Inside a framed section, anything that is itself a card has to sit a shade DARKER than the 736 frame, or it merges into it and the grid reads as loose icons on a panel. The frame is 737 --qs-chrome-2, so its contents drop to --qs-chrome - the same relationship the placement 738 cards (.qs-opt) already have. Scoped to .qs-fold-body because outside a frame these sit on 739 the panel background, where the lighter shade is what makes them stand out at all. */ 740 .qs-fold-body .qs-card, 741 .qs-fold-body .qs-tree 742 { background-color: var(--qs-chrome); 743 } 744 745 .qs-link 746 { padding: 0; 747 border: none; 748 background: none; 749 color: var(--qs-brand-fg); 750 font: inherit; 751 text-decoration: underline; 752 text-underline-offset: 2px; 753 cursor: pointer; 754 } 755 756 /* ===== radio cards (placement) ===== */ 757 .qs-opt 758 { display: flex; 759 gap: 0.6em; 760 align-items: flex-start; 761 width: 100%; 762 margin-top: 0.4em; 763 padding: 0.6em 0.7em; 764 border: 1px solid var(--qs-line); 765 border-radius: 0.6em; 766 background-color: var(--qs-chrome); 767 color: var(--qs-fg); 768 font: inherit; 769 text-align: left; 770 cursor: pointer; 771 } 772 .qs-opt:hover 773 { border-color: var(--qs-line-2); 774 } 775 .qs-opt.qs-on 776 { border-color: var(--qs-brand); 777 background-color: var(--qs-brand-soft); 778 } 779 .qs-opt-radio 780 { display: inline-flex; 781 flex: 0 0 auto; 782 align-items: center; 783 justify-content: center; 784 width: 1.05em; 785 height: 1.05em; 786 margin-top: 0.15em; 787 border: 1px solid var(--qs-line-2); 788 border-radius: 50%; 789 } 790 .qs-opt.qs-on .qs-opt-radio 791 { border-color: var(--qs-brand); 792 } 793 .qs-opt.qs-on .qs-opt-radio::after 794 { content: ''; 795 width: 0.5em; 796 height: 0.5em; 797 border-radius: 50%; 798 background-color: var(--qs-brand); 799 } 800 .qs-opt-t 801 { font-weight: 600; 802 } 803 .qs-opt-d 804 { margin-top: 0.15em; 805 color: var(--qs-muted); 806 font-size: 88%; 807 } 808 809 /* ===== checkbox row ===== */ 810 .qs-chk 811 { display: flex; 812 gap: 0.55em; 813 align-items: flex-start; 814 margin-top: 0.6em; 815 cursor: pointer; 816 } 817 .qs-chk input 818 { flex: 0 0 auto; 819 margin: 0.2em 0 0; 820 } 821 .qs-chk-sub 822 { margin-top: 0.15em; 823 color: var(--qs-muted); 824 font-size: 88%; 825 } 826 827 /* ===== ad-size grid ===== */ 828 .qs-sizes 829 { display: flex; 830 flex-wrap: wrap; 831 gap: 0.4em; 832 margin-top: 0.4em; 833 } 834 .qs-size 835 { padding: 0.35em 0.6em; 836 border: 1px solid var(--qs-line); 837 border-radius: 0.5em; 838 background-color: var(--qs-chrome); 839 color: var(--qs-muted); 840 font: inherit; 841 font-size: 88%; 842 font-weight: 700; 843 cursor: pointer; 844 } 845 .qs-size:hover 846 { border-color: var(--qs-line-2); 847 color: var(--qs-fg); 848 } 849 .qs-size.qs-on 850 { border-color: var(--qs-brand); 851 background-color: var(--qs-brand-soft);
852 color: var(--qs-brand-fg); 853 } 854 .qs-size-custom 855 { display: flex; 856 gap: 0.4em; 857 align-items: center; 858 margin-top: 0.55em; 859 color: var(--qs-muted); 860 font-size: 88%; 861 } 862 .qs-num 863 { width: 5em; 864 padding: 0.4em 0.5em; 865 border: 1px solid var(--qs-line); 866 border-radius: 0.5em; 867 background-color: var(--qs-chrome); 868 color: var(--qs-fg); 869 font: inherit; 870 font-size: 100%; 871 } 872 873 /* ===== how broad is this selector ===== */ 874 .qs-scope 875 { margin-top: 0.6em; 876 padding: 0.6em 0.7em; 877 border: 1px solid var(--qs-line); 878 border-radius: 0.6em; 879 background-color: var(--qs-chrome); 880 } 881 .qs-scope-top 882 { display: flex; 883 gap: 0.5em; 884 align-items: center; 885 } 886 .qs-scope-dot 887 { flex: 0 0 auto; 888 width: 0.6em; 889 height: 0.6em; 890 border-radius: 50%; 891 background-color: currentColor; 892 } 893 .qs-scope-label 894 { font-weight: 700; 895 } 896 .qs-scope-tag 897 { flex: 0 0 auto; 898 margin-left: auto; 899 color: var(--qs-muted-2); 900 font-size: 86%; 901 } 902 .qs-scope-meter 903 { position: relative; 904 height: 0.35em; 905 margin: 0.5em 0 0.3em; 906 border-radius: 1em; 907 background-color: var(--qs-chrome-3); 908 overflow: hidden; 909 } 910 .qs-scope-bar 911 { position: absolute; 912 top: 0; 913 left: 0; 914 height: 100%; 915 border-radius: 1em; 916 background-color: currentColor; 917 } 918 .qs-scope-scale 919 { display: flex; 920 justify-content: space-between; 921 color: var(--qs-muted-2); 922 font-size: 80%; 923 } 924 .qs-scope-desc 925 { margin-top: 0.4em; 926 color: var(--qs-muted); 927 font-size: 88%; 928 } 929 .qs-narrow 930 { color: var(--qs-brand-fg); 931 } 932 .qs-wide 933 { color: #F0B429; 934 } 935 936 /* ===== error banner ===== */ 937 .qs-err 938 { display: flex; 939 gap: 0.6em; 940 align-items: flex-start; 941 margin: 0.8em 0.8em 0; 942 padding: 0.7em 0.8em; 943 border: 1px solid rgba(239, 68, 68, 0.35); 944 border-radius: 0.7em; 945 background-color: var(--qs-danger-soft);
946 color: var(--qs-danger-fg); 947 font-size: 92%; 948 } 949 .qs-err > div 950 { flex: 10000 1 0; 951 } 952 953 /* ===== controls ===== */ 954 .qs-btn 955 { display: inline-flex; 956 align-items: center; 957 gap: 0.4em; 958 padding: 0.45em 0.9em; 959 border: 1px solid var(--qs-line-2); 960 border-radius: 0.5em; 961 background-color: var(--qs-chrome-2); 962 color: var(--qs-fg); 963 font: inherit; 964 font-weight: 600; 965 white-space: nowrap; 966 cursor: pointer; 967 } 968 .qs-btn:hover:not(:disabled) 969 { background-color: var(--qs-chrome-3); 970 } 971 .qs-btn:disabled 972 { opacity: 0.55; 973 cursor: default; 974 } 975 .qs-btn-primary 976 { border-color: transparent; 977 background-color: var(--qs-brand); 978 color: #08231C; 979 } 980 .qs-btn-primary:hover:not(:disabled) 981 { background-color: #15CE97; 982 } 983 .qs-btn-row 984 { display: flex; 985 flex-wrap: wrap; 986 gap: 0.5em; 987 align-items: center; 988 } 989 990 .qs-select 991 { width: 100%; 992 padding: 0.45em 0.6em; 993 border: 1px solid var(--qs-line); 994 border-radius: 0.5em; 995 background-color: var(--qs-chrome-2); 996 color: var(--qs-fg); 997 font: inherit; 998 } 999 1000 /* ===== pick states ===== */ 1001 .qs-callout 1002 { display: flex; 1003 gap: 0.6em; 1004 align-items: center; 1005 padding: 0.8em; 1006 border: 1px dashed var(--qs-brand); 1007 border-radius: 0.7em; 1008 background-color: var(--qs-brand-soft); 1009 color: var(--qs-brand-fg); 1010 } 1011 .qs-callout > div 1012 { flex: 10000 1 0; 1013 } 1014 1015 .qs-selector 1016 { padding: 0.55em 0.7em; 1017 border: 1px solid var(--qs-line); 1018 border-radius: 0.5em; 1019 background-color: var(--qs-chrome-2); 1020 color: var(--qs-brand-fg); 1021 font-family: var(--qs-mono); 1022 font-size: 92%; 1023 word-break: break-all; 1024 } 1025 1026 .qs-tree 1027 { margin: 0.5em 0 0; 1028 padding: 0.35em; 1029 border: 1px solid var(--qs-line); 1030 border-radius: 0.5em; 1031 background-color: var(--qs-chrome-2); 1032 max-height: 12em; 1033 overflow: auto; 1034 } 1035 .qs-tree-row 1036 { display: block; 1037 width: 100%; 1038 padding: 0.2em 0.45em; 1039 border: none; 1040 border-radius: 0.35em; 1041 background: transparent; 1042 color: var(--qs-muted); 1043 font-family: var(--qs-mono); 1044 font-size: 92%; 1045 text-align: left; 1046 white-space: nowrap; 1047 overflow: hidden; 1048 text-overflow: ellipsis; 1049 cursor: pointer; 1050 } 1051 .qs-tree-row:hover 1052 { background-color: var(--qs-chrome-3); 1053 color: var(--qs-fg); 1054 } 1055 .qs-tree-row.qs-on 1056 { background-color: var(--qs-brand-soft); 1057 color: var(--qs-brand-fg); 1058 font-weight: 700; 1059 } 1060 1061 /* A "name = value" row. The two are the same length and the same monospace on their own, so 1062 without a weight and a colour between them the eye has to parse the '=' to tell which half it 1063 is reading. The name is what the row is chosen by, so it gets the emphasis; the value is 1064 evidence, so it recedes. 1065 Each half ellipsises separately: the row used to clip as one string, and a long cookie name 1066 would then push the value off the end entirely - the half that says whether it is the right 1067 cookie. */ 1068 .qs-tree-row.qs-kv 1069 { display: flex; 1070 gap: 0.35em; 1071 align-items: baseline; 1072 } 1073 .qs-kv-k 1074 { flex: 0 1 auto; 1075 min-width: 3em; 1076 max-width: 60%; 1077 overflow: hidden; 1078 color: var(--qs-fg); 1079 font-weight: 700; 1080 text-overflow: ellipsis; 1081 } 1082 .qs-kv-sep 1083 { flex: 0 0 auto; 1084 color: var(--qs-muted-2); 1085 } 1086 .qs-kv-v 1087 { flex: 1 1 auto; 1088 min-width: 0; 1089 overflow: hidden; 1090 color: var(--qs-muted); 1091 font-weight: 400; 1092 text-overflow: ellipsis; 1093 } 1094 .qs-kv-v.qs-empty 1095 { opacity: 0.6; 1096 font-style: italic; 1097 } 1098 /* Selected: the row already carries the brand colour, so the two halves separate by weight 1099 alone rather than fighting it with a second colour. */ 1100 .qs-tree-row.qs-on .qs-kv-k, 1101 .qs-tree-row.qs-on .qs-kv-v, 1102 .qs-tree-row.qs-on .qs-kv-sep 1103 { color: inherit; 1104 } 1105 .qs-tree-row.qs-on .qs-kv-v 1106 { opacity: 0.75; 1107 } 1108 .qs-tree-row:hover .qs-kv-v 1109 { color: var(--qs-fg); 1110 } 1111 1112 /* ===== "Describe what to grab" AI card ===== 1113 The mockup's own treatment: the one purple surface in a green panel, so the box that writes 1114 the form for you doesn't read as another of the form's own sections. */ 1115 .qs-ai 1116 { margin-bottom: 1.2em; 1117 padding: 0.15em 0.75em 0.55em; 1118 border: 1px solid rgba(167, 139, 250, 0.28); 1119 border-radius: 0.7em; 1120 background-image: linear-gradient(180deg, rgba(167, 139, 250, 0.09), rgba(167, 139, 250, 0)); 1121 } 1122 .qs-ai + .qs-sec 1123 { margin-top: 0; 1124 padding-top: 0; 1125 border-top: none; 1126 } 1127 /* A framed section after the AI card keeps its own border, so it only needs the gap. */ 1128 .qs-ai + .qs-fold 1129 { margin-top: 0.7em; 1130 } 1131 .qs-ai-head 1132 { display: flex; 1133 gap: 0.5em; 1134 align-items: center; 1135 width: 100%; 1136 padding: 0.6em 0; 1137 border: none; 1138 background: transparent; 1139 color: inherit; 1140 font: inherit; 1141 text-align: left; 1142 cursor: pointer; 1143 } 1144 .qs-ai-head h3 1145 { flex: 10000 1 0; 1146 margin: 0; 1147 font-size: 100%; 1148 font-weight: 600; 1149 } 1150 .qs-ai-ico 1151 { display: grid; 1152 flex: 0 0 auto; 1153 place-items: center; 1154 width: 1.7em; 1155 height: 1.7em; 1156 border-radius: 0.4em; 1157 background-color: rgba(167, 139, 250, 0.16); 1158 color: #C4B5FD; 1159 } 1160 .qs-ai-ico svg 1161 { width: 0.95em; 1162 height: 0.95em; 1163 } 1164 .qs-ai-tag 1165 { flex: 0 0 auto; 1166 color: #C4B5FD; 1167 font-size: 80%; 1168 font-weight: 700; 1169 letter-spacing: 0.06em; 1170 } 1171 .qs-ai-chev 1172 { display: flex; 1173 flex: 0 0 auto; 1174 color: var(--qs-muted-2); 1175 transition: transform 0.15s; 1176 } 1177 .qs-ai-chev.qs-on 1178 { transform: rotate(180deg); 1179 } 1180 1181 .qs-ai-input 1182 { display: block; 1183 width: 100%; 1184 padding: 0.6em 0.7em; 1185 border: 1px solid var(--qs-line); 1186 border-radius: 0.5em; 1187 background-color: var(--qs-chrome-2); 1188 color: var(--qs-fg); 1189 font: inherit; 1190 line-height: 1.5; 1191 resize: vertical; 1192 } 1193 .qs-ai-input:focus 1194 { border-color: #A78BFA; 1195 outline: none; 1196 } 1197 .qs-ai-chips 1198 { display: flex; 1199 flex-wrap: wrap; 1200 gap: 0.35em; 1201 margin-top: 0.55em; 1202 } 1203 .qs-ai-chip 1204 { padding: 0.3em 0.7em; 1205 border: 1px solid var(--qs-line-2); 1206 border-radius: 999px; 1207 background-color: var(--qs-chrome-2); 1208 color: var(--qs-muted); 1209 font: inherit; 1210 font-size: 88%; 1211 cursor: pointer; 1212 } 1213 .qs-ai-chip:hover:not(:disabled) 1214 { border-color: #A78BFA; 1215 color: var(--qs-fg); 1216 } 1217 .qs-ai-chip:disabled 1218 { opacity: 0.55; 1219 cursor: default; 1220 } 1221 .qs-ai-btn 1222 { justify-content: center; 1223 width: 100%; 1224 margin-top: 0.6em; 1225 border-color: rgba(167, 139, 250, 0.45); 1226 background-color: rgba(167, 139, 250, 0.18);
1227 color: #E4CCFF; 1228 } 1229 .qs-ai-btn:hover:not(:disabled) 1230 { background-color: rgba(167, 139, 250, 0.3); 1231 color: #FFF; 1232 } 1233 .qs-ai-status 1234 { margin-top: 0.5em; 1235 color: var(--qs-muted-2); 1236 font-family: var(--qs-mono); 1237 font-size: 88%; 1238 word-break: break-all; 1239 } 1240 .qs-ai-warn 1241 { border-color: rgba(239, 68, 68, 0.35); 1242 border-style: solid; 1243 background-color: var(--qs-danger-soft); 1244 color: var(--qs-danger-fg); 1245 } 1246 1247 .qs-ai-result 1248 { margin-top: 0.8em; 1249 padding: 0.75em; 1250 border: 1px solid rgba(167, 139, 250, 0.3); 1251 border-radius: 0.7em; 1252 background-color: rgba(167, 139, 250, 0.07); 1253 } 1254 .qs-ai-result-head 1255 { display: flex; 1256 gap: 0.45em; 1257 align-items: center; 1258 margin-bottom: 0.6em; 1259 color: #C4B5FD; 1260 font-size: 80%; 1261 font-weight: 700; 1262 letter-spacing: 0.06em; 1263 text-transform: uppercase; 1264 } 1265 .qs-ai-field + .qs-ai-field 1266 { margin-top: 0.5em; 1267 } 1268 .qs-ai-k 1269 { margin-bottom: 0.1em; 1270 color: var(--qs-muted-2); 1271 font-size: 78%; 1272 font-weight: 700; 1273 letter-spacing: 0.04em; 1274 text-transform: uppercase; 1275 } 1276 .qs-ai-v 1277 { font-weight: 600; 1278 overflow-wrap: break-word; 1279 } 1280 .qs-ai-v.qs-ai-mono 1281 { color: #C4B5FD; 1282 font-family: var(--qs-mono); 1283 font-size: 92%; 1284 font-weight: 400; 1285 word-break: break-all; 1286 } 1287 1288 /* ===== collapsed handle ===== */ 1289 .qs-handle 1290 { position: fixed; 1291 top: 40vh; 1292 right: 0; 1293 z-index: 2147483647; 1294 display: flex; 1295 align-items: center; 1296 gap: 0.4em; 1297 padding: 0.6em 0.7em; 1298 border: none; 1299 border-radius: 0.7em 0 0 0.7em; 1300 background-color: #12182A; 1301 color: #E8EDF7; 1302 font: normal normal 700 13px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; 1303 cursor: pointer; 1304 box-shadow: 0 0 1em rgba(0, 0, 0, 0.45); 1305 } 1306 .qs-handle.qs-left 1307 { right: auto; 1308 left: 0; 1309 border-radius: 0 0.7em 0.7em 0; 1310 } 1311 1312 /* ===== spinner ===== */ 1313 .qs-spin 1314 { display: inline-block; 1315 width: 1em; 1316 height: 1em; 1317 border: 2px solid rgba(255, 255, 255, 0.25); 1318 border-top-color: #12B886; 1319 border-radius: 50%; 1320 animation: qs-spin 0.8s linear infinite; 1321 } 1322 @keyframes qs-spin 1323 { to 1324 { transform: rotate(360deg); 1325 } 1326 } 1327`; 1328var ic = { 1329 target: /* @__PURE__ */ u2("svg", { 1330 viewBox: "0 0 24 24", 1331 fill: "none", 1332 stroke: "currentColor", 1333 "stroke-width": "2", 1334 children: [
1335 /* @__PURE__ */ u2("circle", { 1336 cx: "12", 1337 cy: "12", 1338 r: "9" 1339 }), 1340 /* @__PURE__ */ u2("circle", { 1341 cx: "12", 1342 cy: "12", 1343 r: "4" 1344 }), 1345 /* @__PURE__ */ u2("path", { 1346 d: "M12 1v3M12 20v3M1 12h3M20 12h3" 1347 }) 1348 ] 1349 }), 1350 layout: /* @__PURE__ */ u2("svg", { 1351 viewBox: "0 0 24 24", 1352 fill: "none", 1353 stroke: "currentColor", 1354 "stroke-width": "2", 1355 children: [ 1356 /* @__PURE__ */ u2("rect", { 1357 x: "3", 1358 y: "3", 1359 width: "18", 1360 height: "18", 1361 rx: "2" 1362 }), 1363 /* @__PURE__ */ u2("path", { 1364 d: "M3 9h18M9 21V9" 1365 }) 1366 ] 1367 }), 1368 eye: /* @__PURE__ */ u2("svg", { 1369 viewBox: "0 0 24 24", 1370 fill: "none", 1371 stroke: "currentColor", 1372 "stroke-width": "2", 1373 children: [ 1374 /* @__PURE__ */ u2("path", { 1375 d: "M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" 1376 }), 1377 /* @__PURE__ */ u2("circle", { 1378 cx: "12", 1379 cy: "12", 1380 r: "3" 1381 }) 1382 ] 1383 }), 1384 warn: /* @__PURE__ */ u2("svg", { 1385 viewBox: "0 0 24 24", 1386 fill: "none", 1387 stroke: "currentColor", 1388 "stroke-width": "2", 1389 children: [
1390 /* @__PURE__ */ u2("path", { 1391 d: "M12 3l9 16H3z" 1392 }), 1393 /* @__PURE__ */ u2("path", { 1394 d: "M12 9v5M12 17h.01" 1395 }) 1396 ] 1397 }), 1398 check: /* @__PURE__ */ u2("svg", { 1399 viewBox: "0 0 24 24", 1400 fill: "none", 1401 stroke: "currentColor", 1402 "stroke-width": "2", 1403 children: /* @__PURE__ */ u2("path", { 1404 d: "M20 6L9 17l-5-5" 1405 }) 1406 }), 1407 cross: /* @__PURE__ */ u2("svg", { 1408 viewBox: "0 0 24 24", 1409 fill: "none", 1410 stroke: "currentColor", 1411 "stroke-width": "2", 1412 children: /* @__PURE__ */ u2("path", { 1413 d: "M18 6L6 18M6 6l12 12" 1414 }) 1415 }), 1416 minus: /* @__PURE__ */ u2("svg", { 1417 viewBox: "0 0 24 24", 1418 fill: "none", 1419 stroke: "currentColor", 1420 "stroke-width": "2", 1421 children: /* @__PURE__ */ u2("path", { 1422 d: "M5 12h14" 1423 }) 1424 }), 1425 swap: /* @__PURE__ */ u2("svg", { 1426 viewBox: "0 0 24 24", 1427 fill: "none", 1428 stroke: "currentColor", 1429 "stroke-width": "2", 1430 children: /* @__PURE__ */ u2("path", { 1431 d: "M7 8h13l-3-3M17 16H4l3 3" 1432 }) 1433 }), 1434 sparkle: /* @__PURE__ */ u2("svg", { 1435 viewBox: "0 0 24 24", 1436 fill: "none", 1437 stroke: "currentColor", 1438 "stroke-width": "2", 1439 "stroke-linejoin": "round", 1440 children: /* @__PURE__ */ u2("path", { 1441 d: "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z" 1442 }) 1443 }), 1444 chevronDown: /* @__PURE__ */ u2("svg", { 1445 viewBox: "0 0 24 24", 1446 fill: "none", 1447 stroke: "currentColor", 1448 "stroke-width": "2", 1449 "stroke-linecap": "round", 1450 "stroke-linejoin": "round", 1451 children: /* @__PURE__ */ u2("path", { 1452 d: "M6 9l6 6 6-6" 1453 }) 1454 }) 1455}; 1456function PanelSection(props) { 1457 return /* @__PURE__ */ u2("div", { 1458 class: "qs-fold" + (props.isOpen ? "" : " qs-closed"), 1459 children: [
1460 /* @__PURE__ */ u2("button", { 1461 type: "button", 1462 class: "qs-fold-head", 1463 onClick: props.onToggle, 1464 children: [ 1465 /* @__PURE__ */ u2("span", { 1466 class: "qs-fold-ico", 1467 children: props.icon 1468 }), 1469 /* @__PURE__ */ u2("span", { 1470 class: "qs-fold-name", 1471 children: props.title 1472 }), 1473 props.meta != null && props.meta !== "" && /* @__PURE__ */ u2("span", { 1474 class: "qs-fold-meta", 1475 children: props.meta 1476 }), 1477 /* @__PURE__ */ u2("span", { 1478 class: "qs-fold-chev", 1479 children: ic.chevronDown 1480 }) 1481 ] 1482 }), 1483 props.isOpen && /* @__PURE__ */ u2("div", { 1484 class: "qs-fold-body", 1485 children: props.children 1486 }) 1487 ] 1488 }); 1489} 1490function SimulatorPanel(props) { 1491 const [isLeft, setIsLeft] = p2(false); 1492 const [isMinimized, setIsMinimized] = p2(false); 1493 const sideClass = isLeft ? " qs-left" : ""; 1494 if (isMinimized) { 1495 return /* @__PURE__ */ u2("button", { 1496 type: "button", 1497 class: "qs-handle" + sideClass, 1498 title: "Reopen the Personyze picker", 1499 onClick: () => setIsMinimized(false), 1500 children: [ 1501 ic.target, 1502 "Personyze" 1503 ] 1504 }); 1505 } 1506 return /* @__PURE__ */ u2("div", { 1507 class: "qs-panel" + sideClass + (props.panelClass ? " " + props.panelClass : ""), 1508 children: [
1509 /* @__PURE__ */ u2("div", { 1510 class: "qs-head", 1511 children: [ 1512 props.logoSrc && /* @__PURE__ */ u2("img", { 1513 class: "qs-logo", 1514 src: props.logoSrc, 1515 alt: "" 1516 }), 1517 /* @__PURE__ */ u2("div", { 1518 class: "qs-title", 1519 children: [ 1520 /* @__PURE__ */ u2("div", { 1521 class: "qs-title-main", 1522 children: props.title 1523 }), 1524 /* @__PURE__ */ u2("div", { 1525 class: "qs-title-sub", 1526 children: props.subtitle 1527 }) 1528 ] 1529 }), 1530 /* @__PURE__ */ u2("button", { 1531 type: "button", 1532 class: "qs-icon", 1533 title: "Move the window to the other side", 1534 onClick: () => setIsLeft(!isLeft), 1535 children: ic.swap 1536 }), 1537 /* @__PURE__ */ u2("button", { 1538 type: "button", 1539 class: "qs-icon", 1540 title: "Collapse the window", 1541 onClick: () => setIsMinimized(true), 1542 children: ic.minus 1543 }),
1544 /* @__PURE__ */ u2("button", { 1545 type: "button", 1546 class: "qs-icon", 1547 title: "Close the picker", 1548 onClick: props.onClose, 1549 children: ic.cross 1550 }) 1551 ] 1552 }), 1553 props.error && /* @__PURE__ */ u2("div", { 1554 class: "qs-err", 1555 children: [ 1556 ic.warn, 1557 /* @__PURE__ */ u2("div", { 1558 children: props.error 1559 }), 1560 props.onDismissError && /* @__PURE__ */ u2("button", { 1561 type: "button", 1562 class: "qs-icon", 1563 title: "Dismiss", 1564 onClick: props.onDismissError, 1565 children: ic.cross 1566 }) 1567 ] 1568 }), 1569 /* @__PURE__ */ u2("div", { 1570 class: "qs-body", 1571 children: props.children 1572 }), 1573 props.footer && /* @__PURE__ */ u2("div", { 1574 class: "qs-foot", 1575 children: props.footer 1576 }) 1577 ] 1578 }); 1579} 1580
1581// src/modules/picker/private/selector.ts 1582var RE_VOLATILE_TAIL = /[_\-.][0-9A-F]{4,}$/i; 1583var RE_CSS_IN_JS = /^(?:css|sc|jsx|emotion|svelte|ng)-[0-9a-z]{4,}$/i; 1584var RE_OWN_CLASS = /^(?:\$|_st|personyze|qs-)/i; 1585function isStableName(name) { 1586 return !!name && !RE_VOLATILE_TAIL.test(name) && !RE_CSS_IN_JS.test(name) && !RE_OWN_CLASS.test(name); 1587} 1588function cssEscape(name) { 1589 return typeof CSS != "undefined" && CSS.escape ? CSS.escape(name) : name.replace(/[^\w-]/g, (ch) => "\\" + ch); 1590} 1591function matchesOnly(selector, elem) { 1592 if (!selector) { 1593 return false; 1594 } 1595 try { 1596 const found = elem.ownerDocument.querySelectorAll(selector); 1597 return found.length == 1 && found[0] == elem; 1598 } catch { 1599 return false; 1600 } 1601} 1602function indexOfType(elem) { 1603 let index = 1; 1604 for (const sib of elem.parentElement?.children ?? []) { 1605 if (sib == elem) { 1606 break; 1607 } 1608 if (sib.localName == elem.localName) { 1609 index++; 1610 } 1611 } 1612 return index; 1613} 1614function groupStep(localName, classNames) { 1615 let step = localName; 1616 for (const name of classNames) { 1617 if (isStableName(name)) { 1618 step += "." + cssEscape(name); 1619 } 1620 } 1621 return step; 1622} 1623function elemToStep(elem) { 1624 const step = groupStep(elem.localName, elem.classList); 1625 let nMatching = 0; 1626 for (const sib of elem.parentElement?.children ?? []) { 1627 try { 1628 if (sib.matches(step)) { 1629 nMatching++; 1630 } 1631 } catch { 1632 nMatching = 2; 1633 break; 1634 } 1635 } 1636 return nMatching > 1 ? `${step}:nth-of-type(${indexOfType(elem)})` : step; 1637} 1638function structuralPath(elem) { 1639 const doc = elem.ownerDocument; 1640 const steps = new Array(); 1641 for (let node = elem; node && node != doc.documentElement; node = node.parentElement) { 1642 if (node == doc.body) { 1643 steps.unshift("body"); 1644 break; 1645 } 1646 steps.unshift(`${node.localName}:nth-of-type(${indexOfType(node)})`); 1647 } 1648 return steps.join(" > "); 1649} 1650function elemToSelector(elem) { 1651 const doc = elem.ownerDocument; 1652 if (!doc || !doc.body || !doc.body.contains(elem)) { 1653 return ""; 1654 } 1655 const steps = new Array(); 1656 for (let node = elem; node && node != doc.body && node != doc.documentElement; node = node.parentElement) { 1657 const id = node.getAttribute("id") ?? ""; 1658 if (isStableName(id) && doc.querySelectorAll("#" + cssEscape(id)).length == 1) { 1659 steps.unshift("#" + cssEscape(id)); 1660 break; 1661 } 1662 steps.unshift(elemToStep(node)); 1663 const selector2 = steps.join(" > "); 1664 if (matchesOnly(selector2, elem)) { 1665 return selector2; 1666 } 1667 } 1668 const selector = steps.join(" > "); 1669 return matchesOnly(selector, elem) ? selector : structuralPath(elem); 1670} 1671function findMatches(selector, doc = document) { 1672 if (!selector) { 1673 return []; 1674 } 1675 try { 1676 return Array.from(doc.querySelectorAll(selector)); 1677 } catch { 1678 return []; 1679 } 1680} 1681function describeElem(elem) { 1682 let text = elem.localName; 1683 if (elem.id) { 1684 text += "#" + elem.id; 1685 } 1686 for (const name of elem.classList) { 1687 text += "." + name; 1688 } 1689 return text; 1690} 1691function ancestorChain(elem) { 1692 const doc = elem.ownerDocument; 1693 const chain = new Array(); 1694 for (let node = elem; node && node != doc.body && node != doc.documentElement; node = node.parentElement) { 1695 chain.unshift(node); 1696 } 1697 return chain; 1698} 1699
1700// src/modules/picker/private/picker.ts 1701var Z_INDEX = 2147483646; 1702var Picker = class { 1703 #layer; 1704 #highlights = new Array(); 1705 #select; 1706 #hovered; 1707 #isTracking = false; 1708 #timer = 0; 1709 /** Outline these elements until the next call. `label` writes the element's name into the 1710 corner of the box, which is what makes a hover read as "this is what you'd get". 1711 **/ 1712 highlight(elems, color = "#12B886", label = false) { 1713 this.#highlights = []; 1714 for (const elem of elems) { 1715 if (elem && elem.isConnected) { 1716 this.#highlights.push({ 1717 elem, 1718 color, 1719 label 1720 }); 1721 } 1722 } 1723 this.#draw(); 1724 this.#trackViewport(this.#highlights.length > 0); 1725 } 1726 /** Enter picking mode: highlight what's under the cursor, and swallow the next click. 1727 **/ 1728 selectBegin(options) { 1729 this.selectEnd(); 1730 this.#select = options; 1731 this.#hovered = void 0; 1732 for (const type of [ 1733 "mousemove", 1734 "mouseover", 1735 "click", 1736 "mousedown", 1737 "mouseup", 1738 "keydown" 1739 ]) { 1740 document.addEventListener(type, this.#onEvent, true); 1741 } 1742 } 1743 selectEnd() { 1744 if (this.#select) { 1745 this.#select = void 0; 1746 this.#hovered = void 0; 1747 for (const type of [ 1748 "mousemove", 1749 "mouseover", 1750 "click", 1751 "mousedown", 1752 "mouseup", 1753 "keydown" 1754 ]) { 1755 document.removeEventListener(type, this.#onEvent, true); 1756 } 1757 this.highlight([]); 1758 } 1759 } 1760 isSelecting() { 1761 return !!this.#select; 1762 } 1763 destroy() { 1764 this.selectEnd(); 1765 this.highlight([]); 1766 this.#layer?.remove(); 1767 this.#layer = void 0; 1768 } 1769 /** Single capture-phase handler for the whole picking session. Capture phase and 1770 `stopPropagation()` are what keep the page from reacting: the click never reaches the 1771 page's own listeners, and `preventDefault()` keeps links and submit buttons inert. 1772 **/ 1773 #onEvent = (event) => { 1774 const select = this.#select; 1775 if (!select) { 1776 return; 1777 } 1778 if (event.type == "keydown") { 1779 if (event.key == "Escape") { 1780 event.preventDefault(); 1781 event.stopPropagation(); 1782 select.onSelect(null); 1783 } 1784 return; 1785 } 1786 const target = this.#targetOf(event, select.ignore); 1787 if (!target) { 1788 if (this.#hovered) { 1789 this.#hovered = void 0; 1790 this.highlight([]); 1791 select.onHover?.(null); 1792 } 1793 return; 1794 } 1795 event.preventDefault(); 1796 event.stopPropagation(); 1797 if (event.type == "click") { 1798 select.onSelect(target); 1799 } else if (event.type == "mousemove" || event.type == "mouseover") { 1800 if (this.#hovered != target) { 1801 this.#hovered = target; 1802 this.highlight([ 1803 target 1804 ], "#12B886", true); 1805 select.onHover?.(target); 1806 } 1807 } 1808 }; 1809 /** The element the event points at, or null when it's the tool's own UI. `composedPath()` is 1810 what sees through the panel's shadow root, whose events retarget to the host element. 1811 **/ 1812 #targetOf(event, ignore) { 1813 const path = typeof event.composedPath == "function" ? event.composedPath() : []; 1814 const target = path[0] ?? event.target; 1815 if (!(target instanceof Element)) { 1816 return null; 1817 } 1818 for (const root of ignore) { 1819 if (root == target || root.contains(target) || path.indexOf(root) != -1) { 1820 return null; 1821 } 1822 } 1823 return target; 1824 } 1825 #draw = () => { 1826 const layer = this.#ensureLayer(); 1827 while (layer.childNodes.length > this.#highlights.length) { 1828 layer.lastChild.remove(); 1829 } 1830 while (layer.childNodes.length < this.#highlights.length) { 1831 const box = document.createElement("div"); 1832 box.appendChild(document.createElement("span")); 1833 layer.appendChild(box); 1834 } 1835 for (let i4 = 0; i4 < this.#highlights.length; i4++) { 1836 const { elem, color, label } = this.#highlights[i4]; 1837 const box = layer.childNodes[i4]; 1838 const rect = elem.getBoundingClientRect(); 1839 box.style.cssText = `position:absolute; box-sizing:border-box; pointer-events:none; border:2px solid ${color}; background-color:${color}22; border-radius:2px; left:${rect.left + globalThis.scrollX}px; top:${rect.top + globalThis.scrollY}px; width:${Math.max(rect.width, 4)}px; height:${Math.max(rect.height, 4)}px`; 1840 const tag = box.firstChild; 1841 tag.textContent = !label ? "" : describeElem(elem).slice(0, 80); 1842 tag.style.cssText = !label ? "display:none" : `position:absolute; left:0; top:-1.5em; max-width:100%; overflow:hidden; white-space:nowrap; box-sizing:border-box; padding:0 0.4em; border-radius:2px; background-color:${color}; color:#08231C; font:600 11px/1.5em ui-monospace, Menlo, Consolas, monospace`; 1843 } 1844 }; 1845 #ensureLayer() { 1846 let layer = this.#layer; 1847 if (!layer?.isConnected) { 1848 layer = document.createElement("div"); 1849 layer.style.cssText = `position:absolute; left:0; top:0; width:0; height:0; margin:0; padding:0; border:none; pointer-events:none; z-index:${Z_INDEX}`; 1850 document.body.appendChild(layer); 1851 this.#layer = layer; 1852 } 1853 return layer; 1854 } 1855 /** Highlight boxes are placed in page coordinates, so they only need redrawing when the page 1856 moves under them - but an element can also be resized by the page itself, hence the poll. 1857 **/ 1858 #trackViewport(on) { 1859 if (on != this.#isTracking) { 1860 this.#isTracking = on; 1861 if (on) { 1862 globalThis.addEventListener("scroll", this.#draw, true); 1863 globalThis.addEventListener("resize", this.#draw); 1864 this.#timer = setInterval(this.#draw, 500); 1865 } else { 1866 globalThis.removeEventListener("scroll", this.#draw, true); 1867 globalThis.removeEventListener("resize", this.#draw); 1868 clearInterval(this.#timer); 1869 } 1870 } 1871 } 1872}; 1873
1874// src/modules/tracker/private/tracker.ts 1875function getPageUrl() { 1876 try { 1877 return getTracker()?.get_location?.()?.href || location.href; 1878 } catch { 1879 return location.href; 1880 } 1881} 1882var GRAB_MAX_CHARS = 150; 1883function grabValue(elem) { 1884 const value = elem.value; 1885 const text = typeof value == "string" ? value : elem.textContent ?? ""; 1886 return text.trim().replace(/\s+/g, " ").substring(0, GRAB_MAX_CHARS).trim(); 1887} 1888function getTracker() { 1889 return globalThis._S_T; 1890} 1891function getPanelWindow() { 1892 const scope = globalThis; 1893 const thisWindow = globalThis; 1894 return scope._S_T_OPENER ?? globalThis.opener ?? (parent != thisWindow ? parent : null); 1895} 1896function resolveHtmlId(htmlId) { 1897 const tracker = getTracker(); 1898 if (tracker?.id) { 1899 try { 1900 const found = tracker.id(htmlId); 1901 if (found instanceof Element) { 1902 return found; 1903 } 1904 } catch (e3) { 1905 console.error(e3); 1906 } 1907 } 1908 try { 1909 return document.querySelector(htmlId); 1910 } catch { 1911 return null; 1912 } 1913} 1914
1915// src/modules/toolbridge/private/toolbridge.ts 1916var ACK_TIMEOUT = 4e4; 1917var RESEND_EACH = 1e3; 1918var GET_VALUE_TRIES = 60; 1919var MESSAGE_TYPE_GET_VALUE = "(GET_VALUE)"; 1920var MESSAGE_TYPE_VALUE = "(VALUE)"; 1921var MESSAGE_TYPE_SLAVE = "slave"; 1922var ToolBridge = class { 1923 #options; 1924 #pending = new Array(); 1925 #timer = 0; 1926 #isStopped = false; 1927 #lastValue = null; 1928 constructor(options) { 1929 this.#options = options; 1930 } 1931 /** Start listening, then ask the panel for the value being edited. Resolves true once the panel 1932 has answered, false if it never did. 1933 **/ 1934 async start() { 1935 globalThis.addEventListener("message", this.#onMessage); 1936 for (let i4 = 0; i4 < GET_VALUE_TRIES; i4++) { 1937 if (this.#isStopped || await this.#send({ 1938 get_value: true 1939 }, MESSAGE_TYPE_GET_VALUE)) { 1940 return !this.#isStopped; 1941 } 1942 } 1943 return false; 1944 } 1945 /** Hand the result back to the panel. Resolves true once the panel acknowledges it - the caller 1946 must not close the window before that, or the result is lost. 1947 **/ 1948 setValue(value) { 1949 this.#lastValue = value; 1950 return this.#send({ 1951 value 1952 }, MESSAGE_TYPE_VALUE); 1953 } 1954 /** Push an incremental update to the panel - for the WYSIWYG editor, `{page_is_loaded, href, 1955 n_changes, html_changes}`. Resolves true once the panel acknowledges it. 1956 1957 Only the latest one matters, so an unanswered previous update is superseded rather than 1958 queued: a burst of keystrokes must not turn into a backlog of resends. 1959 **/ 1960 reportMessage(messageData) { 1961 return this.#send({ 1962 message_data: messageData 1963 }, MESSAGE_TYPE_SLAVE); 1964 } 1965 destroy() { 1966 this.#isStopped = true; 1967 globalThis.removeEventListener("message", this.#onMessage); 1968 clearInterval(this.#timer); 1969 this.#timer = 0; 1970 for (const pending of this.#pending.splice(0)) { 1971 pending.resolve(false); 1972 } 1973 } 1974 #send(message, messageType) { 1975 message.buffer_key = this.#options.bufferKey; 1976 message.message_type = messageType; 1977 for (let i4 = this.#pending.length - 1; i4 >= 0; i4--) { 1978 if (this.#pending[i4].message.message_type == messageType) { 1979 this.#pending.splice(i4, 1)[0].resolve(false); 1980 } 1981 } 1982 this.#post(message); 1983 return new Promise((resolve) => { 1984 const now = Date.now(); 1985 this.#pending.push({ 1986 message, 1987 resolve, 1988 startTime: now, 1989 lastTime: now 1990 }); 1991 this.#startStopResend(); 1992 }); 1993 } 1994 /** Reply that needs no acknowledgement of its own: it IS the acknowledgement of `messageType`. 1995 **/ 1996 #postAck(messageType, extra) { 1997 this.#post({ 1998 ...extra, 1999 buffer_key: this.#options.bufferKey, 2000 message_type: messageType 2001 }); 2002 } 2003 #post(message) { 2004 getPanelWindow()?.postMessage(message, this.#options.guiOrigin); 2005 } 2006 #onMessage = (event) => { 2007 const { guiOrigin, bufferKey, onValue, onMessageData } = this.#options; 2008 if (guiOrigin != "*" && event.origin != guiOrigin) { 2009 return; 2010 } 2011 const message = event.data; 2012 if (!message || typeof message != "object") { 2013 return; 2014 } 2015 const messageType = typeof message.message_type == "string" ? message.message_type : ""; 2016 if (!messageType || message.buffer_key != bufferKey) { 2017 return; 2018 } 2019 if ("value" in message) { 2020 const value = message.value; 2021 if (value && typeof value == "object") { 2022 onValue(value); 2023 } 2024 } else if (message.message_data && typeof message.message_data == "object") { 2025 onMessageData?.(message.message_data); 2026 } 2027 const i4 = this.#pending.findIndex((v3) => v3.message.message_type == messageType); 2028 if (i4 != -1) { 2029 this.#pending.splice(i4, 1)[0].resolve(true); 2030 this.#startStopResend(); 2031 } else if (message.get_value === true) { 2032 this.#postAck(messageType, { 2033 value: this.#lastValue 2034 }); 2035 } else if ("value" in message || message.message_data) { 2036 this.#postAck(messageType); 2037 } 2038 }; 2039 #startStopResend() { 2040 if (this.#pending.length == 0) { 2041 clearInterval(this.#timer); 2042 this.#timer = 0; 2043 } else if (this.#timer == 0) { 2044 this.#timer = setInterval(() => { 2045 const now = Date.now(); 2046 for (let i4 = this.#pending.length - 1; i4 >= 0; i4--) { 2047 const pending = this.#pending[i4]; 2048 if (now - pending.startTime > ACK_TIMEOUT) { 2049 this.#pending.splice(i4, 1); 2050 pending.resolve(false); 2051 } else if (now - pending.lastTime > RESEND_EACH) {
2052 pending.lastTime = now; 2053 this.#post(pending.message); 2054 } 2055 } 2056 this.#startStopResend(); 2057 }, RESEND_EACH); 2058 } 2059 } 2060}; 2061
2062// src/modules/jsapi/private/jsapi.ts 2063var N_ATTEMPTS = 3; 2064var CACHE_MAX_QUERIES = 32; 2065var MAX_URLENCODED_DATA = 7 * 1024; 2066var config = null; 2067var cache = /* @__PURE__ */ new Map(); 2068function configureJsapi(newConfig) { 2069 config = newConfig; 2070 cache.clear(); 2071} 2072function isJsapiConfigured() { 2073 return config != null; 2074} 2075async function query(sql, params, noCache = false) { 2076 if (!config) { 2077 throw new Error("The Simulator has no database connection."); 2078 } 2079 const postQuery = { 2080 sql, 2081 params 2082 }; 2083 const post = JSON.stringify(postQuery); 2084 if (!noCache) { 2085 const hit = cache.get(post); 2086 if (hit) { 2087 return hit; 2088 } 2089 } 2090 const isBig = post.length > MAX_URLENCODED_DATA; 2091 const response = await fetchRetrying(config.url, { 2092 mode: "cors", 2093 credentials: "include", 2094 headers: { 2095 "Content-Type": isBig ? "application/json" : "application/x-www-form-urlencoded" 2096 }, 2097 method: "POST", 2098 body: isBig ? JSON.stringify({ 2099 data: [ 2100 postQuery 2101 ], 2102 server_id: config.serverId 2103 }) : `data=${encodeURIComponent("[" + post + "]")}&server_id=${config.serverId}` 2104 }); 2105 if (!response.ok) { 2106 throw new Error(response.statusText || `Database request failed (${response.status})`); 2107 } 2108 const resultsets = toResultsets(await response.text()); 2109 if (!noCache && resultsets.every((v3) => v3.fields)) { 2110 while (cache.size >= CACHE_MAX_QUERIES) { 2111 const oldest = cache.keys().next().value; 2112 if (oldest == void 0) { 2113 break; 2114 } 2115 cache.delete(oldest); 2116 } 2117 cache.set(post, resultsets); 2118 } 2119 return resultsets; 2120} 2121async function queryRow(sql, params, noCache = false) { 2122 const resultsets = await query(sql, params, noCache); 2123 return resultsets[0]?.[0]; 2124} 2125async function fetchRetrying(url, init) { 2126 let lastError; 2127 for (let i4 = 0; i4 < N_ATTEMPTS; i4++) { 2128 try { 2129 return await fetch(url, init); 2130 } catch (e3) { 2131 lastError = e3; 2132 } 2133 } 2134 console.error(lastError); 2135 throw new Error("Failed to reach the Personyze server. Please check your network connection."); 2136} 2137function toResultsets(text) { 2138 const pos = text.indexOf("\n\n//"); 2139 const data = JSON.parse(pos == -1 ? text : text.slice(0, pos)); 2140 const raw = data?.[0]; 2141 if (raw?.error) { 2142 throw new Error(raw.error + ""); 2143 } 2144 if (!Array.isArray(raw)) { 2145 throw new Error("Unexpected answer from the Personyze server."); 2146 } 2147 const resultsets = new Array(); 2148 for (const rset of raw) { 2149 if (rset?.error) { 2150 throw new Error(rset.error + ""); 2151 } 2152 const fields = rset?.fields; 2153 const rows = rset?.rows; 2154 const converted = []; 2155 if (fields && rows) { 2156 for (const row of rows) { 2157 const obj = {}; 2158 for (let i4 = 0; i4 < fields.length; i4++) { 2159 obj[fields[i4]] = row[i4]; 2160 } 2161 converted.push(obj); 2162 } 2163 converted.fields = fields; 2164 } 2165 resultsets.push(converted); 2166 } 2167 return resultsets; 2168} 2169
2170// src/modules/ailive/private/serialize.ts 2171var OPAQUE = /* @__PURE__ */ new Set([ 2172 "script", 2173 "style", 2174 "noscript", 2175 "template", 2176 "svg", 2177 "iframe", 2178 "object", 2179 "embed", 2180 "canvas", 2181 "video", 2182 "audio", 2183 "select" 2184]); 2185var SHOWN_ATTRS = [ 2186 [ 2187 "href", 2188 60 2189 ], 2190 [ 2191 "src", 2192 60 2193 ], 2194 [ 2195 "alt", 2196 40 2197 ], 2198 [ 2199 "title", 2200 40 2201 ], 2202 [ 2203 "type", 2204 20 2205 ], 2206 [ 2207 "name", 2208 30 2209 ], 2210 [ 2211 "role", 2212 20 2213 ], 2214 [ 2215 "aria-label", 2216 40 2217 ], 2218 [ 2219 "placeholder", 2220 40 2221 ] 2222]; 2223var MAX_CLASSES = 5; 2224var MAX_TEXT_CHARS = 80; 2225var MAX_CHILDREN = 30; 2226var MAX_DEPTH = 30; 2227var XML_ELEMENT_NODE = 1; 2228var XML_TEXT_NODE = 3; 2229function pageSkeleton(ignore, maxChars = 6e4) { 2230 const out = new Array(); 2231 let spent = 0; 2232 let truncated = false; 2233 function emit(line) { 2234 if (spent + line.length > maxChars) { 2235 truncated = true; 2236 return false; 2237 } 2238 out.push(line); 2239 spent += line.length + 1; 2240 return true; 2241 } 2242 function walk(elem, depth) { 2243 if (ignore.indexOf(elem) != -1) { 2244 return true; 2245 } 2246 const indent = " ".repeat(depth); 2247 if (depth > MAX_DEPTH) { 2248 return emit(indent + "\u2026"); 2249 } 2250 let line = indent + "<" + elem.localName; 2251 if (elem.id) { 2252 line += " #" + elem.id; 2253 } 2254 const classes = Array.from(elem.classList).slice(0, MAX_CLASSES); 2255 if (classes.length) { 2256 line += " ." + classes.join("."); 2257 } 2258 for (const [name, max] of SHOWN_ATTRS) { 2259 const value = elem.getAttribute(name); 2260 if (value) { 2261 line += ` ${name}="${cut(value, max)}"`; 2262 } 2263 } 2264 line += ">"; 2265 const isOpaque = OPAQUE.has(elem.localName); 2266 if (!isOpaque) { 2267 let text = ""; 2268 for (let node = elem.firstChild; node; node = node.nextSibling) { 2269 if (node.nodeType == XML_TEXT_NODE) { 2270 text += node.data; 2271 } 2272 } 2273 text = text.replace(/\s+/g, " ").trim(); 2274 if (text) { 2275 line += ` "${cut(text, MAX_TEXT_CHARS)}"`; 2276 } 2277 } 2278 if (!emit(line)) { 2279 return false; 2280 } 2281 if (isOpaque) { 2282 return true; 2283 } 2284 let nShown = 0; 2285 let nSkipped = 0; 2286 for (let node = elem.firstChild; node; node = node.nextSibling) { 2287 if (node.nodeType != XML_ELEMENT_NODE) { 2288 continue; 2289 } 2290 if (nShown >= MAX_CHILDREN) { 2291 nSkipped++; 2292 continue; 2293 } 2294 if (!walk(node, depth + 1)) { 2295 return false; 2296 } 2297 nShown++; 2298 } 2299 if (nSkipped) { 2300 return emit(" ".repeat(depth + 1) + `\u2026 ${nSkipped} more elements`); 2301 } 2302 return true; 2303 } 2304 walk(document.body, 0); 2305 if (truncated) { 2306 out.push("\u2026 (the skeleton was cut here - the page continues)"); 2307 } 2308 return out.join("\n"); 2309} 2310function cut(text, maxChars) { 2311 return text.length <= maxChars ? text : text.slice(0, maxChars - 1) + "\u2026"; 2312} 2313
2314// src/modules/pagedata/private/pagedata.ts 2315function parsePairs(text, separator) { 2316 const pairs = new Array(); 2317 for (const pair of text.split(separator)) { 2318 if (!pair) { 2319 continue; 2320 } 2321 const pos = pair.indexOf("="); 2322 const rawKey = pos < 0 ? pair : pair.slice(0, pos); 2323 const rawValue = pos < 0 ? "" : pair.slice(pos + 1); 2324 pairs.push({ 2325 key: decodeSafe(rawKey), 2326 value: decodeSafe(rawValue) 2327 }); 2328 } 2329 return pairs; 2330} 2331function decodeSafe(text) { 2332 try { 2333 return decodeURIComponent(text); 2334 } catch { 2335 return text; 2336 } 2337} 2338function resolveVarPath(root, path) { 2339 let value = root; 2340 for (const step of varPathSteps(path)) { 2341 if (value == null || typeof value != "object" && typeof value != "function") { 2342 return void 0; 2343 } 2344 value = value[step]; 2345 } 2346 return value; 2347} 2348function varPathSteps(path) { 2349 const steps = new Array(); 2350 for (const step of path.split(/[.[\]]/)) { 2351 const name = step.trim().replace(/^(["'])(.*)\1$/, "$2"); 2352 if (name) { 2353 steps.push(name); 2354 } 2355 } 2356 return steps; 2357} 2358function listCandidates(source, url) { 2359 switch (source) { 2360 case "cookie": 2361 return dedupeByKey(parsePairs(document.cookie, /;\s*/)); 2362 case "url": 2363 return dedupeByKey(parsePairs(queryOf(url), /&/)); 2364 case "local": 2365 return listStorage(safeStorage(() => localStorage)); 2366 case "session": 2367 return listStorage(safeStorage(() => sessionStorage)); 2368 case "meta": 2369 return dedupeByKey(listMetas()); 2370 default: 2371 return []; 2372 } 2373} 2374function dedupeByKey(candidates) { 2375 const seen = /* @__PURE__ */ new Set(); 2376 return candidates.filter((item) => { 2377 if (seen.has(item.key)) { 2378 return false; 2379 } 2380 seen.add(item.key); 2381 return true; 2382 }); 2383} 2384function queryOf(url) { 2385 const pos = url.indexOf("?"); 2386 if (pos < 0) { 2387 return ""; 2388 } 2389 const hash = url.indexOf("#", pos); 2390 return url.slice(pos + 1, hash < 0 ? void 0 : hash); 2391} 2392function safeStorage(get) { 2393 try { 2394 return get(); 2395 } catch { 2396 return null; 2397 } 2398} 2399function listStorage(storage) { 2400 const found = new Array(); 2401 for (let i4 = 0; storage && i4 < storage.length; i4++) { 2402 const key = storage.key(i4); 2403 if (key != null) { 2404 found.push({ 2405 key, 2406 value: storage.getItem(key) ?? "" 2407 }); 2408 } 2409 } 2410 return found; 2411} 2412function listMetas() { 2413 const found = new Array(); 2414 for (const meta of document.getElementsByTagName("meta")) { 2415 if (meta.httpEquiv) { 2416 continue; 2417 } 2418 const key = meta.getAttribute("name") || meta.getAttribute("property") || ""; 2419 const content = meta.content ?? ""; 2420 if (key) { 2421 found.push({ 2422 key, 2423 value: content 2424 }); 2425 } else { 2426 const selector = selectorForMeta(meta); 2427 if (selector) { 2428 found.push({ 2429 key: selector, 2430 value: content, 2431 selector 2432 }); 2433 } 2434 } 2435 } 2436 return found; 2437} 2438function selectorForMeta(meta) { 2439 for (const { name, value } of meta.attributes) { 2440 if (name != "content" && /^[\w-]+$/.test(name)) { 2441 const selector = `meta[${name}=${JSON.stringify(value)}]`; 2442 const all = document.querySelectorAll(selector); 2443 if (all.length == 1 && all[0] == meta) { 2444 return selector; 2445 } 2446 } 2447 } 2448 return ""; 2449} 2450function readValue(source, key, url) { 2451 if (!key) { 2452 return ""; 2453 } 2454 if (source == "variable") { 2455 const value = resolveVarPath(globalThis, key); 2456 return value == null || typeof value == "object" && !(value instanceof Date) ? "" : String(value); 2457 } 2458 const found = listCandidates(source, url).find((v3) => v3.key == key); 2459 return found?.value ?? ""; 2460} 2461
2462// src/modules/aigrab/private/aiGrab.ts 2463var MAX_NAME_CHARS = 50; 2464var MASK_LABELS = { 2465 none: "Pass everything", 2466 number: "Number only", 2467 nonnumber: "Nonnumbers only", 2468 email: "Email address" 2469}; 2470function maskLabel(mask) { 2471 return MASK_LABELS[mask] ?? MASK_LABELS.none; 2472} 2473var MAX_ROUNDS = 8; 2474var SKELETON_MAX_CHARS = 3e4; 2475var SOURCES_MAX_CHARS = 24e3; 2476var SOURCE_VALUE_MAX_CHARS = 200; 2477var MAX_LISTED_MATCHES = 10; 2478var QUERY_VALUE_MAX_CHARS = 120; 2479async function aiGrabSuggest(request) { 2480 const { kind, hostElem, onStatus } = request; 2481 let payload = { 2482 prompt: request.instruction, 2483 grab: { 2484 kind, 2485 sources: kind == "attribute" ? listSources(request.pageUrl) : "" 2486 }, 2487 page: { 2488 url: request.pageUrl || location.href, 2489 title: document.title, 2490 viewport: `${globalThis.innerWidth}x${globalThis.innerHeight}`, 2491 skeleton: pageSkeleton([ 2492 hostElem 2493 ], SKELETON_MAX_CHARS) 2494 } 2495 }; 2496 let text = ""; 2497 for (let round = 0; true; round++) { 2498 const turn = await callServer(payload); 2499 if (turn.text) { 2500 text = turn.text; 2501 } 2502 const proposal = turn.tool_calls.find((v3) => v3.name == "propose_grab"); 2503 if (proposal) { 2504 return { 2505 suggestion: readSuggestion(kind, proposal.input, hostElem, request.pageUrl), 2506 text 2507 }; 2508 } 2509 if (!turn.tool_calls.length) { 2510 return { 2511 suggestion: null, 2512 text: text || "The AI did not find anything on this page that matches what you described." 2513 }; 2514 } 2515 if (round >= MAX_ROUNDS) { 2516 return { 2517 suggestion: null, 2518 text: "The AI did not settle on an answer in the allotted number of steps. Try describing the value differently." 2519 }; 2520 } 2521 const results = turn.tool_calls.map((call) => ({ 2522 id: call.id, 2523 ...call.name == "query" ? runQuery(str(call.input.selector), hostElem, onStatus) : { 2524 content: `Unknown tool: ${call.name}`, 2525 is_error: true 2526 } 2527 })); 2528 payload = { 2529 grab: { 2530 kind 2531 }, 2532 messages: turn.messages, 2533 tool_results: results 2534 }; 2535 } 2536} 2537async function callServer(payload) { 2538 const row = await queryRow("CALL acc_actions.ai_live_edit(@request, @action_id, @action_version)", { 2539 request: JSON.stringify(payload), 2540 action_id: 0, 2541 action_version: 0 2542 }, true); 2543 const raw = String(row?.result ?? ""); 2544 if (!raw) { 2545 throw new Error("The AI service returned an empty answer. Your picker session may have expired - reopen the picker from Personyze."); 2546 } 2547 let parsed; 2548 try { 2549 parsed = JSON.parse(raw); 2550 } catch { 2551 throw new Error("The AI service answered with something unreadable: " + raw.slice(0, 120)); 2552 } 2553 if (!Array.isArray(parsed?.messages) || !Array.isArray(parsed?.tool_calls)) { 2554 throw new Error("Unexpected answer from the AI service."); 2555 } 2556 return { 2557 messages: parsed.messages, 2558 text: typeof parsed.text == "string" ? parsed.text : "", 2559 tool_calls: parsed.tool_calls 2560 }; 2561} 2562function runQuery(selector, hostElem, onStatus) { 2563 if (!selector) { 2564 return { 2565 content: "No selector given", 2566 is_error: true 2567 }; 2568 } 2569 let found; 2570 try { 2571 found = Array.from(document.querySelectorAll(selector)).filter((v3) => v3 != hostElem && !hostElem.contains(v3)); 2572 } catch { 2573 return { 2574 content: `Not a valid CSS selector: ${selector}`, 2575 is_error: true 2576 }; 2577 } 2578 onStatus?.(`Checked ${selector} - ${found.length} match${found.length == 1 ? "" : "es"}`); 2579 if (!found.length) { 2580 return { 2581 content: "0 elements match." 2582 }; 2583 } 2584 const lines = [ 2585 `${found.length} element${found.length == 1 ? "" : "s"} match.` 2586 ]; 2587 for (let i4 = 0, iEnd = Math.min(found.length, MAX_LISTED_MATCHES); i4 < iEnd; i4++) { 2588 const elem = found[i4]; 2589 const value = grabValue(elem); 2590 lines.push(`${i4 + 1}. ${describeElem(elem)} - would read: ${value ? JSON.stringify(cut2(value, QUERY_VALUE_MAX_CHARS)) : "(nothing)"}`); 2591 } 2592 if (found.length > MAX_LISTED_MATCHES) { 2593 lines.push(`... and ${found.length - MAX_LISTED_MATCHES} more`); 2594 } 2595 return { 2596 content: lines.join("\n") 2597 }; 2598} 2599function listSources(pageUrl) { 2600 const blocks = [ 2601 [ 2602 "Cookies", 2603 "cookie" 2604 ], 2605 [ 2606 "Local storage", 2607 "local" 2608 ], 2609 [ 2610 "Session storage", 2611 "session" 2612 ], 2613 [ 2614 "META tags", 2615 "meta" 2616 ], 2617 [ 2618 "URL parameters", 2619 "url" 2620 ] 2621 ]; 2622 const out = new Array(); 2623 let spent = 0; 2624 for (const [title, source] of blocks) { 2625 const candidates = listCandidates(source, pageUrl); 2626 const lines = [ 2627 `## ${title} (source: ${source})` 2628 ]; 2629 if (!candidates.length) { 2630 lines.push("(none on this page)"); 2631 } 2632 for (const item of candidates) { 2633 const line = `- ${item.key} = ${JSON.stringify(cut2(item.value, SOURCE_VALUE_MAX_CHARS))}`; 2634 if (spent + line.length > SOURCES_MAX_CHARS) { 2635 lines.push(`- ... the rest of this list was cut`); 2636 break; 2637 } 2638 spent += line.length; 2639 lines.push(line); 2640 } 2641 out.push(lines.join("\n")); 2642 } 2643 return out.join("\n\n"); 2644} 2645function readSuggestion(kind, input, hostElem, pageUrl) { 2646 const explanation = str(input.explanation).trim(); 2647 if (kind == "placeholder") { 2648 const selector = str(input.selector).trim(); 2649 const matches2 = findOutside(selector, hostElem); 2650 return { 2651 kind: "placeholder", 2652 selector, 2653 placement: readPlacement(str(input.placement)), 2654 name: str(input.name).trim().slice(0, MAX_NAME_CHARS), 2655 explanation, 2656 elem: matches2[0] ?? null, 2657 nMatches: matches2.length 2658 }; 2659 } 2660 if (kind != "attribute") { 2661 const selector = str(input.selector).trim(); 2662 const matches2 = findOutside(selector, hostElem); 2663 return { 2664 kind: "goal", 2665 selector, 2666 isMany: input.match_many === true, 2667 explanation, 2668 elem: matches2[0] ?? null, 2669 value: matches2[0] ? grabValue(matches2[0]) : "", 2670 nMatches: matches2.length 2671 }; 2672 } 2673 const source = readSource(str(input.source)); 2674 const key = str(input.key).trim();
2675 const isPage = source == "page"; 2676 const matches = isPage ? findOutside(key, hostElem) : []; 2677 const elem = matches[0] ?? null; 2678 const attrRaw = str(input.attr).trim(); 2679 const attr = isPage && elem?.hasAttribute(attrRaw) ? attrRaw : ""; 2680 const triggerRaw = str(input.trigger_selector).trim(); 2681 const trigger = findOutside(triggerRaw, hostElem).length ? triggerRaw : ""; 2682 return { 2683 kind: "attribute", 2684 source, 2685 key, 2686 attr, 2687 isSearchInput: input.is_search_input === true, 2688 triggerSelector: trigger, 2689 mask: readMask(str(input.mask)), 2690 explanation, 2691 elem, 2692 value: !isPage ? readValue(source, key, pageUrl) : !elem ? "" : attr ? elem.getAttribute(attr) ?? "" : grabValue(elem), 2693 nMatches: isPage ? matches.length : -1 2694 }; 2695} 2696function findOutside(selector, hostElem) { 2697 if (!selector) { 2698 return []; 2699 } 2700 try { 2701 return Array.from(document.querySelectorAll(selector)).filter((v3) => v3 != hostElem && !hostElem.contains(v3)); 2702 } catch { 2703 return []; 2704 } 2705} 2706function readSource(source) { 2707 switch (source) { 2708 case "page": 2709 case "meta": 2710 case "cookie": 2711 case "local": 2712 case "session": 2713 case "variable": 2714 case "url": 2715 return source; 2716 } 2717 return "page"; 2718} 2719function readPlacement(placement) { 2720 switch (placement) { 2721 case "before": 2722 case "after": 2723 case "replace": 2724 return placement; 2725 } 2726 return "inside"; 2727} 2728function readMask(mask) { 2729 switch (mask) { 2730 case "number": 2731 case "nonnumber": 2732 case "email": 2733 return mask; 2734 } 2735 return "none"; 2736} 2737function str(value) { 2738 return typeof value == "string" ? value : ""; 2739} 2740function cut2(text, maxChars) { 2741 return text.length <= maxChars ? text : text.slice(0, maxChars - 1) + "\u2026"; 2742} 2743
2744// src/components/AiGrabCard.tsx 2745function AiGrabCard(props) { 2746 const [isOpen, setIsOpen] = p2(false); 2747 const [prompt, setPrompt] = p2(""); 2748 const [isBusy, setIsBusy] = p2(false); 2749 const [status, setStatus] = p2(""); 2750 const [error, setError] = p2(""); 2751 const [suggestion, setSuggestion] = p2(null); 2752 const [answer, setAnswer] = p2(""); 2753 if (!isJsapiConfigured()) { 2754 return null; 2755 } 2756 async function suggest(instruction) { 2757 const text = instruction.trim(); 2758 if (!text || isBusy) { 2759 return; 2760 } 2761 setIsBusy(true); 2762 setError(""); 2763 setStatus(""); 2764 setSuggestion(null); 2765 setAnswer(""); 2766 try { 2767 const result = await aiGrabSuggest({ 2768 kind: props.kind, 2769 instruction: text, 2770 hostElem: props.hostElem, 2771 pageUrl: props.pageUrl, 2772 onStatus: setStatus 2773 }); 2774 setSuggestion(result.suggestion); 2775 setAnswer(result.suggestion ? "" : result.text); 2776 } catch (e3) { 2777 console.error(e3); 2778 setError(e3 instanceof Error ? e3.message : "The AI request failed."); 2779 } 2780 setIsBusy(false); 2781 setStatus(""); 2782 } 2783 return /* @__PURE__ */ u2("div", { 2784 class: "qs-sec qs-ai", 2785 children: [
2786 /* @__PURE__ */ u2("button", { 2787 type: "button", 2788 class: "qs-ai-head", 2789 "aria-expanded": isOpen, 2790 onClick: () => setIsOpen(!isOpen), 2791 children: [ 2792 /* @__PURE__ */ u2("span", { 2793 class: "qs-ai-ico", 2794 children: ic.sparkle 2795 }), 2796 /* @__PURE__ */ u2("h3", { 2797 children: props.title 2798 }), 2799 /* @__PURE__ */ u2("span", { 2800 class: "qs-ai-tag", 2801 children: "AI" 2802 }), 2803 /* @__PURE__ */ u2("span", { 2804 class: "qs-ai-chev" + (isOpen ? " qs-on" : ""), 2805 children: ic.chevronDown 2806 }) 2807 ] 2808 }), 2809 isOpen && /* @__PURE__ */ u2("div", { 2810 class: "qs-ai-body", 2811 children: [ 2812 /* @__PURE__ */ u2("div", { 2813 class: "qs-hint", 2814 children: props.hint 2815 }), 2816 /* @__PURE__ */ u2("textarea", { 2817 class: "qs-ai-input", 2818 rows: 2, 2819 value: prompt, 2820 placeholder: props.placeholder, 2821 disabled: isBusy, 2822 onInput: (ev) => setPrompt(ev.target.value), 2823 onKeyDown: (ev) => { 2824 if (ev.key == "Enter" && !ev.shiftKey) { 2825 ev.preventDefault(); 2826 void suggest(prompt); 2827 } 2828 } 2829 }),
2830 /* @__PURE__ */ u2("div", { 2831 class: "qs-ai-chips", 2832 children: props.chips.map((chip) => /* @__PURE__ */ u2("button", { 2833 type: "button", 2834 class: "qs-ai-chip", 2835 title: "Ask for: " + chip.prompt, 2836 disabled: isBusy, 2837 onClick: () => { 2838 setPrompt(chip.prompt); 2839 void suggest(chip.prompt); 2840 }, 2841 children: chip.label 2842 }, chip.label)) 2843 }), 2844 /* @__PURE__ */ u2("button", { 2845 type: "button", 2846 class: "qs-btn qs-ai-btn", 2847 disabled: isBusy || !prompt.trim(), 2848 onClick: () => void suggest(prompt), 2849 children: [ 2850 isBusy ? /* @__PURE__ */ u2("span", { 2851 class: "qs-spin" 2852 }) : ic.sparkle, 2853 isBusy ? "Looking at the page..." : "Suggest with AI" 2854 ] 2855 }), 2856 isBusy && status && /* @__PURE__ */ u2("div", { 2857 class: "qs-ai-status", 2858 children: status 2859 }), 2860 error && /* @__PURE__ */ u2("div", { 2861 class: "qs-callout qs-ai-warn", 2862 style: "margin-top:0.7em", 2863 children: [ 2864 ic.warn,
2865 /* @__PURE__ */ u2("div", { 2866 children: error 2867 }) 2868 ] 2869 }), 2870 !!answer && !suggestion && /* @__PURE__ */ u2("div", { 2871 class: "qs-callout qs-ai-warn", 2872 style: "margin-top:0.7em", 2873 children: [ 2874 ic.warn, 2875 /* @__PURE__ */ u2("div", { 2876 children: answer 2877 }) 2878 ] 2879 }), 2880 suggestion && /* @__PURE__ */ u2(Result, { 2881 suggestion, 2882 onApply: () => props.onApply(suggestion), 2883 onDiscard: () => setSuggestion(null) 2884 }) 2885 ] 2886 }) 2887 ] 2888 }); 2889} 2890function Result(props) { 2891 const { suggestion } = props; 2892 const rows = suggestion.kind == "attribute" ? attributeRows(suggestion) : suggestion.kind == "placeholder" ? placeholderRows(suggestion) : goalRows(suggestion); 2893 const isUnusable = suggestion.nMatches == 0; 2894 return /* @__PURE__ */ u2("div", { 2895 class: "qs-ai-result", 2896 children: [ 2897 /* @__PURE__ */ u2("div", { 2898 class: "qs-ai-result-head", 2899 children: [ 2900 ic.sparkle, 2901 " AI suggestion" 2902 ] 2903 }), 2904 rows.map(([label, value, isMono]) => /* @__PURE__ */ u2("div", { 2905 class: "qs-ai-field", 2906 children: [
2907 /* @__PURE__ */ u2("div", { 2908 class: "qs-ai-k", 2909 children: label 2910 }), 2911 /* @__PURE__ */ u2("div", { 2912 class: "qs-ai-v" + (isMono ? " qs-ai-mono" : ""), 2913 children: value || "\u2014" 2914 }) 2915 ] 2916 }, label)), 2917 !!suggestion.explanation && /* @__PURE__ */ u2("div", { 2918 class: "qs-hint", 2919 style: "margin:0.6em 0 0", 2920 children: suggestion.explanation 2921 }), 2922 isUnusable && /* @__PURE__ */ u2("div", { 2923 class: "qs-hint", 2924 style: "margin:0.6em 0 0", 2925 children: "That selector matches nothing on this page, so there is nothing to apply. Rephrase, or pick the element by hand below." 2926 }), 2927 /* @__PURE__ */ u2("div", { 2928 class: "qs-btn-row", 2929 style: "margin-top:0.7em", 2930 children: [ 2931 /* @__PURE__ */ u2("button", { 2932 type: "button", 2933 class: "qs-btn", 2934 onClick: props.onDiscard, 2935 children: "Discard" 2936 }), 2937 /* @__P
2937URE__ */ u2("button", { 2938 type: "button", 2939 class: "qs-btn qs-btn-primary", 2940 disabled: isUnusable, 2941 onClick: props.onApply, 2942 children: [ 2943 ic.check, 2944 "Apply & fill the form" 2945 ] 2946 }) 2947 ] 2948 }) 2949 ] 2950 }); 2951} 2952var SOURCE_LABELS = { 2953 page: "An element on the page", 2954 cookie: "A cookie", 2955 local: "Local storage", 2956 session: "Session storage", 2957 meta: "A META tag", 2958 url: "A URL parameter", 2959 variable: "A JavaScript variable" 2960}; 2961function attributeRows(suggestion) { 2962 const isPage = suggestion.source == "page"; 2963 const rows = [ 2964 [ 2965 "Source", 2966 SOURCE_LABELS[suggestion.source] ?? suggestion.source 2967 ], 2968 [ 2969 isPage ? "Selector" : "Key", 2970 suggestion.key, 2971 true 2972 ] 2973 ]; 2974 if (isPage) { 2975 rows.push([ 2976 "Collect", 2977 suggestion.attr ? `The "${suggestion.attr}" attribute` : `The element's text` 2978 ]); 2979 rows.push([ 2980 "Matches on this page", 2981 suggestion.nMatches == 1 ? "1 element" : `${suggestion.nMatches} elements` 2982 ]); 2983 if (suggestion.isSearchInput) { 2984 rows.push([ 2985 "This field is", 2986 `The site's search box` 2987 ]); 2988 } 2989 } 2990 if (suggestion.triggerSelector) { 2991 rows.push([ 2992 "Read it after a click on", 2993 suggestion.triggerSelector, 2994 true 2995 ]); 2996 } 2997 if (suggestion.mask != "none") { 2998 rows.push([ 2999 "Mask", 3000 maskLabel(suggestion.mask) 3001 ]); 3002 } 3003 rows.push([ 3004 "Value right now", 3005 suggestion.value || "(nothing here right now)" 3006 ]); 3007 return rows; 3008} 3009var PLACEMENT_LABELS = { 3010 inside: "Inside the selected element", 3011 before: "Before the selected element", 3012 after: "After the selected element", 3013 replace: "Replace the selected element" 3014}; 3015function placeholderRows(suggestion) { 3016 return [ 3017 [ 3018 "Placeholder name", 3019 suggestion.name 3020 ], 3021 [ 3022 "Anchor element", 3023 suggestion.selector, 3024 true 3025 ], 3026 [ 3027 "Content goes", 3028 PLACEMENT_LABELS[suggestion.placement] ?? suggestion.placement 3029 ], 3030 [ 3031 "Matches on this page", 3032 suggestion.nMatches == 1 ? "1 element" : `${suggestion.nMatches} elements` 3033 ] 3034 ]; 3035} 3036function goalRows(suggestion) { 3037 const rows = [ 3038 [ 3039 "Selector", 3040 suggestion.selector, 3041 true 3042 ], 3043 [ 3044 "This goal is about", 3045 suggestion.isMany ? "Every element like it" : "Only this element" 3046 ], 3047 [ 3048 "Matches on this page", 3049 suggestion.nMatches == 1 ? "1 element" : `${suggestion.nMatches} elements` 3050 ] 3051 ]; 3052 if (suggestion.value) { 3053 rows.push([ 3054 "Value right now", 3055 suggestion.value 3056 ]); 3057 } 3058 return rows; 3059} 3060
3061// src/components/ElementPick.tsx 3062function useElementPick(hostElem, options) { 3063 const [isPicking, setIsPicking] = p2(false); 3064 const [chain, setChain] = p2(new Array()); 3065 const [chainIndex, setChainIndex] = p2(-1); 3066 const [selector, setSelector] = p2(""); 3067 const [highlight, setHighlight] = p2(null); 3068 const pickerRef = F2(); 3069 const optionsRef = F2(options); 3070 optionsRef.current = options; 3071 if (!pickerRef.current) { 3072 pickerRef.current = new Picker(); 3073 } 3074 const picker = pickerRef.current; 3075 const selected = chainIndex >= 0 && chainIndex < chain.length ? chain[chainIndex] : null; 3076 const chainRef = F2(chain); 3077 chainRef.current = chain; 3078 const highlightRef = F2(highlight); 3079 highlightRef.current = highlight; 3080 const selectedRef = F2(selected); 3081 selectedRef.current = selected; 3082 const selectElem = x2((elem, selector2) => { 3083 const newChain = ancestorChain(elem); 3084 setChain(newChain); 3085 setChainIndex(newChain.length - 1); 3086 setSelector(selector2 ?? (optionsRef.current?.selectorOf ?? elemToSelector)(elem)); 3087 }, []); 3088 const pickAncestor = x2((index) => { 3089 const elem = chainRef.current[index]; 3090 if (elem) { 3091 setChainIndex(index); 3092 setSelector((optionsRef.current?.selectorOf ?? elemToSelector)(elem)); 3093 } 3094 }, []); 3095 const beginPick = x2(() => { 3096 setIsPicking(true); 3097 getTracker()?.proxy_modify_links?.(true, 111); 3098 picker.selectBegin({ 3099 ignore: [ 3100 hostElem 3101 ], 3102 onSelect(elem) { 3103 picker.selectEnd(); 3104 setIsPicking(false); 3105 if (elem) { 3106 selectElem(elem); 3107 } 3108 } 3109 }); 3110 }, [ 3111 picker, 3112 hostElem, 3113 selectElem 3114 ]); 3115 const endPick = x2(() => { 3116 picker.selectEnd(); 3117 setIsPicking(false); 3118 }, [ 3119 picker 3120 ]); 3121 const restoreHighlight = x2(() => picker.highlight(highlightRef.current ?? (selectedRef.current ? [ 3122 selectedRef.current 3123 ] : [])), [ 3124 picker 3125 ]); 3126 _2(() => { 3127 if (!isPicking) { 3128 picker.highlight(highlight ?? (selected ? [ 3129 selected 3130 ] : [])); 3131 } 3132 }, [ 3133 picker, 3134 highlight, 3135 selected, 3136 isPicking 3137 ]); 3138 _2(() => () => picker.destroy(), [ 3139 picker 3140 ]); 3141 return { 3142 picker, 3143 isPicking, 3144 chain, 3145 chainIndex, 3146 selected, 3147 selector, 3148 setSelector, 3149 beginPick, 3150 endPick, 3151 selectElem, 3152 pickAncestor, 3153 setHighlight, 3154 restoreHighlight 3155 }; 3156} 3157function ElementPickBody(props) { 3158 const { pick } = props; 3159 if (props.isConnecting) { 3160 return /* @__PURE__ */ u2("div", { 3161 class: "qs-callout", 3162 children: [
3163 /* @__PURE__ */ u2("span", { 3164 class: "qs-spin" 3165 }), 3166 /* @__PURE__ */ u2("div", { 3167 children: "Connecting to the Personyze panel..." 3168 }) 3169 ] 3170 }); 3171 } 3172 if (pick.isPicking) { 3173 return /* @__PURE__ */ u2("div", { 3174 class: "qs-callout", 3175 children: [ 3176 ic.target, 3177 /* @__PURE__ */ u2("div", { 3178 children: "Point and click the spot on the page. Press Esc to stop." 3179 }) 3180 ] 3181 }); 3182 } 3183 if (!pick.selected) { 3184 return /* @__PURE__ */ u2("div", { 3185 class: "qs-btn-row", 3186 children: [ 3187 /* @__PURE__ */ u2("button", { 3188 type: "button", 3189 class: "qs-btn qs-btn-primary", 3190 onClick: pick.beginPick, 3191 children: [ 3192 ic.target, 3193 " ", 3194 props.pickLabel 3195 ] 3196 }), 3197 pick.selector && /* @__PURE__ */ u2("span", { 3198 class: "qs-selector", 3199 children: pick.selector 3200 }) 3201 ] 3202 }); 3203 } 3204 return /* @__PURE__ */ u2(k, { 3205 children: [
3206 /* @__PURE__ */ u2("div", { 3207 class: "qs-label", 3208 children: "Element" 3209 }), 3210 /* @__PURE__ */ u2("div", { 3211 class: "qs-tree", 3212 children: pick.chain.map((elem, i4) => /* @__PURE__ */ u2("button", { 3213 type: "button", 3214 class: "qs-tree-row" + (i4 == pick.chainIndex ? " qs-on" : ""), 3215 style: "padding-left:" + (0.45 + i4 * 0.9) + "em", 3216 title: describeElem(elem), 3217 onMouseEnter: () => pick.picker.highlight([ 3218 elem 3219 ], "#60A5FA", true), 3220 onMouseLeave: pick.restoreHighlight, 3221 onClick: () => pick.pickAncestor(i4), 3222 children: describeElem(elem) 3223 }, i4)) 3224 }), 3225 /* @__PURE__ */ u2("div", { 3226 class: "qs-label", 3227 style: "margin-top:0.8em", 3228 children: "Captured selector" 3229 }), 3230 /* @__PURE__ */ u2("div", { 3231 class: "qs-selector", 3232 children: pick.selector 3233 }), 3234 /* @__PURE__ */ u2("div", { 3235 class: "qs-btn-row", 3236 style: "margin-top:0.6em", 3237 children: /* @__PURE__ */ u2("button", { 3238 type: "button", 3239 class: "qs-btn", 3240 onClick: pick.beginPick, 3241 children: "Reselect" 3242 }) 3243 }) 3244 ] 3245 }); 3246} 3247
3248// src/components/PlaceholderTool.tsx 3249var PANEL_TIMEOUT = 2e4; 3250var PLACE_MODES = [ 3251 { 3252 value: "inside", 3253 text: "Inside the selected element", 3254 hint: "Replaces whatever is inside the element with your content.", 3255 meta: "Inside element" 3256 }, 3257 { 3258 value: "before", 3259 text: "Before selected element", 3260 hint: "Injects the content before the element in the DOM.", 3261 meta: "Before element" 3262 }, 3263 { 3264 value: "after", 3265 text: "After selected element", 3266 hint: "Injects the content after the element in the DOM.", 3267 meta: "After element" 3268 }, 3269 { 3270 value: "replace", 3271 text: "Replace selected element", 3272 hint: "Swaps the element out and renders your content in its place.", 3273 meta: "Replace element" 3274 } 3275]; 3276var AI_CHIPS = [ 3277 { 3278 label: "Recommendations for returning shoppers", 3279 prompt: "A recommendations widget for returning shoppers, under the category title" 3280 }, 3281 { 3282 label: "Promo banner above the grid", 3283 prompt: "A limited-time promo banner above the main product grid" 3284 }, 3285 { 3286 label: "Free-shipping bar", 3287 prompt: "A free-shipping bar across the top of the page, for first-time visitors" 3288 }, 3289 { 3290 label: "Newsletter block before the footer", 3291 prompt: "A newsletter signup block just before the footer" 3292 } 3293]; 3294var PREVIEW_SIZES = [ 3295 { 3296 value: "336x280", 3297 color: "#79B157" 3298 }, 3299 { 3300 value: "300x250", 3301 color: "#5794B1" 3302 }, 3303 { 3304 value: "728x90", 3305 color: "#B1575F" 3306 }, 3307 { 3308 value: "300x600", 3309 color: "#C79352" 3310 }, 3311 { 3312 value: "320x100", 3313 color: "#1EA774" 3314 } 3315]; 3316var CUSTOM_SIZE_COLOR = "#8B7BD8"; 3317function hasContent(elem) { 3318 for (const node of Array.from(elem?.childNodes ?? [])) { 3319 if (node.nodeType == 1) { 3320 return true; 3321 } 3322 if (node.nodeType == 3 && (node.nodeValue ?? "").trim()) { 3323 return true; 3324 } 3325 } 3326 return false; 3327} 3328function scopeOf(selector, nMatches) { 3329 if (/#[\w-]/.test(selector)) { 3330 return { 3331 label: "Precise match", 3332 tag: "this element only", 3333 ratio: 0.12, 3334 desc: "Pinned to an id, so it lands on exactly one element wherever it appears.", 3335 isWide: false 3336 }; 3337 } 3338 if (nMatches <= 1) { 3339 return { 3340 label: "Specific match", 3341 tag: "one element here", 3342 ratio: 0.38, 3343 desc: "Matches a single element on this page. It may still match on other pages built from the same template.", 3344 isWide: false 3345 }; 3346 } 3347 if (nMatches <= 4) { 3348 return { 3349 label: "Repeats on this page", 3350 tag: `${nMatches} elements here`, 3351 ratio: 0.66, 3352 desc: `This selector already matches ${nMatches} elements here, so the content would be placed at each of them.`, 3353 isWide: true 3354 }; 3355 } 3356 return { 3357 label: "Broad match", 3358 tag: "appears on many pages", 3359 ratio: 0.92, 3360 desc: `A generic selector like this matches ${nMatches} elements on this page alone, and typically appears across many pages of the site.`, 3361 isWide: true 3362 }; 3363} 3364function PlaceholderTool(props) { 3365 const [isConnecting, setIsConnecting] = p2(true); 3366 const [error, setError] = p2(""); 3367 const [isSaving, setIsSaving] = p2(false); 3368 const [isClosed, setIsClosed] = p2(false); 3369 const [placeMode, setPlaceMode] = p2("inside"); 3370 const [previewSize, setPreviewSize] = p2(PREVIEW_SIZES[0].value); 3371 const [isPreviewOn, setIsPreviewOn] = p2(false); 3372 const [customWidth, setCustomWidth] = p2(336); 3373 const [customHeight, setCustomHeight] = p2(280); 3374 const [isPickOpen, setIsPickOpen] = p2(true); 3375 const [isPlaceOpen, setIsPlaceOpen] = p2(false); 3376 const [isLookOpen, setIsLookOpen] = p2(false); 3377 const bridgeRef = F2(); 3378 const previewRef = F2(null); 3379 const styleOverrideRef = F2(""); 3380 const aiNameRef = F2(""); 3381 const pick = useElementPick(props.hostElem); 3382 const { selected, selector: htmlId, setSelector: setHtmlId, selectElem, beginPick, endPick } = pick; 3383 _2(() => { 3384 let isGone = false; 3385 let isConnected = false; 3386 const bridge = new ToolBridge({ 3387 bufferKey: props.bufferKey, 3388 guiOrigin: props.guiOrigin, 3389 onValue(value) { 3390 if (isGone) { 3391 return; 3392 } 3393 isConnected = true; 3394 setIsConnecting(false); 3395 const columns = value.columns ?? {}; 3396 const toolProps = value.tool_props ?? {}; 3397 const savedPlaceMode = parseAeWhere(toolProps.html_change ?? columns.html_change); 3398 if (savedPlaceMode) { 3399 setPlaceMode(savedPlaceMode); 3400 } 3401 const savedStyleOverride = toolProps.style_override_occupied ?? columns.style_override_occupied; 3402 if (typeof savedStyleOverride == "string") { 3403 styleOverrideRef.current = savedStyleOverride; 3404 } 3405 const savedHtmlId = typeof columns.html_id == "string" ? columns.html_id : ""; 3406 if (!savedHtmlId) { 3407 beginPick(); 3408 return; 3409 } 3410 setHtmlId(savedHtmlId); 3411 const elem = resolveHtmlId(savedHtmlId); 3412 if (elem) { 3413 selectElem(elem, savedHtmlId); 3414 } else { 3415 setError("This placeholder points at an element that is not on this page. Pick the spot again, or open a page where it exists."); 3416 beginPick(); 3417 } 3418 } 3419 }); 3420 bridgeRef.current = bridge; 3421 bridge.start(); 3422 const timer = setTimeout(() => { 3423 if (!isGone && !isConnected) { 3424 setIsConnecting(false); 3425 setError("Could not reach the Personyze panel, so this placeholder could not be loaded. Keep the Personyze tab open and reopen the picker from there."); 3426 } 3427 }, PANEL_TIMEOUT); 3428 return () => { 3429 isGone = true; 3430 clearTimeout(timer); 3431 bridge.destroy(); 3432 }; 3433 }, [ 3434 props.bufferKey, 3435 props.guiOrigin, 3436 beginPick, 3437 selectElem, 3438 setHtmlId 3439 ]); 3440 _2(() => { 3441 if (htmlId) { 3442 setIsPickOpen(false); 3443 setIsPlaceOpen(true); 3444 } 3445 }, [ 3446 htmlId 3447 ]); 3448 _2(() => () => { 3449 previewRef.current?.revert(); 3450 previewRef.current = null; 3451 }, []); 3452 _2(() => { 3453 previewRef.current?.revert(); 3454 previewRef.current = null; 3455 if (isPreviewOn && selected) { 3456 const size = PREVIEW_SIZES.find((v3) => v3.value == previewSize) ?? { 3457 value: previewSize, 3458 color: CUSTOM_SIZE_COLOR 3459 }; 3460 const doPutHtml = getTracker()?.do_put_html; 3461 if (!doPutHtml) { 3462 setError("This page is running an older Personyze tracker that cannot show the preview."); 3463 setIsPreviewOn(false); 3464 return; 3465 }
3466 try { 3467 previewRef.current = doPutHtml(selected, previewElem(size.value, size.color), "", { 3468 ae_where: placeMode, 3469 add_elem: "div" 3470 }, {}, false, 0); 3471 } catch (e3) { 3472 setError(e3 instanceof Error ? e3.message : String(e3)); 3473 setIsPreviewOn(false); 3474 } 3475 } 3476 }, [ 3477 isPreviewOn, 3478 previewSize, 3479 placeMode, 3480 selected 3481 ]); 3482 function applySuggestion(suggestion) { 3483 if (suggestion.kind != "placeholder") { 3484 return; 3485 } 3486 setError(""); 3487 endPick(); 3488 aiNameRef.current = suggestion.name; 3489 setPlaceMode(suggestion.placement); 3490 setHtmlId(suggestion.selector); 3491 if (suggestion.elem) { 3492 selectElem(suggestion.elem, suggestion.selector); 3493 } 3494 } 3495 function close() { 3496 const panelWindow = getPanelWindow(); 3497 setIsClosed(true); 3498 try { 3499 globalThis.close(); 3500 panelWindow?.focus(); 3501 } catch (e3) { 3502 console.error(e3); 3503 } 3504 } 3505 async function save() { 3506 const bridge = bridgeRef.current; 3507 if (!bridge || !htmlId) { 3508 return; 3509 } 3510 const htmlChange = JSON.stringify({ 3511 ae_where: placeMode, 3512 add_elem: "div" 3513 }); 3514 setIsSaving(true); 3515 setError(""); 3516 previewRef.current?.revert(); 3517 previewRef.current = null; 3518 setIsPreviewOn(false); 3519 const styleOverride = styleOverrideRef.current; 3520 const isAcked = await bridge.setValue({ 3521 columns: { 3522 name: selected ? describeElem(selected) : htmlId, 3523 html_id: htmlId, 3524 html_change: htmlChange, 3525 style_override_occupied: styleOverride 3526 }, 3527 tool_props: { 3528 html_change: htmlChange, 3529 style_override_occupied: styleOverride, 3530 ai_name: aiNameRef.current, 3531 has_content: hasContent(selected) 3532 } 3533 }); 3534 setIsSaving(false); 3535 if (!isAcked) { 3536 setError("The Personyze panel did not confirm the selection. Make sure its tab is still open, then try again."); 3537 } else { 3538 close(); 3539 } 3540 } 3541 if (isClosed) { 3542 return null; 3543 } 3544 const scope = scopeOf(htmlId, findMatches(htmlId).length); 3545 const placeMeta = PLACE_MODES.find((v3) => v3.value == placeMode); 3546 return /* @__PURE__ */ u2(SimulatorPanel, { 3547 title: "CONTENT PLACEHOLDER", 3548 subtitle: "Point, place & preview on your live page", 3549 logoSrc: props.counterUrl ? props.counterUrl + "/images/logo-icon.svg" : void 0, 3550 error, 3551 onDismissError: () => setError(""), 3552 onClose: close, 3553 footer: /* @__PURE__ */ u2(k, { 3554 children: [
3555 /* @__PURE__ */ u2("button", { 3556 type: "button", 3557 class: "qs-btn", 3558 onClick: close, 3559 children: "Cancel" 3560 }), 3561 /* @__PURE__ */ u2("button", { 3562 type: "button", 3563 class: "qs-btn qs-btn-primary", 3564 disabled: !htmlId || isSaving, 3565 onClick: save, 3566 children: [ 3567 isSaving ? /* @__PURE__ */ u2("span", { 3568 class: "qs-spin" 3569 }) : ic.check, 3570 "Save placeholder" 3571 ] 3572 }) 3573 ] 3574 }), 3575 children: [ 3576 !isConnecting && /* @__PURE__ */ u2(AiGrabCard, { 3577 kind: "placeholder", 3578 hostElem: props.hostElem, 3579 pageUrl: getPageUrl(), 3580 title: "Describe this placement", 3581 hint: "Tell the AI what this placeholder is for - it reads this page, picks the element to anchor the content to, decides where it goes, and names the spot for you.", 3582 placeholder: 'e.g. a promo strip under the "Shop by Category" title... / a recommendations widget before the footer...', 3583 chips: AI_CHIPS, 3584 onApply: applySuggestion 3585 }),
3586 /* @__PURE__ */ u2(PanelSection, { 3587 icon: ic.target, 3588 title: "Select the placeholder element", 3589 meta: htmlId ? scope.label : "", 3590 isOpen: isPickOpen, 3591 onToggle: () => setIsPickOpen(!isPickOpen), 3592 children: [ 3593 /* @__PURE__ */ u2("div", { 3594 class: "qs-hint", 3595 children: "Point and click an element on the page. Personyze writes the CSS selector for you \u2014 walk up the list to widen the selection, or start over with Reselect." 3596 }), 3597 /* @__PURE__ */ u2(ElementPickBody, { 3598 pick, 3599 isConnecting, 3600 pickLabel: "Pick an element" 3601 }), 3602 !!htmlId && /* @__PURE__ */ u2("div", { 3603 class: "qs-scope " + (scope.isWide ? "qs-wide" : "qs-narrow"), 3604 children: [ 3605 /* @__PURE__ */ u2("div", { 3606 class: "qs-scope-top", 3607 children: [ 3608 /* @__PURE__ */ u2("span", { 3609 class: "qs-scope-dot" 3610 }),
3611 /* @__PURE__ */ u2("span", { 3612 class: "qs-scope-label", 3613 children: scope.label 3614 }), 3615 /* @__PURE__ */ u2("span", { 3616 class: "qs-scope-tag", 3617 children: scope.tag 3618 }) 3619 ] 3620 }), 3621 /* @__PURE__ */ u2("div", { 3622 class: "qs-scope-meter", 3623 children: /* @__PURE__ */ u2("div", { 3624 class: "qs-scope-bar", 3625 style: `width:${Math.round(scope.ratio * 100)}%` 3626 }) 3627 }), 3628 /* @__PURE__ */ u2("div", { 3629 class: "qs-scope-scale", 3630 children: [ 3631 /* @__PURE__ */ u2("span", { 3632 children: "This page & variants" 3633 }), 3634 /* @__PURE__ */ u2("span", { 3635 children: "Many pages" 3636 }) 3637 ] 3638 }), 3639 /* @__PURE__ */ u2("div", { 3640 class: "qs-scope-desc", 3641 children: scope.desc 3642 }) 3643 ] 3644 }) 3645 ] 3646 }),
3647 /* @__PURE__ */ u2(PanelSection, { 3648 icon: ic.swap, 3649 title: "Put personalized content to", 3650 meta: placeMeta?.meta, 3651 isOpen: isPlaceOpen, 3652 onToggle: () => setIsPlaceOpen(!isPlaceOpen), 3653 children: [ 3654 /* @__PURE__ */ u2("div", { 3655 class: "qs-hint", 3656 children: "Where the content is injected, relative to the element you selected." 3657 }), 3658 PLACE_MODES.map((item) => /* @__PURE__ */ u2("button", { 3659 type: "button", 3660 class: "qs-opt" + (item.value == placeMode ? " qs-on" : ""), 3661 // Answering this one opens the preview, which is the only reason to still be 3662 // here: the placement is chosen to be looked at. 3663 onClick: () => { 3664 setPlaceMode(item.value); 3665 setIsPlaceOpen(false); 3666 setIsLookOpen(true); 3667 }, 3668 children: [ 3669 /* @__PURE__ */ u2("span", { 3670 class: "qs-opt-radio" 3671 }), 3672 /* @__P
3672URE__ */ u2("span", { 3673 children: [ 3674 /* @__PURE__ */ u2("div", { 3675 class: "qs-opt-t", 3676 children: item.text 3677 }), 3678 /* @__PURE__ */ u2("div", { 3679 class: "qs-opt-d", 3680 children: item.hint 3681 }) 3682 ] 3683 }) 3684 ] 3685 }, item.value)) 3686 ] 3687 }), 3688 /* @__PURE__ */ u2(PanelSection, { 3689 icon: ic.eye, 3690 title: "Test the look", 3691 meta: isPreviewOn ? previewSize : "Nothing previewed", 3692 isOpen: isLookOpen, 3693 onToggle: () => setIsLookOpen(!isLookOpen), 3694 children: [ 3695 /* @__PURE__ */ u2("div", { 3696 class: "qs-hint", 3697 children: "Drop a blank block in to see how content sits here. Nothing is saved to the page \u2014 this is only a preview, and it comes off when you save." 3698 }), 3699 /* @__PURE__ */ u2("div", { 3700 class: "qs-label", 3701 children: "Test a blank ad size" 3702 }),
3703 /* @__PURE__ */ u2("div", { 3704 class: "qs-sizes", 3705 children: PREVIEW_SIZES.map((v3) => /* @__PURE__ */ u2("button", { 3706 type: "button", 3707 class: "qs-size" + (v3.value == previewSize ? " qs-on" : ""), 3708 onClick: () => setPreviewSize(v3.value), 3709 children: v3.value 3710 }, v3.value)) 3711 }), 3712 /* @__PURE__ */ u2("div", { 3713 class: "qs-size-custom", 3714 children: [ 3715 /* @__PURE__ */ u2("span", { 3716 children: "Or" 3717 }), 3718 /* @__PURE__ */ u2("input", { 3719 class: "qs-num", 3720 type: "number", 3721 min: "1", 3722 value: customWidth, 3723 onInput: (e3) => setCustomWidth(Number(e3.target.value) || 0) 3724 }), 3725 /* @__PURE__ */ u2("span", { 3726 children: "\xD7" 3727 }), 3728 /* @__PURE__ */ u2("input", { 3729 class: "qs-num", 3730 type: "number", 3731 min: "1", 3732 value: customHeight, 3733 onInput: (e3) => setCustomHeight(Number(e3.target.value) || 0) 3734 }),
3735 /* @__PURE__ */ u2("button", { 3736 type: "button", 3737 class: "qs-btn", 3738 disabled: !(customWidth > 0 && customHeight > 0), 3739 onClick: () => setPreviewSize(`${customWidth | 0}x${customHeight | 0}`), 3740 children: "Use this size" 3741 }) 3742 ] 3743 }), 3744 /* @__PURE__ */ u2("div", { 3745 class: "qs-btn-row", 3746 style: "margin-top:0.7em", 3747 children: /* @__PURE__ */ u2("button", { 3748 type: "button", 3749 class: "qs-btn", 3750 disabled: !selected, 3751 onClick: () => setIsPreviewOn(!isPreviewOn), 3752 children: [ 3753 ic.layout, 3754 isPreviewOn ? "Remove preview" : "Preview in this location" 3755 ] 3756 }) 3757 }) 3758 ] 3759 }) 3760 ] 3761 }); 3762} 3763function previewElem(size, color) { 3764 const [width, height] = size.split("x"); 3765 const elem = document.createElement("div"); 3766 elem.style.cssText = `box-sizing:border-box; width:${width}px; height:${height}px; max-width:100%; line-height:${height}px; border:1px solid ${color}; text-align:center; overflow:hidden; background-image:repeating-linear-gradient(135deg, ${color} 0px, ${color} 5px, white 5px, white 10px, ${color} 10px)`; 3767 const text = document.createElement("span"); 3768 text.style.cssText = "background-color:white; color:black; padding:3px; font:normal normal 400 13px/1.45 sans-serif"; 3769 text.textContent = size; 3770 elem.appendChild(text); 3771 return elem; 3772} 3773function parseAeWhere(htmlChange) { 3774 let value = htmlChange; 3775 if (typeof value == "string") { 3776 if (!value) { 3777 return void 0; 3778 } 3779 try { 3780 value = JSON.parse(value); 3781 } catch { 3782 return void 0; 3783 } 3784 } 3785 const aeWhere = value?.ae_where; 3786 return aeWhere == "before" || aeWhere == "after" || aeWhere == "replace" || aeWhere == "inside" ? aeWhere : void 0; 3787} 3788
3789// src/apps/simulator-placeholder.ts 3790var HOST_STYLE = "all: initial !important; position: fixed !important; z-index: 2147483647 !important; top: 0 !important; left: 0 !important; width: 0 !important; height: 0 !important"; 3791function start(options) { 3792 if (options.jsapi_url) { 3793 configureJsapi({ 3794 url: options.jsapi_url, 3795 serverId: options.server_id || 0 3796 }); 3797 } 3798 const hostElem = document.createElement("div"); 3799 hostElem.setAttribute("style", HOST_STYLE); 3800 document.body.appendChild(hostElem); 3801 const shadow = hostElem.attachShadow({ 3802 mode: "open" 3803 }); 3804 const style = document.createElement("style"); 3805 style.textContent = PANEL_STYLE; 3806 shadow.appendChild(style); 3807 const mount = document.createElement("div"); 3808 shadow.appendChild(mount); 3809 B(_(PlaceholderTool, { 3810 bufferKey: options.buffer_key, 3811 guiOrigin: options.gui_origin || "*", 3812 counterUrl: options.counter_url || "", 3813 hostElem 3814 }), mount); 3815 return { 3816 destroy() { 3817 B(null, mount); 3818 hostElem.remove(); 3819 } 3820 }; 3821} 3822var globalScope = globalThis; 3823if (globalScope.personyzeSimulatorPlaceholder == void 0) { 3824 globalScope.personyzeSimulatorPlaceholder = { 3825 version: 1, 3826 start 3827 }; 3828} 3829})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.