@sonordev/site-kit 7.1.2 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +60 -0
  3. package/README.md +9 -8
  4. package/agent-manifest.json +17 -7
  5. package/dist/{AnalyticsProvider-ZB33W6MC.js → AnalyticsProvider-DJQA66AG.js} +4 -4
  6. package/dist/{ArticleViewTracker-GMHYLLLZ.js → ArticleViewTracker-GFOAXFV7.js} +3 -3
  7. package/dist/{BlocksPopup-EA6LYL25.js → BlocksPopup-AHDU34TL.js} +5 -5
  8. package/dist/ChatWidget-FHBAHFZX.js +17 -0
  9. package/dist/{FileField-QKA3JB2Q.js → FileField-J5W5MIAZ.js} +3 -3
  10. package/dist/{FormSpotlight-AQTIA5TP.js → FormSpotlight-PE5YZBFZ.js} +20 -6
  11. package/dist/{FormStage-FDTLTP3B.js → FormStage-OOPQC27J.js} +27 -7
  12. package/dist/ManagedForm-JRZAJ7SZ.js +16 -0
  13. package/dist/{ManagedNewsletterForm-J6QSAGGP.js → ManagedNewsletterForm-TC5542ZG.js} +7 -5
  14. package/dist/{SignalCore-JZNXOLNT.js → SignalCore-2YP5FCAS.js} +3 -3
  15. package/dist/SiteChat-EGEZJJVV.js +5 -0
  16. package/dist/{SiteDesignReporter-W4EJUSTE.js → SiteDesignReporter-YEEWJKWN.js} +5 -5
  17. package/dist/SitePopups-LQBIXIFV.js +10 -0
  18. package/dist/SitemapSync-LSZ2EYOF.js +8 -0
  19. package/dist/_client/booking-widget.js +5 -5
  20. package/dist/affiliates/index.js +3 -3
  21. package/dist/analytics/index.js +4 -4
  22. package/dist/analytics/send-gate.d.ts +1 -1
  23. package/dist/articles/index.js +2 -2
  24. package/dist/articles/server-ui.js +3 -2
  25. package/dist/articles/server.js +2 -1
  26. package/dist/{engage → chat}/ChatWidget.d.ts +7 -6
  27. package/dist/{engage → chat}/EchoUiActions.d.ts +1 -1
  28. package/dist/chat/SiteChat.d.ts +25 -0
  29. package/dist/{engage → chat}/brand-color.d.ts +1 -1
  30. package/dist/{engage → chat}/chat-messages.d.ts +1 -1
  31. package/dist/{engage → chat}/echo-config.d.ts +1 -1
  32. package/dist/chat/index.d.ts +10 -6
  33. package/dist/chat/index.js +14 -8
  34. package/dist/{engage → chat}/launcher-placement.d.ts +1 -7
  35. package/dist/{engage → chat}/socket-loader.d.ts +2 -2
  36. package/dist/chat/types.d.ts +136 -0
  37. package/dist/chunk-27FISYK4.js +4 -0
  38. package/dist/{chunk-HF57LG73.js → chunk-2AD3CDRR.js} +43 -29
  39. package/dist/{chunk-M3YEPKP7.js → chunk-2ECWEUHP.js} +1 -1
  40. package/dist/{chunk-LUXVWITO.js → chunk-4NTBQNHA.js} +247 -78
  41. package/dist/{chunk-AH5Q262S.js → chunk-56KNHB4U.js} +1 -1
  42. package/dist/{chunk-GLHQ3LRO.js → chunk-6U3VLV2C.js} +1 -1
  43. package/dist/{chunk-3SDOQUUF.js → chunk-BEBR4OJD.js} +2 -2
  44. package/dist/{chunk-JSZN6LDZ.js → chunk-BF7TZYC3.js} +38 -31
  45. package/dist/{chunk-AQSNPZY4.js → chunk-C2FZBUSS.js} +80 -1
  46. package/dist/{chunk-PHYMNUJU.js → chunk-CYUFBKJQ.js} +1 -1
  47. package/dist/{chunk-6WIQCXOO.js → chunk-DNPNYWVL.js} +1 -1
  48. package/dist/{chunk-V6FDQLR7.js → chunk-EPT6FJUY.js} +53 -21
  49. package/dist/chunk-HODO5BX5.js +28 -0
  50. package/dist/chunk-HW7B43E5.js +14 -0
  51. package/dist/{chunk-PGMVL4AB.js → chunk-I2YX3HVD.js} +2 -2
  52. package/dist/{chunk-JTU2GOM4.js → chunk-L7U23XI2.js} +18 -6
  53. package/dist/{chunk-YEMPUQVU.js → chunk-MKMD2HJW.js} +2 -2
  54. package/dist/{chunk-Q4W23JYM.js → chunk-MRQ2U4LZ.js} +1 -1
  55. package/dist/chunk-MVR4FY5R.js +187 -0
  56. package/dist/{chunk-VGH4MDTU.js → chunk-NI2XNEMR.js} +1 -1
  57. package/dist/{chunk-4Y5FWDPM.js → chunk-NZ4RXN3G.js} +55 -7
  58. package/dist/{chunk-RHNWA34F.js → chunk-O5RGXTWU.js} +41 -7
  59. package/dist/{chunk-TXBAOEKG.js → chunk-PKGN32AU.js} +5 -4
  60. package/dist/chunk-Q6E4OPGG.js +40 -0
  61. package/dist/chunk-RDPW4D33.js +45 -0
  62. package/dist/{chunk-UXOGCKL6.js → chunk-T4DLETKR.js} +1 -1
  63. package/dist/{chunk-NK4CSJNP.js → chunk-UPRSH6Q4.js} +2 -2
  64. package/dist/{chunk-ERXXITG4.js → chunk-VF4F5WXZ.js} +1 -1
  65. package/dist/chunk-VWWITFWM.js +300 -0
  66. package/dist/{chunk-WWSHFRDL.js → chunk-WDQB4OXY.js} +7 -3
  67. package/dist/{chunk-VDF5DFWT.js → chunk-WGG6GTKW.js} +1 -1
  68. package/dist/{chunk-CSTQDNGK.js → chunk-WGIDC6QP.js} +43 -24
  69. package/dist/{chunk-V3PUVBME.js → chunk-XLSQTTUE.js} +2 -4
  70. package/dist/{chunk-JBE46QJZ.js → chunk-Y6LP36UW.js} +1 -1
  71. package/dist/chunk-YJLS6JBI.js +370 -0
  72. package/dist/{chunk-QEDHRBAT.js → chunk-Z65DHMTW.js} +26 -9
  73. package/dist/{chunk-ILU5I6RW.js → chunk-ZHS2XFLV.js} +1 -1
  74. package/dist/{chunk-D5EC5KVO.js → chunk-ZKHI4E2B.js} +2 -2
  75. package/dist/{chunk-CIG5UL2S.js → chunk-ZTLMPUO6.js} +3 -2
  76. package/dist/client/index.js +3 -3
  77. package/dist/commerce/index.js +4 -4
  78. package/dist/contracts/color.d.ts +1 -1
  79. package/dist/contracts/entries.d.ts +1 -1
  80. package/dist/contracts/error-page.d.ts +183 -0
  81. package/dist/contracts/llms.d.ts +1 -0
  82. package/dist/contracts/proposal-sitemap.d.ts +130 -0
  83. package/dist/contracts/schema-placeholders.d.ts +87 -0
  84. package/dist/engage/EngageWidget.d.ts +13 -12
  85. package/dist/engage/index.d.ts +10 -9
  86. package/dist/engage/index.js +31 -35
  87. package/dist/engage/types.d.ts +19 -244
  88. package/dist/fleet/FleetHeartbeat.d.ts +1 -1
  89. package/dist/fleet/index.js +4 -4
  90. package/dist/forms/FormEnhancer.d.ts +25 -12
  91. package/dist/forms/ServerForm.d.ts +11 -10
  92. package/dist/forms/StaticForm.d.ts +3 -1
  93. package/dist/forms/field-autocomplete.d.ts +28 -0
  94. package/dist/forms/form-dom-values.d.ts +42 -0
  95. package/dist/forms/index.js +11 -9
  96. package/dist/forms/server.js +6 -4
  97. package/dist/forms/static.js +3 -2
  98. package/dist/forms/submitForm.d.ts +8 -1
  99. package/dist/forms/types.d.ts +41 -2
  100. package/dist/forms/useForm.d.ts +21 -4
  101. package/dist/forms/webmcp.d.ts +38 -0
  102. package/dist/images/index.js +4 -4
  103. package/dist/index.d.ts +4 -1
  104. package/dist/index.js +1 -1
  105. package/dist/layout/SiteKitClientProviders.d.ts +3 -3
  106. package/dist/layout/SiteKitLayout.d.ts +4 -4
  107. package/dist/layout/client.d.ts +3 -3
  108. package/dist/layout/client.js +7 -7
  109. package/dist/layout/index.js +8 -8
  110. package/dist/layout/types.d.ts +5 -4
  111. package/dist/llms/agent-access.d.ts +4 -0
  112. package/dist/llms/contract.js +1 -1
  113. package/dist/llms/index.js +6 -6
  114. package/dist/maps/index.js +3 -3
  115. package/dist/mcp/WebMcpTools.d.ts +5 -4
  116. package/dist/mcp/client.js +14 -7
  117. package/dist/mcp/discovery.d.ts +48 -0
  118. package/dist/mcp/handlers.d.ts +13 -7
  119. package/dist/mcp/index.d.ts +5 -3
  120. package/dist/mcp/index.js +62 -30
  121. package/dist/mcp/serverCard.d.ts +6 -7
  122. package/dist/mcp/sonor.js +14 -11
  123. package/dist/revalidate/index.js +2 -2
  124. package/dist/seo/client.js +4 -4
  125. package/dist/seo/index.js +15 -8
  126. package/dist/seo/llms/contract.js +1 -1
  127. package/dist/seo/llms.js +6 -6
  128. package/dist/seo/register-sitemap-cli.js +1 -1
  129. package/dist/seo/sitemap.js +4 -4
  130. package/dist/server/index.js +2 -2
  131. package/dist/shared/dialog.d.ts +27 -0
  132. package/dist/shared/identity.d.ts +1 -1
  133. package/dist/shared/layers.d.ts +7 -0
  134. package/dist/shared/mid-form.d.ts +53 -0
  135. package/dist/shared/reporting-gate.d.ts +1 -1
  136. package/dist/shared/version.d.ts +1 -1
  137. package/dist/shared/visual-viewport-gap.d.ts +1 -1
  138. package/dist/signal/index.js +2 -2
  139. package/dist/signal/types.d.ts +1 -1
  140. package/dist/sitemap/index.js +4 -4
  141. package/dist/{socket-loader-R24ZSRSQ.js → socket-loader-CGIPEG74.js} +1 -1
  142. package/dist/sync/index.js +5 -5
  143. package/dist/types.d.ts +3 -1
  144. package/dist/{web-vitals.attribution-GD6LGLVF.js → web-vitals.attribution-N2PCCF4Q.js} +1 -1
  145. package/dist/website/BlocksPopup.d.ts +1 -1
  146. package/dist/website/PopupBlocks.d.ts +5 -2
  147. package/dist/website/SitePopups.d.ts +25 -0
  148. package/dist/website/images.js +4 -4
  149. package/dist/website/index.js +6 -6
  150. package/dist/website/popup-rules.d.ts +46 -0
  151. package/dist/website/popup-types.d.ts +113 -0
  152. package/dist/website/popups.d.ts +2 -6
  153. package/dist/website/popups.js +6 -14
  154. package/dist/{writeLLMsTxt-G3JBNBC5.js → writeLLMsTxt-2NQVDGYI.js} +3 -3
  155. package/docs/MIGRATING-TO-7.md +41 -9
  156. package/docs.json +2 -1
  157. package/package.json +2 -2
  158. package/src/analytics/README.md +2 -2
  159. package/src/articles/README.md +4 -1
  160. package/src/{engage → chat}/README.md +63 -62
  161. package/src/forms/README.md +49 -3
  162. package/src/layout/README.md +8 -5
  163. package/src/llms/README.md +69 -0
  164. package/src/mcp/README.md +50 -16
  165. package/src/seo/README.md +3 -1
  166. package/src/sync/README.md +10 -0
  167. package/src/website/README.md +133 -0
  168. package/dist/ChatWidget-UCDWMWCW.js +0 -15
  169. package/dist/EngageWidget-7ZYSK4GE.js +0 -11
  170. package/dist/ManagedForm-H7BVAH2W.js +0 -14
  171. package/dist/SitemapSync-XBANGKHZ.js +0 -8
  172. package/dist/chunk-NDF4A5JM.js +0 -37
  173. package/dist/chunk-VLARKWZU.js +0 -100
  174. package/dist/chunk-YCJT4JJG.js +0 -837
  175. package/dist/engage/DesignRenderer.d.ts +0 -57
  176. package/dist/engage/element-rules.d.ts +0 -38
