@sagepilot-ai/web-events-addon 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -338,7 +338,7 @@ function createSagepilotInstallationClient(options) {
338
338
 
339
339
  // package.json
340
340
  var name = "@sagepilot-ai/web-events-addon";
341
- var version = "0.2.2";
341
+ var version = "0.2.3";
342
342
 
343
343
  // src/projection.ts
344
344
  var sensitive = /password|passwd|secret|token|authorization|cookie|session|email|phone|contact|address|card|payment|cvv|ssn|dob|birth|customer|user|account|person|profile|name|description|message|content|text|search|query/i;
@@ -2175,6 +2175,8 @@ var popupDesignStyles = [
2175
2175
  ].join("");
2176
2176
 
2177
2177
  // src/popup.ts
2178
+ var PHONE_FORMAT = /^\+[1-9][0-9]{7,14}$/;
2179
+ var PHONE_GUIDANCE = "Start with + and your country code, e.g. +12025550123. No spaces or dashes.";
2178
2180
  function popupCompletionKey(workspaceId, installationId) {
2179
2181
  return `sagepilot:sdk-popup:${workspaceId}:${installationId}:completed`;
2180
2182
  }
@@ -2225,6 +2227,30 @@ function createPopup(options) {
2225
2227
  if (text2 !== void 0) node2.textContent = text2;
2226
2228
  return node2;
2227
2229
  }
2230
+ function phoneField(label2, input) {
2231
+ const guidance = input.required ? PHONE_GUIDANCE : "Optional. " + PHONE_GUIDANCE;
2232
+ const hint = element("small", guidance);
2233
+ hint.id = "sage-popup-phone-hint";
2234
+ hint.className = "phone-hint";
2235
+ hint.setAttribute("aria-live", "polite");
2236
+ input.setAttribute("aria-describedby", hint.id);
2237
+ function validate() {
2238
+ const value = input.value.trim();
2239
+ const invalid = (input.required || value.length > 0) && !PHONE_FORMAT.test(value);
2240
+ if (invalid === (input.getAttribute("aria-invalid") === "true")) return !invalid;
2241
+ input.setAttribute("aria-invalid", String(invalid));
2242
+ hint.classList.toggle("phone-error", invalid);
2243
+ hint.textContent = invalid ? "Check your phone number. " + PHONE_GUIDANCE : guidance;
2244
+ return !invalid;
2245
+ }
2246
+ function updatePhoneError() {
2247
+ if (input.getAttribute("aria-invalid") === "true") validate();
2248
+ }
2249
+ input.addEventListener("input", updatePhoneError);
2250
+ const group = element("div");
2251
+ group.append(label2, hint);
2252
+ return { group, validate };
2253
+ }
2228
2254
  function show() {
2229
2255
  if (!eligible() || !config) return;
2230
2256
  const published = config, revision = ++generation;
@@ -2235,6 +2261,7 @@ function createPopup(options) {
2235
2261
  const shadow = host.attachShadow({ mode: "open" });
2236
2262
  const style = element("style");
2237
2263
  style.textContent = `:host{font-family:system-ui,sans-serif;color:#172c23;color-scheme:light}*{box-sizing:border-box}.panel{background:white;width:min(420px,calc(100vw - 40px));max-height:90dvh;overflow:auto;border-radius:18px;padding:28px;box-shadow:0 16px 80px #0003;position:relative}h2{margin:4px 28px 10px 0;font-size:25px}p{line-height:1.5;color:#52645a}label{display:block;margin-top:14px;font-size:14px}input{display:block;width:100%;padding:11px;border:1px solid #b6c7bd;border-radius:7px;margin-top:6px;font:inherit;background:white;color:#172c23}button{cursor:pointer;font:inherit;color:inherit}button[type=submit]{display:block;width:100%;border:0;border-radius:8px;background:${published.accent_color};color:white;padding:13px;margin-top:20px;font-weight:600}button:disabled{opacity:.6;cursor:wait}.close{position:absolute;right:15px;top:12px;border:0;background:transparent;font-size:25px}.status{min-height:1.3em;font-size:14px}.logo{max-width:160px;max-height:60px;object-fit:contain}input:focus-visible,button:focus-visible{outline:3px solid #729e82;outline-offset:3px}@media(max-width:480px){.panel{padding:22px}h2{font-size:22px}}`;
2264
+ style.textContent += ".phone-hint{display:block;margin-top:6px;line-height:1.4}.phone-error{font-weight:600}";
2238
2265
  style.textContent += popupDesignStyles;
2239
2266
  shadow.append(style);
2240
2267
  const panel = element("section");
@@ -2256,7 +2283,8 @@ function createPopup(options) {
2256
2283
  status.setAttribute("role", "status");
2257
2284
  status.setAttribute("aria-live", "polite");
2258
2285
  const inputs = /* @__PURE__ */ new Map();
2259
- const contactLabels = [];
2286
+ const contactFields = [];
2287
+ let validatePhone;
2260
2288
  for (const field of ["name", "email", "phone"]) {
2261
2289
  if (!published.fields[field]) continue;
2262
2290
  const label2 = element("label", field === "phone" ? "Phone" : field === "email" ? "Email" : "Name");
@@ -2267,8 +2295,14 @@ function createPopup(options) {
2267
2295
  input.maxLength = field === "phone" ? 32 : field === "email" ? 254 : 100;
2268
2296
  input.required = published.required_fields.includes(field) || field === "email" && published.verification === "email";
2269
2297
  label2.append(input);
2270
- form.append(label2);
2271
- contactLabels.push(label2);
2298
+ let control = label2;
2299
+ if (field === "phone") {
2300
+ const phone = phoneField(label2, input);
2301
+ control = phone.group;
2302
+ validatePhone = phone.validate;
2303
+ }
2304
+ form.append(control);
2305
+ contactFields.push(control);
2272
2306
  inputs.set(field, input);
2273
2307
  }
2274
2308
  const submit = element("button", published.button_text);
@@ -2284,6 +2318,11 @@ function createPopup(options) {
2284
2318
  async function submitForm(event) {
2285
2319
  event.preventDefault();
2286
2320
  if (busy || revision !== generation) return;
2321
+ if (!challenge && validatePhone?.() === false) {
2322
+ status.textContent = "";
2323
+ inputs.get("phone")?.focus();
2324
+ return;
2325
+ }
2287
2326
  busy = true;
2288
2327
  submit.disabled = true;
2289
2328
  status.textContent = "";
@@ -2312,7 +2351,7 @@ function createPopup(options) {
2312
2351
  for (const [key, value] of contactInputs) inputs.set(key, value);
2313
2352
  submit.textContent = published.button_text;
2314
2353
  status.textContent = "";
2315
- form.replaceChildren(...contactLabels, submit, status);
2354
+ form.replaceChildren(...contactFields, submit, status);
2316
2355
  inputs.values().next().value?.focus();
2317
2356
  };
2318
2357
  var restartForm = restartForm2;