@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.
@@ -1,6 +1,7 @@
1
1
  import type { BuilderPayload } from "./schemas";
2
2
  import type { BuilderState } from "./hooks";
3
3
  import type { FileUploadResult, EntitySearch, EntityCreate } from "./fields";
4
+ import type { FieldSuggestion } from "./BuilderForm";
4
5
  /** Single-block builder presentation. Two cosmetic variants of the SAME form:
5
6
  * - "escalation": compact, accent left-rail, no title (the host/dock owns it),
6
7
  * outlined "Continue" CTA, no in-card cancel. A high-urgency interruption
@@ -26,6 +27,9 @@ export interface BlockFormProps {
26
27
  dense?: boolean;
27
28
  /** Cosmetic variant. Defaults to "form". */
28
29
  variant?: BlockFormVariant;
30
+ /** Agent-proposed values rendered as Apply chips under matching fields. */
31
+ fieldSuggestions?: FieldSuggestion[];
32
+ onApplySuggestion?: (suggestion: FieldSuggestion) => void;
29
33
  }
30
- export declare function BlockForm({ builder, state, onSubmit, onCancel, disabled, onFileUpload, onEntitySearch, onEntityCreate, hideActions, dense, variant, }: BlockFormProps): import("react/jsx-runtime").JSX.Element | null;
34
+ export declare function BlockForm({ builder, state, onSubmit, onCancel, disabled, onFileUpload, onEntitySearch, onEntityCreate, hideActions, dense, variant, fieldSuggestions, onApplySuggestion, }: BlockFormProps): import("react/jsx-runtime").JSX.Element | null;
31
35
  //# sourceMappingURL=BlockForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlockForm.d.ts","sourceRoot":"","sources":["../../src/builders/BlockForm.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7E;;;;;;;qFAOqF;AACrF,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACzD,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;0EACsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,cAAc,EACd,WAAW,EACX,KAAK,EACL,OAAgB,GACjB,EAAE,cAAc,kDA6FhB"}
1
+ {"version":3,"file":"BlockForm.d.ts","sourceRoot":"","sources":["../../src/builders/BlockForm.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;;qFAOqF;AACrF,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACzD,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;0EACsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,cAAc,EACd,WAAW,EACX,KAAK,EACL,OAAgB,EAChB,gBAAgB,EAChB,iBAAiB,GAClB,EAAE,cAAc,kDAyJhB"}
@@ -16,6 +16,21 @@ export interface BuilderSubmission {
16
16
  }>;
17
17
  values?: Record<string, unknown>;
18
18
  }