@@ -1,6 +1,6 @@
1
+ import { declarativeToolField } from './chunk-HW7B43E5.js';
1
2
  import { jsx, jsxs } from 'react/jsx-runtime';
2
3
 
3
- // src/forms/delight.tsx
4
4
  var STYLE_ID = "sk-delight-css";
5
5
  var CSS = `
6
6
  /* Every frame must carry the centering translateY: the animation fills both
@@ -208,6 +208,101 @@ function FormMomentum({ done, total }) {
208
208
  }
209
209
  );
210
210
  }
211
+
212
+ // src/forms/field-autocomplete.ts
213
+ var TOKEN_BY_KEY = {
214
+ email: "email",
215
+ email_address: "email",
216
+ e_mail: "email",
217
+ first_name: "given-name",
218
+ firstname: "given-name",
219
+ fname: "given-name",
220
+ given_name: "given-name",
221
+ last_name: "family-name",
222
+ lastname: "family-name",
223
+ lname: "family-name",
224
+ surname: "family-name",
225
+ family_name: "family-name",
226
+ name: "name",
227
+ full_name: "name",
228
+ fullname: "name",
229
+ your_name: "name",
230
+ contact_name: "name",
231
+ phone: "tel",
232
+ phone_number: "tel",
233
+ telephone: "tel",
234
+ mobile: "tel",
235
+ mobile_phone: "tel",
236
+ cell: "tel",
237
+ cell_phone: "tel",
238
+ tel: "tel",
239
+ company: "organization",
240
+ company_name: "organization",
241
+ organization: "organization",
242
+ organisation: "organization",
243
+ business_name: "organization",
244
+ job_title: "organization-title",
245
+ website: "url",
246
+ website_url: "url",
247
+ company_website: "url",
248
+ url: "url",
249
+ street_address: "street-address",
250
+ address_line1: "address-line1",
251
+ address_line_1: "address-line1",
252
+ address1: "address-line1",
253
+ address_line2: "address-line2",
254
+ address_line_2: "address-line2",
255
+ address2: "address-line2",
256
+ city: "address-level2",
257
+ state: "address-level1",
258
+ province: "address-level1",
259
+ zip: "postal-code",
260
+ zip_code: "postal-code",
261
+ zipcode: "postal-code",
262
+ postal_code: "postal-code",
263
+ postcode: "postal-code",
264
+ country: "country-name"
265
+ };
266
+ var TOKEN_FIELD_TYPES = /* @__PURE__ */ new Set(["text", "email", "phone", "tel", "select"]);
267
+ function toKey(raw) {
268
+ return raw.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/\*/g, "").trim().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
269
+ }
270
+ function withoutGeneratedSuffix(key) {
271
+ const match = /^(.+)_([a-z0-9]{6,10})$/.exec(key);
272
+ if (match && /\d/.test(match[2])) return match[1];
273
+ return key;
274
+ }
275
+ function tokenForKey(raw) {
276
+ if (!raw) return void 0;
277
+ const key = toKey(raw);
278
+ return TOKEN_BY_KEY[key] ?? TOKEN_BY_KEY[withoutGeneratedSuffix(key)];
279
+ }
280
+ function autocompleteFor(field) {
281
+ if (!TOKEN_FIELD_TYPES.has(field.field_type)) return void 0;
282
+ const destination = field.destination_field;
283
+ if (destination && !destination.startsWith("custom.")) {
284
+ const fromDestination = tokenForKey(destination);
285
+ if (fromDestination) return fromDestination;
286
+ }
287
+ if (field.field_type === "email") return "email";
288
+ if (field.field_type === "phone" || field.field_type === "tel") return "tel";
289
+ return tokenForKey(field.slug) ?? tokenForKey(field.label);
290
+ }
291
+ var SINGLE_CONTROL_TYPES = /* @__PURE__ */ new Set([
292
+ "text",
293
+ "email",
294
+ "phone",
295
+ "tel",
296
+ "number",
297
+ "textarea",
298
+ "select",
299
+ "multi-select",
300
+ "date",
301
+ "time",
302
+ "datetime",
303
+ "file",
304
+ "slider"
305
+ ]);
211
306
  function normalizeOptions(options) {
212
307
  if (!options) return [];
213
308
  if (Array.isArray(options)) {
@@ -279,6 +374,17 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
279
374
  }
280
375
  const hideLabel = !!field.hide_label;
281
376
  const effectivePlaceholder = hideLabel ? field.label : field.placeholder;
377
+ const labelId = `${inputId}-label`;
378
+ const errorId = `${inputId}-error`;
379
+ const helpId = `${inputId}-help`;
380
+ const showsHelp = !!field.help_text && !error && field.field_type !== "checkbox";
381
+ const describedBy = [error ? errorId : null, showsHelp ? helpId : null].filter(Boolean).join(" ") || void 0;
382
+ const a11y = {
383
+ "aria-invalid": error ? true : void 0,
384
+ "aria-describedby": describedBy
385
+ };
386
+ const autoComplete = autocompleteFor(field);
387
+ const toolParam = field.help_text ? declarativeToolField(`${field.label}. ${field.help_text}`) : {};
282
388
  const focusProps = interactive && (onFocus || onBlur) ? {
283
389
  onFocus: (e) => {
284
390
  if (!e.currentTarget.contains(e.relatedTarget)) onFocus?.();
@@ -288,10 +394,19 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
288
394
  }
289
395
  } : {};
290
396
  return /* @__PURE__ */ jsxs("div", { className: `${classPrefix}__field ${classPrefix}__field--${field.field_type}`, ...focusProps, children: [
291
- /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: `${classPrefix}__label`, style: { ...labelStyle, ...hideLabel ? { position: "absolute", width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clip: "rect(0,0,0,0)", whiteSpace: "nowrap", border: 0 } : {} }, children: [
292
- field.label,
293
- field.is_required && /* @__PURE__ */ jsx("span", { style: { color: "var(--sk-error, #dc2626)" }, children: " *" })
294
- ] }),
397
+ /* @__PURE__ */ jsxs(
398
+ "label",
399
+ {
400
+ id: labelId,
401
+ htmlFor: SINGLE_CONTROL_TYPES.has(field.field_type) ? inputId : void 0,
402
+ className: `${classPrefix}__label`,
403
+ style: { ...labelStyle, ...hideLabel ? { position: "absolute", width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clip: "rect(0,0,0,0)", whiteSpace: "nowrap", border: 0 } : {} },
404
+ children: [
405
+ field.label,
406
+ field.is_required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: "var(--sk-error, #dc2626)" }, children: " *" })
407
+ ]
408
+ }
409
+ ),
295
410
  ["text", "email", "phone", "tel", "number"].includes(field.field_type) && /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, "data-sk-part": "field-input-wrap", "data-sk-valid": showValid ? "true" : void 0, children: [
296
411
  /* @__PURE__ */ jsx(
297
412
  "input",
@@ -303,6 +418,9 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
303
418
  ...bind(String(value || "")),
304
419
  placeholder: effectivePlaceholder,
305
420
  required: field.is_required,
421
+ autoComplete,
422
+ ...a11y,
423
+ ...toolParam,
306
424
  style: baseInputStyle
307
425
  }
308
426
  ),
@@ -317,6 +435,8 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
317
435
  ...bind(String(value || "")),
318
436
  placeholder: effectivePlaceholder,
319
437
  required: field.is_required,
438
+ ...a11y,
439
+ ...toolParam,
320
440
  rows: 4,
321
441
  style: { ...baseInputStyle, resize: "vertical" }
322
442
  }
@@ -329,6 +449,9 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
329
449
  name: field.slug,
330
450
  ...bind(String(value || "")),
331
451
  required: field.is_required,
452
+ autoComplete,
453
+ ...a11y,
454
+ ...toolParam,
332
455
  style: baseInputStyle,
333
456
  children: [
334
457
  /* @__PURE__ */ jsx("option", { value: "", children: effectivePlaceholder || "Select an option" }),
@@ -347,24 +470,38 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
347
470
  onChange: (e) => emit(Array.from(e.target.selectedOptions, (opt) => opt.value))
348
471
  } : { defaultValue: Array.isArray(value) ? value : [] },
349
472
  required: field.is_required,
473
+ ...a11y,
474
+ ...toolParam,
350
475
  multiple: true,
351
476
  style: { ...baseInputStyle, height: 120 },
352
477
  children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
353
478
  }
354
479
  ),
355
- field.field_type === "radio" && /* @__PURE__ */ jsx("div", { className: `${classPrefix}__radio-group`, style: { display: "flex", flexDirection: "column", gap: 8 }, children: options.map((option) => /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__radio-option`, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
356
- /* @__PURE__ */ jsx(
357
- "input",
358
- {
359
- type: "radio",
360
- name: field.slug,
361
- value: option.value,
362
- ...interactive ? { checked: value === option.value, onChange: () => emit(option.value) } : { defaultChecked: value === option.value },
363
- required: field.is_required
364
- }
365
- ),
366
- option.label
367
- ] }, option.value)) }),
480
+ field.field_type === "radio" && /* @__PURE__ */ jsx(
481
+ "div",
482
+ {
483
+ className: `${classPrefix}__radio-group`,
484
+ role: "radiogroup",
485
+ "aria-labelledby": labelId,
486
+ "aria-required": field.is_required || void 0,
487
+ ...a11y,
488
+ style: { display: "flex", flexDirection: "column", gap: 8 },
489
+ children: options.map((option) => /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__radio-option`, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
490
+ /* @__PURE__ */ jsx(
491
+ "input",
492
+ {
493
+ type: "radio",
494
+ name: field.slug,
495
+ value: option.value,
496
+ ...interactive ? { checked: value === option.value, onChange: () => emit(option.value) } : { defaultChecked: value === option.value },
497
+ required: field.is_required,
498
+ ...toolParam
499
+ }
500
+ ),
501
+ option.label
502
+ ] }, option.value))
503
+ }
504
+ ),
368
505
  field.field_type === "checkbox" && options.length === 0 && /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__checkbox`, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
369
506
  /* @__PURE__ */ jsx(
370
507
  "input",
@@ -372,32 +509,43 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
372
509
  type: "checkbox",
373
510
  name: field.slug,
374
511
  ...interactive ? { checked: !!value, onChange: (e) => emit(e.target.checked) } : { defaultChecked: !!value },
375
- required: field.is_required
512
+ required: field.is_required,
513
+ ...a11y
376
514
  }
377
515
  ),
378
516
  field.help_text || field.label
379
517
  ] }),
