@adoptai/genui-components 0.1.59 → 0.1.60

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
@@ -5563,7 +5563,14 @@ var decisionCardSchema = zod.z.object({
5563
5563
  zod.z.object({
5564
5564
  id: zod.z.string().optional(),
5565
5565
  label: zod.z.string(),
5566
- recommended: zod.z.boolean().optional()
5566
+ recommended: zod.z.boolean().optional(),
5567
+ value: zod.z.number().optional(),
5568
+ adjust: zod.z.object({
5569
+ min: zod.z.number(),
5570
+ max: zod.z.number(),
5571
+ step: zod.z.number().optional(),
5572
+ unit: zod.z.string().optional()
5573
+ }).optional()
5567
5574
  })
5568
5575
  ).min(1).max(5),
5569
5576
  source: zod.z.object({
@@ -5571,7 +5578,8 @@ var decisionCardSchema = zod.z.object({
5571
5578
  url: zod.z.string().optional()
5572
5579
  }).optional(),
5573
5580
  resolved: zod.z.object({
5574
- option: zod.z.string()
5581
+ option: zod.z.string(),
5582
+ value: zod.z.number().optional()
5575
5583
  }).optional()
5576
5584
  });
5577
5585
  var decisionCardTool = {
@@ -5614,13 +5622,28 @@ var decisionCardTool = {
5614
5622
  type: "array",
5615
5623
  minItems: 1,
5616
5624
  maxItems: 5,
5617
- description: "Mutually-exclusive resolution choices; mark one `recommended` to make it primary",
5625
+ description: "Mutually-exclusive resolution choices; mark one `recommended` to make it primary. An option that carries a numeric figure the user may want to tune (e.g. 'Book reserve' at 50 units) should set `value` (your suggested figure) and `adjust` ({min,max[,step,unit]}) \u2014 the card then lets the user fine-tune the number within that range before confirming.",
5618
5626
  items: {
5619
5627
  type: "object",
5620
5628
  properties: {
5621
5629
  id: { type: "string" },
5622
5630
  label: { type: "string" },
5623
- recommended: { type: "boolean" }
5631
+ recommended: { type: "boolean" },
5632
+ value: {
5633
+ type: "number",
5634
+ description: "Suggested numeric figure for this option (the starting point of the adjuster)"
5635
+ },
5636
+ adjust: {
5637
+ type: "object",
5638
+ description: "Allow the user to tune `value` within this inclusive range before resolving",
5639
+ properties: {
5640
+ min: { type: "number" },
5641
+ max: { type: "number" },
5642
+ step: { type: "number", description: "Increment granularity; defaults to a sensible step for the range" },
5643
+ unit: { type: "string", description: "Short unit suffix shown after the number, e.g. 'units', '%', 'hrs'" }
5644
+ },
5645
+ required: ["min", "max"]
5646
+ }
5624
5647
  },
5625
5648
  required: ["label"]
5626
5649
  }
@@ -5637,7 +5660,8 @@ var decisionCardTool = {
5637
5660
  type: "object",
5638
5661
  description: "Pre-resolved state for transcript replay",
5639
5662
  properties: {
5640
- option: { type: "string" }
5663
+ option: { type: "string" },
5664
+ value: { type: "number", description: "Adjusted figure the user confirmed, when the option was adjustable" }
5641
5665
  },
5642
5666
  required: ["option"]
5643
5667
  }
@@ -20079,8 +20103,15 @@ function useContainerWidth2(ref) {
20079
20103
  var KEYFRAMES2 = `
20080
20104
  @keyframes dcRise{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
20081
20105
  .dc-rise{animation:dcRise 0.28s cubic-bezier(0.22,1,0.36,1) both}
20106
+ .dc-range{-webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:9999px;outline:none;cursor:pointer;background:transparent}
20107
+ .dc-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;background:white;border:2px solid var(--dc-thumb,#ff5000);box-shadow:0 1px 3px rgba(0,0,0,0.18);cursor:grab;transition:transform 0.12s}
20108
+ .dc-range::-webkit-slider-thumb:hover{transform:scale(1.12)}
20109
+ .dc-range:active::-webkit-slider-thumb{cursor:grabbing}
20110
+ .dc-range::-moz-range-thumb{width:12px;height:12px;border-radius:50%;background:white;border:2px solid var(--dc-thumb,#ff5000);box-shadow:0 1px 3px rgba(0,0,0,0.18);cursor:grab}
20111
+ .dc-range::-moz-range-track{height:4px;border-radius:9999px;background:transparent}
20082
20112
  @media (prefers-reduced-motion: reduce){
20083
20113
  .dc-rise{animation:none !important;opacity:1 !important;transform:none !important}
20114
+ .dc-range::-webkit-slider-thumb{transition:none}
20084
20115
  }`;
20085
20116
  function SparkCheck({ size, color }) {
20086
20117
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -20126,17 +20157,239 @@ function FlagPill({ flag }) {
20126
20157
  }
20127
20158
  );
20128
20159
  }
20160
+ function formatFigure(value, unit) {
20161
+ const body = Number.isInteger(value) ? `${value}` : `${Math.round(value * 100) / 100}`;
20162
+ if (!unit) return body;
20163
+ return unit === "%" ? `${body}%` : `${body} ${unit}`;
20164
+ }
20165
+ function clampToRange(raw, adjust) {
20166
+ var _a2;
20167
+ const step = (_a2 = adjust.step) != null ? _a2 : Number.isInteger(adjust.min) && Number.isInteger(adjust.max) ? 1 : (adjust.max - adjust.min) / 100;
20168
+ const snapped = Math.round((raw - adjust.min) / step) * step + adjust.min;
20169
+ const fixed = Math.round(snapped * 1e6) / 1e6;
20170
+ return Math.min(adjust.max, Math.max(adjust.min, fixed));
20171
+ }
20172
+ function ValueAdjuster({
20173
+ option,
20174
+ accent,
20175
+ border,
20176
+ muted,
20177
+ onConfirm,
20178
+ onBack
20179
+ }) {
20180
+ var _a2, _b;
20181
+ const adjust = option.adjust;
20182
+ const suggested = clampToRange((_a2 = option.value) != null ? _a2 : adjust.min, adjust);
20183
+ const [value, setValue] = React45__default.default.useState(suggested);
20184
+ const [text, setText] = React45__default.default.useState(String(suggested));
20185
+ const step = (_b = adjust.step) != null ? _b : Number.isInteger(adjust.min) && Number.isInteger(adjust.max) ? 1 : (adjust.max - adjust.min) / 100;
20186
+ const pct = adjust.max > adjust.min ? (value - adjust.min) / (adjust.max - adjust.min) * 100 : 0;
20187
+ const suggestedPct = adjust.max > adjust.min ? (suggested - adjust.min) / (adjust.max - adjust.min) * 100 : 0;
20188
+ const moved = value !== suggested;
20189
+ const commit = (raw) => {
20190
+ const v = clampToRange(raw, adjust);
20191
+ setValue(v);
20192
+ setText(String(v));
20193
+ };
20194
+ return /* @__PURE__ */ jsxRuntime.jsxs(
20195
+ "div",
20196
+ {
20197
+ className: "dc-rise",
20198
+ "data-testid": "decision-card-adjuster",
20199
+ style: {
20200
+ display: "flex",
20201
+ flexDirection: "column",
20202
+ gap: 12,
20203
+ border: `1px solid ${border}`,
20204
+ borderRadius: 10,
20205
+ padding: "12px 14px",
20206
+ background: "#fafafa"
20207
+ },
20208
+ children: [
20209
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: 8 }, children: [
20210
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.06em", color: muted }, children: [
20211
+ "Adjust \xB7 ",
20212
+ option.label
20213
+ ] }),
20214
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 } }),
20215
+ /* @__PURE__ */ jsxRuntime.jsx(
20216
+ "button",
20217
+ {
20218
+ type: "button",
20219
+ onClick: onBack,
20220
+ "data-testid": "decision-card-adjust-back",
20221
+ style: { border: "none", background: "none", padding: 0, cursor: "pointer", fontSize: 12, fontWeight: 600, color: muted },
20222
+ children: "Back"
20223
+ }
20224
+ )
20225
+ ] }),
20226
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: 6 }, children: [
20227
+ /* @__PURE__ */ jsxRuntime.jsx(
20228
+ "input",
20229
+ {
20230
+ value: text,
20231
+ onChange: (e) => {
20232
+ setText(e.target.value);
20233
+ const n = Number(e.target.value);
20234
+ if (Number.isFinite(n)) setValue(clampToRange(n, adjust));
20235
+ },
20236
+ onBlur: () => commit(Number(text) || suggested),
20237
+ onKeyDown: (e) => {
20238
+ if (e.key === "Enter") {
20239
+ const v = clampToRange(Number(text) || suggested, adjust);
20240
+ commit(v);
20241
+ onConfirm(v);
20242
+ } else if (e.key === "ArrowUp") {
20243
+ e.preventDefault();
20244
+ commit(value + step);
20245
+ } else if (e.key === "ArrowDown") {
20246
+ e.preventDefault();
20247
+ commit(value - step);
20248
+ }
20249
+ },
20250
+ inputMode: "decimal",
20251
+ "aria-label": `${option.label} value`,
20252
+ "data-testid": "decision-card-adjust-input",
20253
+ style: {
20254
+ width: `${Math.max(3, String(text).length + 1)}ch`,
20255
+ fontSize: 26,
20256
+ fontWeight: 700,
20257
+ fontVariantNumeric: "tabular-nums",
20258
+ letterSpacing: "-0.02em",
20259
+ color: "var(--foreground)",
20260
+ border: "none",
20261
+ borderBottom: `2px solid ${accent}`,
20262
+ background: "transparent",
20263
+ outline: "none",
20264
+ padding: 0
20265
+ }
20266
+ }
20267
+ ),
20268
+ adjust.unit && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, fontWeight: 600, color: muted }, children: adjust.unit }),
20269
+ moved && /* @__PURE__ */ jsxRuntime.jsxs(
20270
+ "button",
20271
+ {
20272
+ type: "button",
20273
+ onClick: () => commit(suggested),
20274
+ "data-testid": "decision-card-adjust-reset",
20275
+ style: {
20276
+ marginLeft: 8,
20277
+ border: "none",
20278
+ background: "none",
20279
+ padding: 0,
20280
+ cursor: "pointer",
20281
+ fontSize: 11.5,
20282
+ fontWeight: 600,
20283
+ color: muted,
20284
+ textDecoration: "underline",
20285
+ textUnderlineOffset: 2
20286
+ },
20287
+ children: [
20288
+ "Reset to suggested (",
20289
+ formatFigure(suggested, adjust.unit),
20290
+ ")"
20291
+ ]
20292
+ }
20293
+ )
20294
+ ] }),
20295
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
20296
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", height: 16, display: "flex", alignItems: "center" }, children: [
20297
+ /* @__PURE__ */ jsxRuntime.jsx(
20298
+ "div",
20299
+ {
20300
+ "aria-hidden": "true",
20301
+ style: {
20302
+ position: "absolute",
20303
+ left: 0,
20304
+ right: 0,
20305
+ height: 4,
20306
+ borderRadius: 9999,
20307
+ background: `linear-gradient(to right, ${accent} ${pct}%, #e8e8e8 ${pct}%)`
20308
+ }
20309
+ }
20310
+ ),
20311
+ moved && /* @__PURE__ */ jsxRuntime.jsx(
20312
+ "div",
20313
+ {
20314
+ "aria-hidden": "true",
20315
+ title: `Suggested: ${formatFigure(suggested, adjust.unit)}`,
20316
+ style: {
20317
+ position: "absolute",
20318
+ left: `${suggestedPct}%`,
20319
+ transform: "translateX(-50%)",
20320
+ width: 2,
20321
+ height: 10,
20322
+ borderRadius: 1,
20323
+ background: muted,
20324
+ opacity: 0.55
20325
+ }
20326
+ }
20327
+ ),
20328
+ /* @__PURE__ */ jsxRuntime.jsx(
20329
+ "input",
20330
+ {
20331
+ type: "range",
20332
+ className: "dc-range",
20333
+ min: adjust.min,
20334
+ max: adjust.max,
20335
+ step,
20336
+ value,
20337
+ onChange: (e) => commit(Number(e.target.value)),
20338
+ "aria-label": `${option.label} slider`,
20339
+ "data-testid": "decision-card-adjust-slider",
20340
+ style: { position: "relative", ["--dc-thumb"]: accent }
20341
+ }
20342
+ )
20343
+ ] }),
20344
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 10.5, fontWeight: 600, color: muted, fontVariantNumeric: "tabular-nums" }, children: [
20345
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFigure(adjust.min, adjust.unit) }),
20346
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFigure(adjust.max, adjust.unit) })
20347
+ ] })
20348
+ ] }),
20349
+ /* @__PURE__ */ jsxRuntime.jsxs(
20350
+ "button",
20351
+ {
20352
+ type: "button",
20353
+ onClick: () => onConfirm(value),
20354
+ "data-testid": "decision-card-adjust-confirm",
20355
+ style: {
20356
+ alignSelf: "flex-start",
20357
+ border: `1px solid ${accent}`,
20358
+ background: accent,
20359
+ color: "white",
20360
+ borderRadius: 8,
20361
+ fontSize: 13,
20362
+ fontWeight: 600,
20363
+ padding: "9px 16px",
20364
+ cursor: "pointer",
20365
+ fontVariantNumeric: "tabular-nums",
20366
+ transition: "opacity 0.15s"
20367
+ },
20368
+ onMouseEnter: (e) => e.currentTarget.style.opacity = "0.88",
20369
+ onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
20370
+ children: [
20371
+ option.label,
20372
+ " \xB7 ",
20373
+ formatFigure(value, adjust.unit)
20374
+ ]
20375
+ }
20376
+ )
20377
+ ]
20378
+ }
20379
+ );
20380
+ }
20129
20381
  function DecisionCardRenderer({
20130
20382
  data,
20131
20383
  resolved = null,
20132
20384
  onResolve,
20133
20385
  onOpenSource
20134
20386
  }) {
20135
- var _a2, _b;
20387
+ var _a2, _b, _c;
20136
20388
  const { BORDER: BORDER4, MUTED: MUTED2, ACCENT: ACCENT2, ACCENT_SOFT: ACCENT_SOFT2 } = useTheme();
20137
20389
  const rootRef = React45__default.default.useRef(null);
20138
20390
  const width = useContainerWidth2(rootRef);
20139
20391
  const stacked = width > 0 && width < STACK_BELOW;
20392
+ const [adjustingIdx, setAdjustingIdx] = React45__default.default.useState(null);
20140
20393
  const options = (_a2 = data.options) != null ? _a2 : [];
20141
20394
  const recommendedIdx = Math.max(
20142
20395
  0,
@@ -20291,7 +20544,20 @@ function DecisionCardRenderer({
20291
20544
  ]
20292
20545
  }
20293
20546
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20294
- /* @__PURE__ */ jsxRuntime.jsx(
20547
+ adjustingIdx != null && ((_b = options[adjustingIdx]) == null ? void 0 : _b.adjust) ? /* @__PURE__ */ jsxRuntime.jsx(
20548
+ ValueAdjuster,
20549
+ {
20550
+ option: options[adjustingIdx],
20551
+ accent: ACCENT2,
20552
+ border: BORDER4,
20553
+ muted: MUTED2,
20554
+ onBack: () => setAdjustingIdx(null),
20555
+ onConfirm: (value) => {
20556
+ setAdjustingIdx(null);
20557
+ onResolve == null ? void 0 : onResolve(options[adjustingIdx].label, value);
20558
+ }
20559
+ }
20560
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
20295
20561
  "div",
20296
20562
  {
20297
20563
  style: {
@@ -20301,15 +20567,21 @@ function DecisionCardRenderer({
20301
20567
  gap: 8
20302
20568
  },
20303
20569
  children: options.map((opt, idx) => {
20304
- var _a3;
20570
+ var _a3, _b2;
20305
20571
  const primary = idx === recommendedIdx;
20306
- return /* @__PURE__ */ jsxRuntime.jsx(
20572
+ const adjustable = Boolean(opt.adjust);
20573
+ return /* @__PURE__ */ jsxRuntime.jsxs(
20307
20574
  "button",
20308
20575
  {
20309
20576
  type: "button",
20310
- onClick: () => onResolve == null ? void 0 : onResolve(opt.label),
20577
+ onClick: () => adjustable ? setAdjustingIdx(idx) : onResolve == null ? void 0 : onResolve(opt.label),
20578
+ "data-adjustable": adjustable || void 0,
20311
20579
  style: {
20312
20580
  width: stacked ? "100%" : "auto",
20581
+ display: "inline-flex",
20582
+ alignItems: "center",
20583
+ justifyContent: stacked ? "flex-start" : "center",
20584
+ gap: 7,
20313
20585
  textAlign: stacked ? "left" : "center",
20314
20586
  border: `1px solid ${primary ? ACCENT2 : BORDER4}`,
20315
20587
  background: primary ? ACCENT2 : "white",
@@ -20337,7 +20609,28 @@ function DecisionCardRenderer({
20337
20609
  e.currentTarget.style.background = "white";
20338
20610
  }
20339
20611
  },
20340
- children: opt.label
20612
+ children: [
20613
+ opt.label,
20614
+ adjustable && typeof opt.value === "number" && /* @__PURE__ */ jsxRuntime.jsxs(
20615
+ "span",
20616
+ {
20617
+ style: {
20618
+ fontSize: 11.5,
20619
+ fontWeight: 700,
20620
+ fontVariantNumeric: "tabular-nums",
20621
+ padding: "1px 7px",
20622
+ borderRadius: 9999,
20623
+ background: primary ? "rgba(255,255,255,0.22)" : "#f2f2f2",
20624
+ color: primary ? "white" : MUTED2,
20625
+ lineHeight: 1.5
20626
+ },
20627
+ children: [
20628
+ formatFigure(opt.value, (_b2 = opt.adjust) == null ? void 0 : _b2.unit),
20629
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { marginLeft: 4, opacity: 0.8 }, children: "\u270E" })
20630
+ ]
20631
+ }
20632
+ )
20633
+ ]
20341
20634
  },
20342
20635
  (_a3 = opt.id) != null ? _a3 : opt.label
20343
20636
  );
@@ -20376,7 +20669,7 @@ function DecisionCardRenderer({
20376
20669
  strokeLinejoin: "round"
20377
20670
  }
20378
20671
  ) }),
20379
- (_b = data.source.label) != null ? _b : "View source for this figure"
20672
+ (_c = data.source.label) != null ? _c : "View source for this figure"
20380
20673
  ]
20381
20674
  }
20382
20675
  )
@@ -20385,20 +20678,27 @@ function DecisionCardRenderer({
20385
20678
  }
20386
20679
  );
20387
20680
  }
20681
+ function composeResolution(p, option, value) {
20682
+ var _a2, _b, _c;
20683
+ if (value == null) return option;
20684
+ const unit = (_c = (_b = ((_a2 = p.options) != null ? _a2 : []).find((o) => o.label === option)) == null ? void 0 : _b.adjust) == null ? void 0 : _c.unit;
20685
+ return `${option} \xB7 ${formatFigure(value, unit)}`;
20686
+ }
20388
20687
  function DecisionCardResolver(p) {
20389
- var _a2, _b, _c, _d;
20688
+ var _a2, _b;
20390
20689
  const { resolvedDecisions, onDecisionResolve, onDecisionSource } = useGenUIInteraction();
20391
20690
  const decisionId = (_a2 = p.id) != null ? _a2 : p.title;
20392
20691
  const hostResolved = resolvedDecisions == null ? void 0 : resolvedDecisions[decisionId];
20393
- const initial = (_c = hostResolved != null ? hostResolved : (_b = p.resolved) == null ? void 0 : _b.option) != null ? _c : null;
20692
+ const initial = hostResolved != null ? hostResolved : p.resolved ? composeResolution(p, p.resolved.option, p.resolved.value) : null;
20394
20693
  const [localResolved, setLocalResolved] = React45__default.default.useState(initial);
20395
20694
  React45__default.default.useEffect(() => {
20396
20695
  if (hostResolved !== void 0) setLocalResolved(hostResolved);
20397
20696
  }, [hostResolved]);
20398
20697
  const resolved = hostResolved != null ? hostResolved : localResolved;
20399
- const handleResolve = (option) => {
20400
- setLocalResolved(option);
20401
- onDecisionResolve == null ? void 0 : onDecisionResolve(decisionId, option);
20698
+ const handleResolve = (option, value) => {
20699
+ const resolution = composeResolution(p, option, value);
20700
+ setLocalResolved(resolution);
20701
+ onDecisionResolve == null ? void 0 : onDecisionResolve(decisionId, resolution);
20402
20702
  };
20403
20703
  const handleSource = () => {
20404
20704
  var _a3;
@@ -20407,7 +20707,7 @@ function DecisionCardResolver(p) {
20407
20707
  window.open(p.source.url, "_blank", "noopener,noreferrer");
20408
20708
  }
20409
20709
  };
20410
- return /* @__PURE__ */ jsxRuntime.jsx(ComponentActions, { filename: (_d = p.title) != null ? _d : "decision-card", children: /* @__PURE__ */ jsxRuntime.jsx(
20710
+ return /* @__PURE__ */ jsxRuntime.jsx(ComponentActions, { filename: (_b = p.title) != null ? _b : "decision-card", children: /* @__PURE__ */ jsxRuntime.jsx(
20411
20711
  DecisionCardRenderer,
20412
20712
  {
20413
20713
  data: p,
@@ -22204,7 +22504,9 @@ function BlockForm({
22204
22504
  onEntityCreate,
22205
22505
  hideActions,
22206
22506
  dense,
22207
- variant = "form"
22507
+ variant = "form",
22508
+ fieldSuggestions,
22509
+ onApplySuggestion
22208
22510
  }) {
22209
22511
  var _a2;
22210
22512
  const t = useTheme();
@@ -22235,20 +22537,85 @@ function BlockForm({
22235
22537
  }
22236
22538
  ),
22237
22539
  ((_a2 = block.context) == null ? void 0 : _a2.type) && /* @__PURE__ */ jsxRuntime.jsx(ContextSlot, { payload: block.context }),
22238
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: dense ? "8px" : isEscalation ? "10px" : "12px" }, children: (block.fields || []).map((field) => /* @__PURE__ */ jsxRuntime.jsx("div", { "data-field-key": fieldKey(block.id, field.name), children: /* @__PURE__ */ jsxRuntime.jsx(
22239
- FieldRenderer,
22240
- {
22241
- field,
22242
- value: state.getValue(block.id, field.name),
22243
- onChange: (v) => state.setFieldValue(block.id, field.name, v),
22244
- disabled,
22245
- error: state.getError(block.id, field.name),
22246
- dense,
22247
- onFileUpload,
22248
- onEntitySearch,
22249
- onEntityCreate
22250
- }
22251
- ) }, `${block.id}:${field.name}`)) }),
22540
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: dense ? "8px" : isEscalation ? "10px" : "12px" }, children: (block.fields || []).map((field) => {
22541
+ var _a3;
22542
+ const suggestion = (fieldSuggestions || []).filter((sg) => {
22543
+ var _a4;
22544
+ return sg.field === field.name && ((_a4 = sg.block_id) != null ? _a4 : block.id) === block.id;
22545
+ }).slice(-1)[0];
22546
+ const current = state.getValue(block.id, field.name);
22547
+ const showSuggestion = suggestion != null && current !== suggestion.value;
22548
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-field-key": fieldKey(block.id, field.name), children: [
22549
+ /* @__PURE__ */ jsxRuntime.jsx(
22550
+ FieldRenderer,
22551
+ {
22552
+ field,
22553
+ value: current,
22554
+ onChange: (v) => state.setFieldValue(block.id, field.name, v),
22555
+ disabled,
22556
+ error: state.getError(block.id, field.name),
22557
+ dense,
22558
+ onFileUpload,
22559
+ onEntitySearch,
22560
+ onEntityCreate
22561
+ }
22562
+ ),
22563
+ showSuggestion && !disabled ? /* @__PURE__ */ jsxRuntime.jsxs(
22564
+ "div",
22565
+ {
22566
+ "data-testid": `builder-suggestion-${field.name}`,
22567
+ style: {
22568
+ display: "flex",
22569
+ alignItems: "center",
22570
+ flexWrap: "wrap",
22571
+ gap: "6px",
22572
+ marginTop: "5px",
22573
+ padding: "5px 9px",
22574
+ borderRadius: "8px",
22575
+ border: `1px dashed ${t.BORDER}`,
22576
+ background: "#fafafa",
22577
+ fontSize: "11.5px",
22578
+ lineHeight: 1.4
22579
+ },
22580
+ children: [
22581
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { color: t.ACCENT, fontSize: "11px" }, children: "\u2726" }),
22582
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: t.MUTED, fontWeight: 600 }, children: [
22583
+ "Suggested:",
22584
+ " ",
22585
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--foreground)", fontVariantNumeric: "tabular-nums" }, children: (_a3 = suggestion.label) != null ? _a3 : String(suggestion.value) })
22586
+ ] }),
22587
+ suggestion.note ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: t.MUTED }, children: [
22588
+ "\xB7 ",
22589
+ suggestion.note
22590
+ ] }) : null,
22591
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 } }),
22592
+ /* @__PURE__ */ jsxRuntime.jsx(
22593
+ "button",
22594
+ {
22595
+ type: "button",
22596
+ "data-testid": `builder-suggestion-apply-${field.name}`,
22597
+ onClick: () => {
22598
+ state.setFieldValue(block.id, field.name, suggestion.value);
22599
+ onApplySuggestion == null ? void 0 : onApplySuggestion(suggestion);
22600
+ },
22601
+ style: {
22602
+ font: "inherit",
22603
+ fontSize: "11.5px",
22604
+ fontWeight: 700,
22605
+ color: t.ACCENT,
22606
+ background: "transparent",
22607
+ border: "none",
22608
+ padding: 0,
22609
+ cursor: "pointer"
22610
+ },
22611
+ children: "Apply"
22612
+ }
22613
+ )
22614
+ ]
22615
+ }
22616
+ ) : null
22617
+ ] }, `${block.id}:${field.name}`);
22618
+ }) }),
22252
22619
  hideActions ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "6px", paddingTop: isEscalation ? "2px" : "4px" }, children: [
22253
22620
  errorCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "11px", fontWeight: 600, color: "#dc2626" }, children: [
22254
22621
  errorCount,
@@ -22536,7 +22903,9 @@ function BuilderFormResolver({
22536
22903
  submitRef,
22537
22904
  hideActions,
22538
22905
  dense,
22539
- onValidationError
22906
+ onValidationError,
22907
+ fieldSuggestions,
22908
+ onApplySuggestion
22540
22909
  }) {
22541
22910
  var _a2;
22542
22911
  const state = useBuilderState(builder.blocks);
@@ -22613,7 +22982,9 @@ function BuilderFormResolver({
22613
22982
  onEntitySearch,
22614
22983
  onEntityCreate,
22615
22984
  hideActions,
22616
- dense
22985
+ dense,
22986
+ fieldSuggestions,
22987
+ onApplySuggestion
22617
22988
  }
22618
22989
  );
22619
22990
  default:
@@ -22630,7 +23001,9 @@ function BuilderFormResolver({
22630
23001
  onEntitySearch,
22631
23002
  onEntityCreate,
22632
23003
  dense,
22633
- hideActions
23004
+ hideActions,
23005
+ fieldSuggestions,
23006
+ onApplySuggestion
22634
23007
  }
22635
23008
  );
22636
23009
  }