19
+ /** An agent-proposed value for one field (e.g. surfaced from an escalation
20
+ * discussion thread). Rendered as a "Suggested: X — Apply" chip under the
21
+ * matching field; Apply writes the value into the draft, where the user can
22
+ * still edit it freely before submitting. */
23
+ export interface FieldSuggestion {
24
+ /** Field name the suggestion targets. */
25
+ field: string;
26
+ /** Block id when the builder has several; defaults to the first block. */
27
+ block_id?: string;
28
+ value: unknown;
29
+ /** Display override for the value (e.g. "$6.69M" for 6692000). */
30
+ label?: string;
31
+ /** Short provenance note, e.g. "verified against sheet 4 · D47". */
32
+ note?: string;
33
+ }
19
34
  export interface BuilderFormProps {
20
35
  builder: BuilderPayload;
21
36
  onSubmit: (submission: BuilderSubmission) => void;
@@ -43,6 +58,12 @@ export interface BuilderFormProps {
43
58
  * the failing fields. Lets the host (dock) scroll to + focus the offending
44
59
  * field and show a summary instead of the submit silently doing nothing. */
45
60
  onValidationError?: (failure: ValidationFailure) => void;
61
+ /** Agent-proposed field values (see {@link FieldSuggestion}). Honoured by
62
+ * the form/escalation presentations; a suggestion whose field/block doesn't
63
+ * exist is silently ignored. */
64
+ fieldSuggestions?: FieldSuggestion[];
65
+ /** Fired when the user applies a suggestion (after the draft is updated). */
66
+ onApplySuggestion?: (suggestion: FieldSuggestion) => void;
46
67
  }
47
- export declare function BuilderFormResolver({ builder, onSubmit, onCancel, disabled, onFileUpload, onEntitySearch, onEntityCreate, onChange, submitRef, hideActions, dense, onValidationError, }: BuilderFormProps): import("react/jsx-runtime").JSX.Element;
68
+ export declare function BuilderFormResolver({ builder, onSubmit, onCancel, disabled, onFileUpload, onEntitySearch, onEntityCreate, onChange, submitRef, hideActions, dense, onValidationError, fieldSuggestions, onApplySuggestion, }: BuilderFormProps): import("react/jsx-runtime").JSX.Element;
48
69
  //# sourceMappingURL=BuilderForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BuilderForm.d.ts","sourceRoot":"","sources":["../../src/builders/BuilderForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAI9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7E;;;kDAGkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IAChD,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,CAAC,UAAU,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACzD,yEAAyE;IACzE,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;;qDAEiD;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C;;uDAEmD;IACnD,SAAS,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD;6EACyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;oDACgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;iFAE6E;IAC7E,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC1D;AAED,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,cAAc,EACd,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAK,EACL,iBAAiB,GAClB,EAAE,gBAAgB,2CAwHlB"}
1
+ {"version":3,"file":"BuilderForm.d.ts","sourceRoot":"","sources":["../../src/builders/BuilderForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAI9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7E;;;kDAGkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IAChD,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;6CAG6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,CAAC,UAAU,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACzD,yEAAyE;IACzE,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;;qDAEiD;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C;;uDAEmD;IACnD,SAAS,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD;6EACyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;oDACgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;iFAE6E;IAC7E,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACzD;;qCAEiC;IACjC,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,cAAc,EACd,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAK,EACL,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,EAAE,gBAAgB,2CA4HlB"}
@@ -2,7 +2,7 @@ export { builderSchema, builderBlockSchema, builderFieldSchema, builderFieldOpti
2
2
  export type { BuilderPayload, BuilderBlock, BuilderField, BuilderFieldType, BuilderFieldOption, EntityOption, EntityCreateField, FileMapConfig, FileMapCategory, FileMapFile, FileMapValue, } from "./schemas";
3
3
  export { validateBuilderPayload } from "./validateBuilder";
4
4
  export { BuilderFormResolver } from "./BuilderForm";
5
- export type { BuilderFormProps, BuilderSubmission } from "./BuilderForm";
5
+ export type { BuilderFormProps, BuilderSubmission, FieldSuggestion } from "./BuilderForm";
6
6
  export { BuilderRecap } from "./BuilderRecap";
7
7
  export type { BuilderRecapProps } from "./BuilderRecap";
8
8
  export { BlockForm } from "./BlockForm";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builders/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,EAC5B,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,YAAY,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builders/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,EAC5B,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,YAAY,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
@@ -289,8 +289,15 @@ function useContainerWidth(ref) {
289
289
  var KEYFRAMES = `
290
290
  @keyframes dcRise{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
291
291
  .dc-rise{animation:dcRise 0.28s cubic-bezier(0.22,1,0.36,1) both}
292
+ .dc-range{-webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:9999px;outline:none;cursor:pointer;background:transparent}
293
+ .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}
294
+ .dc-range::-webkit-slider-thumb:hover{transform:scale(1.12)}
295
+ .dc-range:active::-webkit-slider-thumb{cursor:grabbing}
296
+ .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}
297
+ .dc-range::-moz-range-track{height:4px;border-radius:9999px;background:transparent}
292
298
  @media (prefers-reduced-motion: reduce){
293
299
  .dc-rise{animation:none !important;opacity:1 !important;transform:none !important}
300
+ .dc-range::-webkit-slider-thumb{transition:none}
294
301
  }`;
295
302
  function SparkCheck({ size, color }) {
296
303
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -336,17 +343,239 @@ function FlagPill({ flag }) {
336
343
  }
337
344
  );
338
345
  }
346
+ function formatFigure(value, unit) {
347
+ const body = Number.isInteger(value) ? `${value}` : `${Math.round(value * 100) / 100}`;
348
+ if (!unit) return body;
349
+ return unit === "%" ? `${body}%` : `${body} ${unit}`;
350
+ }
351
+ function clampToRange(raw, adjust) {
352
+ var _a;
353
+ const step = (_a = adjust.step) != null ? _a : Number.isInteger(adjust.min) && Number.isInteger(adjust.max) ? 1 : (adjust.max - adjust.min) / 100;
354
+ const snapped = Math.round((raw - adjust.min) / step) * step + adjust.min;
355
+ const fixed = Math.round(snapped * 1e6) / 1e6;
356
+ return Math.min(adjust.max, Math.max(adjust.min, fixed));
357
+ }
358
+ function ValueAdjuster({
359
+ option,
360
+ accent,
361
+ border,
362
+ muted,
363
+ onConfirm,
364
+ onBack
365
+ }) {
366
+ var _a, _b;
367
+ const adjust = option.adjust;
368
+ const suggested = clampToRange((_a = option.value) != null ? _a : adjust.min, adjust);
369
+ const [value, setValue] = React4__default.default.useState(suggested);
370
+ const [text, setText] = React4__default.default.useState(String(suggested));
371
+ const step = (_b = adjust.step) != null ? _b : Number.isInteger(adjust.min) && Number.isInteger(adjust.max) ? 1 : (adjust.max - adjust.min) / 100;
372
+ const pct = adjust.max > adjust.min ? (value - adjust.min) / (adjust.max - adjust.min) * 100 : 0;
373
+ const suggestedPct = adjust.max > adjust.min ? (suggested - adjust.min) / (adjust.max - adjust.min) * 100 : 0;
374
+ const moved = value !== suggested;
375
+ const commit = (raw) => {
376
+ const v = clampToRange(raw, adjust);
377
+ setValue(v);
378
+ setText(String(v));
379
+ };
380
+ return /* @__PURE__ */ jsxRuntime.jsxs(
381
+ "div",
382
+ {
383
+ className: "dc-rise",
384
+ "data-testid": "decision-card-adjuster",
385
+ style: {
386
+ display: "flex",
387
+ flexDirection: "column",
388
+ gap: 12,
389
+ border: `1px solid ${border}`,
390
+ borderRadius: 10,
391
+ padding: "12px 14px",
392
+ background: "#fafafa"
393
+ },
394
+ children: [
395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: 8 }, children: [
396
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.06em", color: muted }, children: [
397
+ "Adjust \xB7 ",
398
+ option.label
399
+ ] }),
400
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 } }),
401
+ /* @__PURE__ */ jsxRuntime.jsx(
402
+ "button",
403
+ {
404
+ type: "button",
405
+ onClick: onBack,
406
+ "data-testid": "decision-card-adjust-back",
407
+ style: { border: "none", background: "none", padding: 0, cursor: "pointer", fontSize: 12, fontWeight: 600, color: muted },
408
+ children: "Back"
409
+ }
410
+ )
411
+ ] }),
412
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: 6 }, children: [
413
+ /* @__PURE__ */ jsxRuntime.jsx(
414
+ "input",
415
+ {
416
+ value: text,
417
+ onChange: (e) => {
418
+ setText(e.target.value);
419
+ const n = Number(e.target.value);
420
+ if (Number.isFinite(n)) setValue(clampToRange(n, adjust));
421
+ },
422
+ onBlur: () => commit(Number(text) || suggested),
423
+ onKeyDown: (e) => {
424
+ if (e.key === "Enter") {
425
+ const v = clampToRange(Number(text) || suggested, adjust);
426
+ commit(v);
427
+ onConfirm(v);
428
+ } else if (e.key === "ArrowUp") {
429
+ e.preventDefault();
430
+ commit(value + step);
431
+ } else if (e.key === "ArrowDown") {
432
+ e.preventDefault();
433
+ commit(value - step);
434
+ }
435
+ },
436
+ inputMode: "decimal",
437
+ "aria-label": `${option.label} value`,
438
+ "data-testid": "decision-card-adjust-input",
439
+ style: {
440
+ width: `${Math.max(3, String(text).length + 1)}ch`,
441
+ fontSize: 26,
442
+ fontWeight: 700,
443
+ fontVariantNumeric: "tabular-nums",
444
+ letterSpacing: "-0.02em",
445
+ color: "var(--foreground)",
446
+ border: "none",
447
+ borderBottom: `2px solid ${accent}`,
448
+ background: "transparent",
449
+ outline: "none",
450
+ padding: 0
451
+ }
452
+ }
453
+ ),
454
+ adjust.unit && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, fontWeight: 600, color: muted }, children: adjust.unit }),
455
+ moved && /* @__PURE__ */ jsxRuntime.jsxs(
456
+ "button",
457
+ {
458
+ type: "button",
459
+ onClick: () => commit(suggested),
460
+ "data-testid": "decision-card-adjust-reset",
461
+ style: {
462
+ marginLeft: 8,
463
+ border: "none",
464
+ background: "none",
465
+ padding: 0,
466
+ cursor: "pointer",
467
+ fontSize: 11.5,
468
+ fontWeight: 600,
469
+ color: muted,
470
+ textDecoration: "underline",
471
+ textUnderlineOffset: 2
472
+ },
473
+ children: [
474
+ "Reset to suggested (",
475
+ formatFigure(suggested, adjust.unit),
476
+ ")"
477
+ ]
478
+ }
479
+ )
480
+ ] }),
481
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
482
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", height: 16, display: "flex", alignItems: "center" }, children: [
483
+ /* @__PURE__ */ jsxRuntime.jsx(
484
+ "div",
485
+ {
486
+ "aria-hidden": "true",
487
+ style: {
488
+ position: "absolute",
489
+ left: 0,
490
+ right: 0,
491
+ height: 4,
492
+ borderRadius: 9999,
493
+ background: `linear-gradient(to right, ${accent} ${pct}%, #e8e8e8 ${pct}%)`
494
+ }
495
+ }
496
+ ),
497
+ moved && /* @__PURE__ */ jsxRuntime.jsx(
498
+ "div",
499
+ {
500
+ "aria-hidden": "true",
501
+ title: `Suggested: ${formatFigure(suggested, adjust.unit)}`,
502
+ style: {
503
+ position: "absolute",
504
+ left: `${suggestedPct}%`,
505
+ transform: "translateX(-50%)",
506
+ width: 2,
507
+ height: 10,
508
+ borderRadius: 1,
509
+ background: muted,
510
+ opacity: 0.55
511
+ }
512
+ }
513
+ ),
514
+ /* @__PURE__ */ jsxRuntime.jsx(
515
+ "input",
516
+ {
517
+ type: "range",
518
+ className: "dc-range",
519
+ min: adjust.min,
520
+ max: adjust.max,
521
+ step,
522
+ value,
523
+ onChange: (e) => commit(Number(e.target.value)),
524
+ "aria-label": `${option.label} slider`,
525
+ "data-testid": "decision-card-adjust-slider",
526
+ style: { position: "relative", ["--dc-thumb"]: accent }
527
+ }
528
+ )
529
+ ] }),
530
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 10.5, fontWeight: 600, color: muted, fontVariantNumeric: "tabular-nums" }, children: [
531
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFigure(adjust.min, adjust.unit) }),
532
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFigure(adjust.max, adjust.unit) })
533
+ ] })
534
+ ] }),
535
+ /* @__PURE__ */ jsxRuntime.jsxs(
536
+ "button",
537
+ {
538
+ type: "button",
539
+ onClick: () => onConfirm(value),
540
+ "data-testid": "decision-card-adjust-confirm",
541
+ style: {
542
+ alignSelf: "flex-start",
543
+ border: `1px solid ${accent}`,
544
+ background: accent,
545
+ color: "white",
546
+ borderRadius: 8,
547
+ fontSize: 13,
548
+ fontWeight: 600,
549
+ padding: "9px 16px",
550
+ cursor: "pointer",
551
+ fontVariantNumeric: "tabular-nums",
552
+ transition: "opacity 0.15s"
553
+ },
554
+ onMouseEnter: (e) => e.currentTarget.style.opacity = "0.88",
555
+ onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
556
+ children: [
557
+ option.label,
558
+ " \xB7 ",
559
+ formatFigure(value, adjust.unit)
560
+ ]
561
+ }
562
+ )
563
+ ]
564
+ }
565
+ );
566
+ }
339
567
  function DecisionCardRenderer({
340
568
  data,
341
569
  resolved = null,
342
570
  onResolve,
343
571
  onOpenSource
344
572
  }) {
345
- var _a, _b;
573
+ var _a, _b, _c;
346
574
  const { BORDER: BORDER2, MUTED: MUTED2, ACCENT: ACCENT2, ACCENT_SOFT: ACCENT_SOFT2 } = useTheme();
347
575
  const rootRef = React4__default.default.useRef(null);
348
576
  const width = useContainerWidth(rootRef);
349
577
  const stacked = width > 0 && width < STACK_BELOW;
578
+ const [adjustingIdx, setAdjustingIdx] = React4__default.default.useState(null);
350
579
  const options = (_a = data.options) != null ? _a : [];
351
580
  const recommendedIdx = Math.max(
352
581
  0,
@@ -501,7 +730,20 @@ function DecisionCardRenderer({
501
730
  ]
502
731
  }
503
732
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
504
- /* @__PURE__ */ jsxRuntime.jsx(
733
+ adjustingIdx != null && ((_b = options[adjustingIdx]) == null ? void 0 : _b.adjust) ? /* @__PURE__ */ jsxRuntime.jsx(
734
+ ValueAdjuster,
735
+ {
736
+ option: options[adjustingIdx],
737
+ accent: ACCENT2,
738
+ border: BORDER2,
739
+ muted: MUTED2,
740
+ onBack: () => setAdjustingIdx(null),
741
+ onConfirm: (value) => {
742
+ setAdjustingIdx(null);
743
+ onResolve == null ? void 0 : onResolve(options[adjustingIdx].label, value);
744
+ }
745
+ }
746
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
505
747
  "div",
506
748
  {
507
749
  style: {
@@ -511,15 +753,21 @@ function DecisionCardRenderer({
511
753
  gap: 8
512
754
  },
513
755
  children: options.map((opt, idx) => {
514
- var _a2;
756
+ var _a2, _b2;
515
757
  const primary = idx === recommendedIdx;
516
- return /* @__PURE__ */ jsxRuntime.jsx(
758
+ const adjustable = Boolean(opt.adjust);
759
+ return /* @__PURE__ */ jsxRuntime.jsxs(
517
760
  "button",
518
761
  {
519
762
  type: "button",
520
- onClick: () => onResolve == null ? void 0 : onResolve(opt.label),
763
+ onClick: () => adjustable ? setAdjustingIdx(idx) : onResolve == null ? void 0 : onResolve(opt.label),
764
+ "data-adjustable": adjustable || void 0,
521
765
  style: {
522
766
  width: stacked ? "100%" : "auto",
767
+ display: "inline-flex",
768
+ alignItems: "center",
769
+ justifyContent: stacked ? "flex-start" : "center",
770
+ gap: 7,
523
771
  textAlign: stacked ? "left" : "center",
524
772
  border: `1px solid ${primary ? ACCENT2 : BORDER2}`,
525
773
  background: primary ? ACCENT2 : "white",
@@ -547,7 +795,28 @@ function DecisionCardRenderer({
547
795
  e.currentTarget.style.background = "white";
548
796
  }
549
797
  },
550
- children: opt.label
798
+ children: [
799
+ opt.label,
800
+ adjustable && typeof opt.value === "number" && /* @__PURE__ */ jsxRuntime.jsxs(
801
+ "span",
802
+ {
803
+ style: {
804
+ fontSize: 11.5,
805
+ fontWeight: 700,
806
+ fontVariantNumeric: "tabular-nums",
807
+ padding: "1px 7px",
808
+ borderRadius: 9999,
809
+ background: primary ? "rgba(255,255,255,0.22)" : "#f2f2f2",
810
+ color: primary ? "white" : MUTED2,
811
+ lineHeight: 1.5
812
+ },
813
+ children: [
814
+ formatFigure(opt.value, (_b2 = opt.adjust) == null ? void 0 : _b2.unit),
815
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { marginLeft: 4, opacity: 0.8 }, children: "\u270E" })
816
+ ]
817
+ }
818
+ )
819
+ ]
551
820
  },
552
821
  (_a2 = opt.id) != null ? _a2 : opt.label
553
822
  );
@@ -586,7 +855,7 @@ function DecisionCardRenderer({
586
855
  strokeLinejoin: "round"
587
856
  }
588
857
  ) }),
589
- (_b = data.source.label) != null ? _b : "View source for this figure"
858
+ (_c = data.source.label) != null ? _c : "View source for this figure"
590
859
  ]
591
860
  }
592
861
  )
@@ -595,20 +864,27 @@ function DecisionCardRenderer({
595
864
  }
596
865
  );
597
866
  }
867
+ function composeResolution(p, option, value) {
868
+ var _a, _b, _c;
869
+ if (value == null) return option;
870
+ const unit = (_c = (_b = ((_a = p.options) != null ? _a : []).find((o) => o.label === option)) == null ? void 0 : _b.adjust) == null ? void 0 : _c.unit;
871
+ return `${option} \xB7 ${formatFigure(value, unit)}`;
872
+ }
598
873
  function DecisionCardResolver(p) {
599
- var _a, _b, _c, _d;
874
+ var _a, _b;
600
875
  const { resolvedDecisions, onDecisionResolve, onDecisionSource } = useGenUIInteraction();
601
876
  const decisionId = (_a = p.id) != null ? _a : p.title;
602
877
  const hostResolved = resolvedDecisions == null ? void 0 : resolvedDecisions[decisionId];
603
- const initial = (_c = hostResolved != null ? hostResolved : (_b = p.resolved) == null ? void 0 : _b.option) != null ? _c : null;
878
+ const initial = hostResolved != null ? hostResolved : p.resolved ? composeResolution(p, p.resolved.option, p.resolved.value) : null;
604
879
  const [localResolved, setLocalResolved] = React4__default.default.useState(initial);
605
880
  React4__default.default.useEffect(() => {
606
881
  if (hostResolved !== void 0) setLocalResolved(hostResolved);
607
882
  }, [hostResolved]);
608
883
  const resolved = hostResolved != null ? hostResolved : localResolved;
609
- const handleResolve = (option) => {
610
- setLocalResolved(option);
611
- onDecisionResolve == null ? void 0 : onDecisionResolve(decisionId, option);
884
+ const handleResolve = (option, value) => {
885
+ const resolution = composeResolution(p, option, value);
886
+ setLocalResolved(resolution);
887
+ onDecisionResolve == null ? void 0 : onDecisionResolve(decisionId, resolution);
612
888
  };
613
889
  const handleSource = () => {
614
890
  var _a2;
@@ -617,7 +893,7 @@ function DecisionCardResolver(p) {
617
893
  window.open(p.source.url, "_blank", "noopener,noreferrer");
618
894
  }
619
895
  };
620
- return /* @__PURE__ */ jsxRuntime.jsx(ComponentActions, { filename: (_d = p.title) != null ? _d : "decision-card", children: /* @__PURE__ */ jsxRuntime.jsx(
896
+ return /* @__PURE__ */ jsxRuntime.jsx(ComponentActions, { filename: (_b = p.title) != null ? _b : "decision-card", children: /* @__PURE__ */ jsxRuntime.jsx(
621
897
  DecisionCardRenderer,
622
898
  {
623
899
  data: p,