380
- field.field_type === "checkbox" && options.length > 0 && /* @__PURE__ */ jsx("div", { className: `${classPrefix}__checkbox-group`, style: { display: "flex", flexDirection: "column", gap: 8 }, children: options.map((option) => {
381
- const selectedValues = Array.isArray(value) ? value : [];
382
- const isChecked = selectedValues.includes(option.value);
383
- return /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__checkbox-option`, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
384
- /* @__PURE__ */ jsx(
385
- "input",
386
- {
387
- type: "checkbox",
388
- name: field.slug,
389
- value: option.value,
390
- ...interactive ? {
391
- checked: isChecked,
392
- onChange: () => emit(
393
- isChecked ? selectedValues.filter((v) => v !== option.value) : [...selectedValues, option.value]
394
- )
395
- } : { defaultChecked: isChecked }
396
- }
397
- ),
398
- option.label
399
- ] }, option.value);
400
- }) }),
518
+ field.field_type === "checkbox" && options.length > 0 && /* @__PURE__ */ jsx(
519
+ "div",
520
+ {
521
+ className: `${classPrefix}__checkbox-group`,
522
+ role: "group",
523
+ "aria-labelledby": labelId,
524
+ "aria-describedby": describedBy,
525
+ style: { display: "flex", flexDirection: "column", gap: 8 },
526
+ children: options.map((option) => {
527
+ const selectedValues = Array.isArray(value) ? value : [];
528
+ const isChecked = selectedValues.includes(option.value);
529
+ return /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__checkbox-option`, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
530
+ /* @__PURE__ */ jsx(
531
+ "input",
532
+ {
533
+ type: "checkbox",
534
+ name: field.slug,
535
+ value: option.value,
536
+ ...interactive ? {
537
+ checked: isChecked,
538
+ onChange: () => emit(
539
+ isChecked ? selectedValues.filter((v) => v !== option.value) : [...selectedValues, option.value]
540
+ )
541
+ } : { defaultChecked: isChecked }
542
+ }
543
+ ),
544
+ option.label
545
+ ] }, option.value);
546
+ })
547
+ }
548
+ ),
401
549
  field.field_type === "date" && (interactive && controls?.Date ? /* @__PURE__ */ jsx(
402
550
  controls.Date,
403
551
  {
@@ -421,6 +569,8 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
421
569
  name: field.slug,
422
570
  defaultValue: String(value || "") || void 0,
423
571
  required: field.is_required,
572
+ ...a11y,
573
+ ...toolParam,
424
574
  style: baseInputStyle
425
575
  }
426
576
  )
@@ -434,6 +584,8 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
434
584
  name: field.slug,
435
585
  ...bind(String(value || "")),
436
586
  required: field.is_required,
587
+ ...a11y,
588
+ ...toolParam,
437
589
  style: baseInputStyle
438
590
  }
