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

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.cjs CHANGED
@@ -364,7 +364,7 @@ function createSagepilotInstallationClient(options) {
364
364
 
365
365
  // package.json
366
366
  var name = "@sagepilot-ai/web-events-addon";
367
- var version = "0.2.2";
367
+ var version = "0.2.4";
368
368
 
369
369
  // src/projection.ts
370
370
  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;
@@ -2201,6 +2201,8 @@ var popupDesignStyles = [
2201
2201
  ].join("");
2202
2202
 
2203
2203
  // src/popup.ts
2204
+ var PHONE_FORMAT = /^\+[1-9][0-9]{7,14}$/;
2205
+ var PHONE_GUIDANCE = "Start with + and your country code, e.g. +12025550123. No spaces or dashes.";
2204
2206
  function popupCompletionKey(workspaceId, installationId) {
2205
2207
  return `sagepilot:sdk-popup:${workspaceId}:${installationId}:completed`;
2206
2208
  }
@@ -2251,6 +2253,30 @@ function createPopup(options) {
2251
2253
  if (text2 !== void 0) node2.textContent = text2;
2252
2254
  return node2;
2253
2255
  }
2256
+ function phoneField(label2, input) {
2257
+ const guidance = input.required ? PHONE_GUIDANCE : "Optional. " + PHONE_GUIDANCE;
2258
+ const hint = element("small", guidance);
2259
+ hint.id = "sage-popup-phone-hint";
2260
+ hint.className = "phone-hint";
2261
+ hint.setAttribute("aria-live", "polite");
2262
+ input.setAttribute("aria-describedby", hint.id);
2263
+ function validate() {
2264
+ const value = input.value.trim();
2265
+ const invalid = (input.required || value.length > 0) && !PHONE_FORMAT.test(value);
2266
+ if (invalid === (input.getAttribute("aria-invalid") === "true")) return !invalid;
2267
+ input.setAttribute("aria-invalid", String(invalid));
2268
+ hint.classList.toggle("phone-error", invalid);
2269
+ hint.textContent = invalid ? "Check your phone number. " + PHONE_GUIDANCE : guidance;
2270
+ return !invalid;
2271
+ }
2272
+ function updatePhoneError() {
2273
+ if (input.getAttribute("aria-invalid") === "true") validate();
2274
+ }
2275
+ input.addEventListener("input", updatePhoneError);
2276
+ const group = element("div");
2277
+ group.append(label2, hint);
2278
+ return { group, validate };
2279
+ }
2254
2280
  function show() {
2255
2281
  if (!eligible() || !config) return;
2256
2282
  const published = config, revision = ++generation;
@@ -2261,6 +2287,7 @@ function createPopup(options) {
2261
2287
  const shadow = host.attachShadow({ mode: "open" });
2262
2288
  const style = element("style");
2263
2289
  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}}`;
2290
+ style.textContent += ".phone-hint{display:block;margin-top:6px;line-height:1.4}.phone-error{font-weight:600}";
2264
2291
  style.textContent += popupDesignStyles;
2265
2292
  shadow.append(style);
2266
2293
  const panel = element("section");
@@ -2282,7 +2309,8 @@ function createPopup(options) {
2282
2309
  status.setAttribute("role", "status");
2283
2310
  status.setAttribute("aria-live", "polite");
2284
2311
  const inputs = /* @__PURE__ */ new Map();
2285
- const contactLabels = [];
2312
+ const contactFields = [];
2313
+ let validatePhone;
2286
2314
  for (const field of ["name", "email", "phone"]) {
2287
2315
  if (!published.fields[field]) continue;
2288
2316
  const label2 = element("label", field === "phone" ? "Phone" : field === "email" ? "Email" : "Name");
@@ -2293,8 +2321,14 @@ function createPopup(options) {
2293
2321
  input.maxLength = field === "phone" ? 32 : field === "email" ? 254 : 100;
2294
2322
  input.required = published.required_fields.includes(field) || field === "email" && published.verification === "email";
2295
2323
  label2.append(input);
2296
- form.append(label2);
2297
- contactLabels.push(label2);
2324
+ let control = label2;
2325
+ if (field === "phone") {
2326
+ const phone = phoneField(label2, input);
2327
+ control = phone.group;
2328
+ validatePhone = phone.validate;
2329
+ }
2330
+ form.append(control);
2331
+ contactFields.push(control);
2298
2332
  inputs.set(field, input);
2299
2333
  }
2300
2334
  const submit = element("button", published.button_text);
@@ -2310,6 +2344,11 @@ function createPopup(options) {
2310
2344
  async function submitForm(event) {
2311
2345
  event.preventDefault();
2312
2346
  if (busy || revision !== generation) return;
2347
+ if (!challenge && validatePhone?.() === false) {
2348
+ status.textContent = "";
2349
+ inputs.get("phone")?.focus();
2350
+ return;
2351
+ }
2313
2352
  busy = true;
2314
2353
  submit.disabled = true;
2315
2354
  status.textContent = "";
@@ -2338,7 +2377,7 @@ function createPopup(options) {
2338
2377
  for (const [key, value] of contactInputs) inputs.set(key, value);
2339
2378
  submit.textContent = published.button_text;
2340
2379
  status.textContent = "";
2341
- form.replaceChildren(...contactLabels, submit, status);
2380
+ form.replaceChildren(...contactFields, submit, status);
2342
2381
  inputs.values().next().value?.focus();
2343
2382
  };
2344
2383
  var restartForm = restartForm2;