@eshal-bot/chat-widget 0.2.10 → 0.2.12

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.
@@ -23851,6 +23851,51 @@
23851
23851
  };
23852
23852
  }
23853
23853
 
23854
+ /**
23855
+ * Undo `remark-breaks` inside list items (EV-3231).
23856
+ *
23857
+ * `remark-breaks` turns every single newline into a hard `<br>`, which is what
23858
+ * chat prose wants: a model that writes two lines means two lines, and without
23859
+ * it they would collapse into one paragraph.
23860
+ *
23861
+ * Inside a list item it is wrong. A soft wrap there is a continuation of the
23862
+ * same item, not a new line, and the model wraps its output whenever the item
23863
+ * is long. So:
23864
+ *
23865
+ * - **Silver Wedding Package**: Starting Rs 5,00,000 -
23866
+ * venue, basic decor, catering, DJ, photography
23867
+ *
23868
+ * rendered as `...5,00,000 -<br>venue, basic decor...`, forcing the
23869
+ * description onto its own line no matter how much width was available. In the
23870
+ * narrow widget the bolded name fills the first line and the bullet marker is
23871
+ * left looking stranded above the rest of the item.
23872
+ *
23873
+ * This is also why telling the agent to emit compact single-line bullets did
23874
+ * not help: the break is introduced at render time, from the model's own soft
23875
+ * wrapping, not from the text it intended.
23876
+ *
23877
+ * Replaces each `break` inside a list item with the "\n" text node remark
23878
+ * would have produced without remark-breaks, so HTML collapses it to a single
23879
+ * space and the item wraps to the available width. Prose outside lists keeps
23880
+ * its hard breaks.
23881
+ *
23882
+ * Mirrors packages/frontend/src/lib/ui/remarkSoftBreaksInLists.ts - the two
23883
+ * chat surfaces render the same agent output and must not disagree about it.
23884
+ */
23885
+ function remarkSoftBreaksInLists() {
23886
+ return tree => {
23887
+ visit(tree, "listItem", item => {
23888
+ visit(item, "break", (_node, index, parent) => {
23889
+ if (!parent || index === undefined) return;
23890
+ parent.children[index] = {
23891
+ type: "text",
23892
+ value: "\n"
23893
+ };
23894
+ });
23895
+ });
23896
+ };
23897
+ }
23898
+
23854
23899
  function _objectWithoutPropertiesLoose$l(r, e) {
23855
23900
  if (null == r) return {};
23856
23901
  var t = {};
@@ -89045,6 +89090,14 @@
89045
89090
  //
89046
89091
  // `time` is a new field kind (none of the three renderers had one before -
89047
89092
  // pickup/delivery slots had to be faked as a select).
89093
+ // Turn a form field key into a human label for the submitted-values message
89094
+ // ("date_time" -> "Date Time", "phoneNumber" -> "Phone Number"). Mirrors the
89095
+ // frontend's onFormSubmit transform (StreamingMarkdown.tsx) so a form submitted
89096
+ // from the widget produces the SAME text the backend parser sees from the
89097
+ // frontend surfaces.
89098
+ function _labelizeFieldKey(k) {
89099
+ return String(k).replace(/([a-z])([A-Z])/g, '$1 $2').replace(/[_-]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
89100
+ }
89048
89101
  function _validateFormField(field, value) {
89049
89102
  const isEmpty = value === undefined || value === null || typeof value === 'string' && value.trim() === '';
89050
89103
  if (field.required && isEmpty) return `${field.label} is required`;
@@ -89314,11 +89367,18 @@
89314
89367
  setErrors(next);
89315
89368
  if (firstError) return;
89316
89369
  setSubmitted(true);
89370
+ // Send the submitted fields as human-readable "Label: value" lines, NOT raw
89371
+ // JSON. A JSON.stringify(values) payload rendered as a customer-facing bubble
89372
+ // (e.g. {"phone":"+91...","date_time":"11am IST tomorrow"}) leaked internals
89373
+ // into the chat. This matches the frontend surfaces (preview / testing-lab /
89374
+ // inbox) byte-for-byte, and the backend's _submitted_form_data parser accepts
89375
+ // this readable format as well as JSON, so no backend change is needed. The
89376
+ // key -> Title Case transform mirrors StreamingMarkdown.tsx's onFormSubmit.
89317
89377
  let payload = '';
89318
89378
  try {
89319
- payload = JSON.stringify(values);
89379
+ payload = Object.entries(values).filter(([, v]) => v !== undefined && v !== null && String(v) !== '').map(([k, v]) => `${_labelizeFieldKey(k)}: ${v}`).join('\n') || 'Form submitted';
89320
89380
  } catch {
89321
- return;
89381
+ payload = 'Form submitted';
89322
89382
  }
89323
89383
  onButtonClick(payload, spec.title || 'Form');
89324
89384
  };
@@ -92047,7 +92107,7 @@
92047
92107
  // markdown soft break (rendered as a space) - keeps agent-authored
92048
92108
  // field-per-line summaries readable (EV-2699).
92049
92109
  ,
92050
- remarkPlugins: [remarkGfm, remarkBreaks]
92110
+ remarkPlugins: [remarkGfm, remarkBreaks, remarkSoftBreaksInLists]
92051
92111
  // Skip the rehypeCitations plugin when the org opted out -
92052
92112
  // markers then render as plain text so nothing squeaks
92053
92113
  // through as a placeholder pill.