439
591
  ),
@@ -446,6 +598,8 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
446
598
  name: field.slug,
447
599
  ...bind(String(value || "")),
448
600
  required: field.is_required,
601
+ ...a11y,
602
+ ...toolParam,
449
603
  style: baseInputStyle
450
604
  }
451
605
  ),
@@ -469,47 +623,60 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
469
623
  type: "file",
470
624
  name: field.slug,
471
625
  required: field.is_required,
626
+ ...a11y,
472
627
  style: baseInputStyle
473
628
  }
474
629
  )
475
630
  )),
476
- field.field_type === "rating" && /* @__PURE__ */ jsxs("div", { className: `${classPrefix}__rating`, style: { display: "flex", gap: 4 }, role: interactive ? void 0 : "radiogroup", "aria-label": interactive ? void 0 : field.label, children: [
477
- !interactive && [1, 2, 3, 4, 5].map((star) => (
478
- // Static: a real radio group. Submits natively, and is reachable
479
- // by keyboard and screen readers without any script.
480
- /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__rating-star`, style: { fontSize: 24, cursor: "pointer", color: value >= star ? "var(--sk-rating-active, #fbbf24)" : "var(--sk-rating-inactive, #d1d5db)" }, children: [
481
- /* @__PURE__ */ jsx(
482
- "input",
631
+ field.field_type === "rating" && /* @__PURE__ */ jsxs(
632
+ "div",
633
+ {
634
+ className: `${classPrefix}__rating`,
635
+ style: { display: "flex", gap: 4 },
636
+ role: interactive ? "group" : "radiogroup",
637
+ "aria-labelledby": labelId,
638
+ "aria-describedby": describedBy,
639
+ children: [
640
+ !interactive && [1, 2, 3, 4, 5].map((star) => (
641
+ // Static: a real radio group. Submits natively, and is reachable
642
+ // by keyboard and screen readers without any script.
643
+ /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__rating-star`, style: { fontSize: 24, cursor: "pointer", color: value >= star ? "var(--sk-rating-active, #fbbf24)" : "var(--sk-rating-inactive, #d1d5db)" }, children: [
644
+ /* @__PURE__ */ jsx(
645
+ "input",
646
+ {
647
+ type: "radio",
648
+ name: field.slug,
649
+ value: star,
650
+ defaultChecked: value === star,
651
+ required: field.is_required && star === 1,
652
+ style: { position: "absolute", width: 1, height: 1, opacity: 0 }
653
+ }
654
+ ),
655
+ /* @__PURE__ */ jsx("span", { "aria-label": `${star} star${star > 1 ? "s" : ""}`, children: "\u2605" })
656
+ ] }, `s${star}`)
657
+ )),
658
+ interactive && [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsx(
659
+ "button",
483
660
  {
484
- type: "radio",
485
- name: field.slug,
486
- value: star,
487
- defaultChecked: value === star,
488
- required: field.is_required && star === 1,
489
- style: { position: "absolute", width: 1, height: 1, opacity: 0 }
490
- }
491
- ),
492
- /* @__PURE__ */ jsx("span", { "aria-label": `${star} star${star > 1 ? "s" : ""}`, children: "\u2605" })
493
- ] }, `s${star}`)
494
- )),
495
- interactive && [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsx(
496
- "button",
497
- {
498
- type: "button",
499
- onClick: () => emit(star),
500
- className: `${classPrefix}__rating-star`,
501
- style: {
502
- background: "none",
503
- border: "none",
504
- fontSize: 24,
505
- cursor: "pointer",
506
- color: value >= star ? "var(--sk-rating-active, #fbbf24)" : "var(--sk-rating-inactive, #d1d5db)"
507
- },
508
- children: "\u2605"
509
- },
510
- star
511
- ))
512
- ] }),
661
+ type: "button",
662
+ onClick: () => emit(star),
663
+ "aria-label": `${star} star${star > 1 ? "s" : ""}`,
664
+ "aria-pressed": value === star,
665
+ className: `${classPrefix}__rating-star`,
666
+ style: {
667
+ background: "none",
668
+ border: "none",
669
+ fontSize: 24,
670
+ cursor: "pointer",
671
+ color: value >= star ? "var(--sk-rating-active, #fbbf24)" : "var(--sk-rating-inactive, #d1d5db)"
672
+ },
673
+ children: "\u2605"
674
+ },
675
+ star
676
+ ))
677
+ ]
678
+ }
679
+ ),
513
680
  field.field_type === "slider" && /* @__PURE__ */ jsxs("div", { className: `${classPrefix}__slider`, children: [
514
681
  /* @__PURE__ */ jsx(
515
682
  "input",
@@ -520,13 +687,15 @@ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix
520
687
  ...interactive ? { value: Number(value || 50), onChange: (e) => emit(Number(e.target.value)) } : { defaultValue: Number(value || 50) },
521
688
  min: field.validation?.min || 0,
522
689
  max: field.validation?.max || 100,
690
+ ...a11y,
691
+ ...toolParam,
523
692
  style: { width: "100%" }
524
693
  }
525
694
  ),
526
695
  /* @__PURE__ */ jsx("div", { className: `${classPrefix}__slider-value`, style: { textAlign: "center", marginTop: 4 }, children: String(value || 50) })
527
696
  ] }),
528
- error && /* @__PURE__ */ jsx("p", { className: `${classPrefix}__error`, style: errorStyle, children: error }),
529
- field.help_text && !error && field.field_type !== "checkbox" && /* @__PURE__ */ jsx("p", { className: `${classPrefix}__help`, style: helpStyle, children: field.help_text })
697
+ error && /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: `${classPrefix}__error`, style: errorStyle, children: error }),
698
+ showsHelp && /* @__PURE__ */ jsx("p", { id: helpId, className: `${classPrefix}__help`, style: helpStyle, children: field.help_text })
530
699
  ] });
531
700
  }
532
701
 
@@ -1,4 +1,4 @@
1
1
  // src/shared/version.ts
2
- var SITE_KIT_VERSION = "7.1.2";
2
+ var SITE_KIT_VERSION = "7.3.0";
3
3
 
4
4
  export { SITE_KIT_VERSION };
@@ -1,5 +1,5 @@
1
1
  import { freshFetch } from './chunk-VX5CMNMM.js';
2
- import { LLM_GEO_CONTRACT_VERSION } from './chunk-4Y5FWDPM.js';
2
+ import { LLM_GEO_CONTRACT_VERSION } from './chunk-NZ4RXN3G.js';
3
3
  import { withSiteParam } from './chunk-MJP63SSS.js';
4
4
  import { cache } from 'react';
5
5
 
@@ -1,5 +1,5 @@
1
- import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-VDF5DFWT.js';
2
- import { SITE_KIT_VERSION } from './chunk-AH5Q262S.js';
1
+ import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-WGG6GTKW.js';
2
+ import { SITE_KIT_VERSION } from './chunk-56KNHB4U.js';
3
3
 
4
4
  // src/shared/fetchWithRetry.ts
5
5
  function backoffDelay(attempt, response) {
@@ -3,12 +3,48 @@ import { normalizeDesignTokens, designTokenCssVars, sanitizePopupHtml, isSafePop
3
3
  import { useId, useRef, useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
+ var DIALOG_FOCUSABLE = 'a[href],button:not([disabled]),input,select,textarea,[tabindex]:not([tabindex="-1"])';
7
+ function usePopupDialog(panelRef, { enabled = true, modal, onClose }) {
8
+ const onCloseRef = useRef(onClose);
9
+ useEffect(() => {
10
+ onCloseRef.current = onClose;
11
+ });
12
+ useEffect(() => {
13
+ if (!enabled) return;
14
+ const panel = panelRef.current;
15
+ const previous = document.activeElement;
16
+ if (modal && panel) panel.focus({ preventScroll: true });
17
+ const onKey = (e) => {
18
+ if (e.key === "Escape") {
19
+ onCloseRef.current?.();
20
+ return;
21
+ }
22
+ if (!modal || e.key !== "Tab" || !panel) return;
23
+ const items = Array.from(panel.querySelectorAll(DIALOG_FOCUSABLE));
24
+ if (!items.length) return;
25
+ const first = items[0];
26
+ const last = items[items.length - 1];
27
+ const active = document.activeElement;
28
+ if (e.shiftKey && (active === first || active === panel)) {
29
+ e.preventDefault();
30
+ last.focus();
31
+ } else if (!e.shiftKey && active === last) {
32
+ e.preventDefault();
33
+ first.focus();
34
+ }
35
+ };
36
+ document.addEventListener("keydown", onKey);
37
+ return () => {
38
+ document.removeEventListener("keydown", onKey);
39
+ if (modal && previous && typeof previous.focus === "function") previous.focus({ preventScroll: true });
40
+ };
41
+ }, [enabled, modal, panelRef]);
42
+ }
6
43
  var DEFAULT_POPUP_TOKENS = normalizeDesignTokens({
7
44
  colors: { background: "#ffffff", text: "#111827", primary: "#111827", muted: "#4b5563", border: "#e5e7eb" },
8
45
  fonts: { body: "inherit", heading: "inherit" },
9
46
  radius: { control: "8px", card: "16px" }
10
47
  });
11
- var FOCUSABLE = 'a[href],button:not([disabled]),input,select,textarea,[tabindex]:not([tabindex="-1"])';
12
48
  var v = (name) => `var(--sk-site-${name})`;
13
49
  function renderBlocks(blocks, headingId, placement, press) {
14
50
  const out = [];
@@ -153,36 +189,7 @@ function PopupBlocks({
153
189
  const hasHeading = blocks.some((b) => b.type === "heading");
154
190
  const t = tokens ?? DEFAULT_POPUP_TOKENS;
155
191
  const vars = designTokenCssVars(t);
156
- useEffect(() => {
157
- if (inline) return;
158
- const panel2 = panelRef.current;
159
- const previous = typeof document !== "undefined" ? document.activeElement : null;
160
- if (modal && panel2) panel2.focus({ preventScroll: true });
161
- const onKey = (e) => {
162
- if (e.key === "Escape") {
163
- onClose?.();
164
- return;
165
- }
166
- if (!modal || e.key !== "Tab" || !panel2) return;
167
- const items = Array.from(panel2.querySelectorAll(FOCUSABLE));
168
- if (!items.length) return;
169
- const first = items[0];
170
- const last = items[items.length - 1];
171
- const active = document.activeElement;
172
- if (e.shiftKey && (active === first || active === panel2)) {
173
- e.preventDefault();
174
- last.focus();
175
- } else if (!e.shiftKey && active === last) {
176
- e.preventDefault();
177
- first.focus();
178
- }
179
- };
180
- document.addEventListener("keydown", onKey);
181
- return () => {
182
- document.removeEventListener("keydown", onKey);
183
- if (modal && previous && typeof previous.focus === "function") previous.focus({ preventScroll: true });
184
- };
185
- }, [inline, modal, onClose]);
192
+ usePopupDialog(panelRef, { enabled: !inline, modal, onClose });
186
193
  const press = (block, index, e) => {
187
194
  if (onButton?.(block, index) === false || !isSafePopupUrl(block.url)) e.preventDefault();
188
195
  };
@@ -89,4 +89,83 @@ function isFieldComplete(field, values, isVisible = (f) => isFieldVisible(f, val
89
89
  return validateField(field, values, isVisible) === null;
90
90
  }
91
91
 
92
- export { isDisplayOnly, isEmptyValue, isFieldComplete, isFieldVisible, validateField };
92
+ // src/forms/form-dom-values.ts
93
+ function isUnreadable(field) {
94
+ return isDisplayOnly(field) || field.field_type === "file";
95
+ }
96
+ function controlsNamed(form, name) {
97
+ const out = [];
98
+ for (const el of Array.from(form.elements)) {
99
+ const control = el;
100
+ if (control.name === name && !control.disabled) out.push(control);
101
+ }
102
+ return out;
103
+ }
104
+ function isInput(el, type) {
105
+ return el.tagName === "INPUT" && el.type === type;
106
+ }
107
+ function isBlank(value) {
108
+ return isEmptyValue(value) || value === false || typeof value === "string" && value.trim() === "";
109
+ }
110
+ function readField(field, controls) {
111
+ switch (field.field_type) {
112
+ case "checkbox": {
113
+ const boxes = controls.filter((c) => isInput(c, "checkbox"));
114
+ if (boxes.length === 0) return void 0;
115
+ const isGroup = boxes.length > 1 || boxes[0].getAttribute("value") !== null;
116
+ return isGroup ? boxes.filter((b) => b.checked).map((b) => b.value) : boxes[0].checked;
117
+ }
118
+ case "radio": {
119
+ const chosen = controls.find((c) => isInput(c, "radio") && c.checked);
120
+ return chosen ? chosen.value : void 0;
121
+ }
122
+ case "rating": {
123
+ const chosen = controls.find((c) => isInput(c, "radio") && c.checked);
124
+ return chosen ? Number(chosen.value) : void 0;
125
+ }
126
+ case "multi-select": {
127
+ const select = controls.find((c) => c.tagName === "SELECT");
128
+ return select ? Array.from(select.selectedOptions, (o) => o.value) : void 0;
129
+ }
130
+ case "slider": {
131
+ const range = controls[0];
132
+ return range && range.value !== "" ? Number(range.value) : void 0;
133
+ }
134
+ default: {
135
+ const control = controls[0];
136
+ return control ? control.value : void 0;
137
+ }
138
+ }
139
+ }
140
+ function readFormControlValues(form, fields, honeypotName) {
141
+ const out = {};
142
+ if (!form || !fields) return out;
143
+ for (const field of fields) {
144
+ if (!field.slug || field.slug === honeypotName || isUnreadable(field)) continue;
145
+ const controls = controlsNamed(form, field.slug);
146
+ if (controls.length === 0) continue;
147
+ const value = readField(field, controls);
148
+ if (!isBlank(value)) out[field.slug] = value;
149
+ }
150
+ return out;
151
+ }
152
+ function shellValuesToCarry(form, fields, honeypotName) {
153
+ const values = readFormControlValues(form, fields, honeypotName);
154
+ for (const field of fields || []) {
155
+ const value = values[field.slug];
156
+ if (value === void 0) continue;
157
+ const fallback = field.default_value ?? "";
158
+ if (!Array.isArray(value) && String(value) === String(fallback)) delete values[field.slug];
159
+ }
160
+ return values;
161
+ }
162
+ function unseenControlValues(form, fields, honeypotName, state) {
163
+ const dom = readFormControlValues(form, fields, honeypotName);
164
+ const unseen = {};
165
+ for (const [slug, value] of Object.entries(dom)) {
166
+ if (isBlank(state[slug])) unseen[slug] = value;
167
+ }
168
+ return unseen;
169
+ }
170
+
171
+ export { isDisplayOnly, isEmptyValue, isFieldComplete, isFieldVisible, shellValuesToCarry, unseenControlValues, validateField };
@@ -54,7 +54,7 @@ function useSignal() {
54
54
  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
55
55
  }
56
56
  var LazySignalCore = dynamic(
57
- () => import('./SignalCore-JZNXOLNT.js').then((m) => ({ default: m.SignalCore })),
57
+ () => import('./SignalCore-2YP5FCAS.js').then((m) => ({ default: m.SignalCore })),
58
58
  { ssr: false }
59
59
  );
60
60
  function SignalBridge({
@@ -1,6 +1,6 @@
1
1
  import { resolveFetch } from './chunk-VX5CMNMM.js';
2
2
  import { monotonicMs } from './chunk-MH2DSGC6.js';
3
- import { SITE_KIT_VERSION } from './chunk-AH5Q262S.js';
3
+ import { SITE_KIT_VERSION } from './chunk-56KNHB4U.js';
4
4
  import 'server-only';
5
5
 
6
6
  var MINT_PATH = "/api/public/site-token";