@xinghunm/ai-chat 0.4.0 → 1.0.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.
package/dist/index.js CHANGED
@@ -78,10 +78,18 @@ var DEFAULT_AI_CHAT_LABELS = {
78
78
  attachmentLimitNotice: "Images exceeded the limit. Only the first 10 images were kept.",
79
79
  userRoleLabel: "User",
80
80
  assistantRoleLabel: "Assistant",
81
+ expandMessageAriaLabel: "Expand message",
82
+ collapseMessageAriaLabel: "Collapse message",
83
+ expandComposerAriaLabel: "Expand composer",
84
+ collapseComposerAriaLabel: "Collapse composer",
81
85
  stoppedResponse: "Response stopped",
82
86
  assistantStreamingAriaLabel: "assistant streaming",
83
87
  networkError: "Network request failed. Please try again.",
84
- genericError: "Something went wrong. Please try again."
88
+ genericError: "Something went wrong. Please try again.",
89
+ questionnaireSubmitting: "Submitting...",
90
+ questionnaireSubmitted: "Selection submitted. Waiting for the plan to continue...",
91
+ questionnaireValidationPrefix: "Please complete:",
92
+ questionnaireSubmitFailed: "Failed to submit. Please try again."
85
93
  };
86
94
 
87
95
  // src/store/chat-store.ts
@@ -97,6 +105,24 @@ var resolveSessionTitleFromMessage = (message) => {
97
105
  }
98
106
  return DEFAULT_CHAT_SESSION_TITLE;
99
107
  };
108
+ var mergeStreamingBlocks = (existingBlocks, incomingBlocks) => {
109
+ const nextBlocks = [...existingBlocks ?? []];
110
+ incomingBlocks.forEach((incomingBlock) => {
111
+ if (incomingBlock.type !== "questionnaire") {
112
+ nextBlocks.push(incomingBlock);
113
+ return;
114
+ }
115
+ const existingIndex = nextBlocks.findIndex(
116
+ (block) => block.type === "questionnaire" && block.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId
117
+ );
118
+ if (existingIndex === -1) {
119
+ nextBlocks.push(incomingBlock);
120
+ return;
121
+ }
122
+ nextBlocks[existingIndex] = incomingBlock;
123
+ });
124
+ return nextBlocks;
125
+ };
100
126
  var finalizeStreamingMessage = (state, sessionId, status, clearError = false) => {
101
127
  const message = state.streamingMessageBySession[sessionId];
102
128
  const hasRenderableMessagePayload = Boolean(
@@ -286,10 +312,15 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
286
312
  const target = state.streamingMessageBySession[sessionId];
287
313
  if (!target)
288
314
  return;
315
+ const nextBlocks = patch.blocks !== void 0 ? mergeStreamingBlocks(target.blocks, patch.blocks) : target.blocks;
289
316
  set({
290
317
  streamingMessageBySession: {
291
318
  ...state.streamingMessageBySession,
292
- [sessionId]: { ...target, ...patch }
319
+ [sessionId]: {
320
+ ...target,
321
+ ...patch,
322
+ ...patch.blocks !== void 0 ? { blocks: nextBlocks } : {}
323
+ }
293
324
  }
294
325
  });
295
326
  },
@@ -509,9 +540,27 @@ var DEFAULT_CHAT_TRANSPORT_ENDPOINTS = {
509
540
  completions: "/chat/completions",
510
541
  terminate: "/chat/terminate"
511
542
  };
543
+ var createToolExecutionHeaders = (policy) => {
544
+ if (!policy?.enabled) {
545
+ return {};
546
+ }
547
+ return {
548
+ "X-Tool-Approval-Required": String(Boolean(policy.approvalRequired)),
549
+ ...typeof policy.approvalTimeoutSec === "number" ? { "X-Tool-Approval-Timeout": String(policy.approvalTimeoutSec) } : {}
550
+ };
551
+ };
552
+ var createModeDefaultHeaders = (mode) => {
553
+ if (mode === "ask" || mode === "plan") {
554
+ return {
555
+ "X-Tool-Approval-Required": "false"
556
+ };
557
+ }
558
+ return {};
559
+ };
512
560
  var createDefaultChatTransport = ({
513
561
  apiBaseUrl,
514
562
  authToken,
563
+ toolExecutionPolicy,
515
564
  streamHeaders,
516
565
  transformStreamPacket,
517
566
  endpoints,
@@ -522,6 +571,10 @@ var createDefaultChatTransport = ({
522
571
  ...DEFAULT_CHAT_TRANSPORT_ENDPOINTS,
523
572
  ...endpoints
524
573
  };
574
+ const resolvedStreamHeaders = {
575
+ ...createToolExecutionHeaders(toolExecutionPolicy),
576
+ ...streamHeaders
577
+ };
525
578
  return {
526
579
  getModels: () => getChatModels(client, resolvedEndpoints.models),
527
580
  startStream: async ({
@@ -535,12 +588,16 @@ var createDefaultChatTransport = ({
535
588
  onDone,
536
589
  onError
537
590
  }) => {
591
+ const requestHeaders = {
592
+ ...createModeDefaultHeaders(mode),
593
+ ...resolvedStreamHeaders
594
+ };
538
595
  await startChatStream({
539
596
  apiBaseUrl,
540
597
  endpointPath: resolvedEndpoints.completions,
541
598
  sessionId,
542
599
  authToken,
543
- requestHeaders: streamHeaders,
600
+ requestHeaders,
544
601
  model,
545
602
  mode,
546
603
  content,
@@ -569,6 +626,8 @@ var AiChatProvider = (props) => {
569
626
  defaultMode,
570
627
  labels,
571
628
  renderMessageBlock,
629
+ handleQuestionnaireSubmit,
630
+ handleConfirmationSubmit,
572
631
  messageRenderOrder,
573
632
  enableImageAttachments = true,
574
633
  children
@@ -624,6 +683,8 @@ var AiChatProvider = (props) => {
624
683
  sendRef,
625
684
  retryRef,
626
685
  renderMessageBlock,
686
+ handleQuestionnaireSubmit,
687
+ handleConfirmationSubmit,
627
688
  messageRenderOrder,
628
689
  transformStreamPacket: defaultTransformStreamPacket,
629
690
  enableImageAttachments
@@ -634,6 +695,8 @@ var AiChatProvider = (props) => {
634
695
  defaultAuthToken,
635
696
  defaultTransformStreamPacket,
636
697
  enableImageAttachments,
698
+ handleConfirmationSubmit,
699
+ handleQuestionnaireSubmit,
637
700
  labels,
638
701
  messageRenderOrder,
639
702
  renderMessageBlock,
@@ -943,7 +1006,7 @@ var getTimelineBlockKey = (block, index) => {
943
1006
  case "confirmation_card":
944
1007
  return `${index}:confirmation_card:${block.proposal.proposalId}`;
945
1008
  case "result_summary":
946
- return `${index}:result_summary:${block.summary.taskId}:${block.summary.status}`;
1009
+ return `${index}:result_summary:${block.summary.summaryId}:${block.summary.status}`;
947
1010
  case "questionnaire":
948
1011
  return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
949
1012
  case "custom":
@@ -1235,21 +1298,21 @@ var useTimelineBlockAnchors = ({
1235
1298
  };
1236
1299
  };
1237
1300
 
1238
- // src/components/chat-thread/components/pde-ai-execution-confirmation-card.tsx
1301
+ // src/components/chat-thread/components/execution-confirmation-card.tsx
1239
1302
  var import_styled = __toESM(require("@emotion/styled"));
1240
1303
  var import_jsx_runtime2 = require("@emotion/react/jsx-runtime");
1241
- var PDEAIExecutionConfirmationCard = ({
1304
+ var ExecutionConfirmationCard = ({
1242
1305
  proposal,
1243
1306
  interactive = false,
1244
1307
  onApply,
1245
1308
  onConfirm,
1246
1309
  onRevise
1247
1310
  }) => {
1248
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { "data-testid": "pde-ai-execution-confirmation-card", children: [
1311
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { "data-testid": "execution-confirmation-card", children: [
1249
1312
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Header, { children: [
1250
1313
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Eyebrow, { children: "Execution Proposal" }),
1251
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Title, { children: proposal.equationName }),
1252
- proposal.solverName ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Subtitle, { children: proposal.solverName }) : null
1314
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Title, { children: proposal.resourceName }),
1315
+ proposal.executorName ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Subtitle, { children: proposal.executorName }) : null
1253
1316
  ] }),
1254
1317
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SummaryList, { children: proposal.parameterSummary.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(SummaryItem, { children: [
1255
1318
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SummaryLabel, { children: item.label }),
@@ -1257,21 +1320,13 @@ var PDEAIExecutionConfirmationCard = ({
1257
1320
  ] }, `${item.fieldPath ?? item.label}-${item.value}`)) }),
1258
1321
  proposal.warnings?.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Warnings, { children: proposal.warnings.map((warning) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Warning, { children: warning }, warning)) }) : null,
1259
1322
  interactive ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Actions, { children: [
1260
- onApply && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "pde-ai-confirmation-apply", onClick: onApply, children: "Apply to Parameters" }),
1261
- onConfirm && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1262
- ActionButton,
1263
- {
1264
- type: "button",
1265
- "data-testid": "pde-ai-confirmation-confirm",
1266
- onClick: onConfirm,
1267
- children: "Confirm Execution"
1268
- }
1269
- ),
1323
+ onApply && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "confirmation-apply", onClick: onApply, children: "Apply to Parameters" }),
1324
+ onConfirm && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "confirmation-confirm", onClick: onConfirm, children: "Confirm Execution" }),
1270
1325
  onRevise && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1271
1326
  SecondaryActionButton,
1272
1327
  {
1273
1328
  type: "button",
1274
- "data-testid": "pde-ai-confirmation-revise",
1329
+ "data-testid": "confirmation-revise",
1275
1330
  onClick: onRevise,
1276
1331
  children: "Revise Plan"
1277
1332
  }
@@ -1368,10 +1423,10 @@ var SecondaryActionButton = (0, import_styled.default)(ActionButton)`
1368
1423
  border: 1px solid rgba(255, 255, 255, 0.14);
1369
1424
  `;
1370
1425
 
1371
- // src/components/chat-thread/components/pde-ai-notice-card.tsx
1426
+ // src/components/chat-thread/components/notice-card.tsx
1372
1427
  var import_styled2 = __toESM(require("@emotion/styled"));
1373
1428
  var import_jsx_runtime3 = require("@emotion/react/jsx-runtime");
1374
- var PDEAINoticeCard = ({ text, tone }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Card2, { "data-testid": "pde-ai-notice-card", "data-tone": tone, children: text });
1429
+ var NoticeCard = ({ text, tone }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Card2, { "data-testid": "notice-card", "data-tone": tone, children: text });
1375
1430
  var Card2 = import_styled2.default.div`
1376
1431
  padding: 12px 14px;
1377
1432
  border-radius: 16px;
@@ -1397,10 +1452,10 @@ var Card2 = import_styled2.default.div`
1397
1452
  }
1398
1453
  `;
1399
1454
 
1400
- // src/components/chat-thread/components/pde-ai-parameter-summary-card.tsx
1455
+ // src/components/chat-thread/components/parameter-summary-card.tsx
1401
1456
  var import_styled3 = __toESM(require("@emotion/styled"));
1402
1457
  var import_jsx_runtime4 = require("@emotion/react/jsx-runtime");
1403
- var PDEAIParameterSummaryCard = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Card3, { "data-testid": "pde-ai-parameter-summary-card", children: [
1458
+ var ParameterSummaryCard = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Card3, { "data-testid": "parameter-summary-card", children: [
1404
1459
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Title2, { children: "Parameter Summary" }),
1405
1460
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(List, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ListItem, { children: [
1406
1461
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Label, { children: item.label }),
@@ -1444,11 +1499,17 @@ var Value = import_styled3.default.span`
1444
1499
  text-align: right;
1445
1500
  `;
1446
1501
 
1447
- // src/components/chat-thread/components/pde-ai-questionnaire-card.tsx
1502
+ // src/components/chat-thread/components/questionnaire-card.tsx
1448
1503
  var import_react7 = require("react");
1449
1504
  var import_styled4 = __toESM(require("@emotion/styled"));
1450
1505
  var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
1451
1506
  var OTHER_OPTION_VALUE = "__other__";
1507
+ var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
1508
+ submitting: "Submitting...",
1509
+ submitted: "Selection submitted. Waiting for the plan to continue...",
1510
+ validationPrefix: "Please complete:",
1511
+ submitFailed: "Failed to submit. Please try again."
1512
+ };
1452
1513
  var createInitialAnswers = (questionnaire) => ({
1453
1514
  ...questionnaire.answers ?? {}
1454
1515
  });
@@ -1542,26 +1603,40 @@ var normalizeQuestionAnswer = (question, answer) => {
1542
1603
  return answer;
1543
1604
  }
1544
1605
  };
1545
- var PDEAIQuestionnaireCardInner = ({
1606
+ var QuestionnaireCardInner = ({
1546
1607
  questionnaire,
1547
1608
  interactive = false,
1548
- onSubmit
1609
+ onSubmit,
1610
+ labels
1549
1611
  }) => {
1550
1612
  const [answers, setAnswers] = (0, import_react7.useState)(
1551
1613
  () => createInitialAnswers(questionnaire)
1552
1614
  );
1553
1615
  const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
1554
- const handleSubmit = () => {
1616
+ const [isSubmitting, setIsSubmitting] = (0, import_react7.useState)(false);
1617
+ const [isSubmitted, setIsSubmitted] = (0, import_react7.useState)(false);
1618
+ const resolvedLabels = {
1619
+ ...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
1620
+ ...labels
1621
+ };
1622
+ const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
1623
+ const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
1624
+ const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
1625
+ const handleSubmit = async () => {
1626
+ if (isSubmitting || isSubmitted) {
1627
+ return;
1628
+ }
1555
1629
  const missingQuestions = questionnaire.questions.filter(
1556
1630
  (question) => question.required && isMissingRequiredAnswer(question, answers)
1557
1631
  );
1558
1632
  if (missingQuestions.length > 0) {
1559
1633
  setErrorMessage(
1560
- `Please complete: ${missingQuestions.map((question) => question.label).join(", ")}`
1634
+ `${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
1561
1635
  );
1562
1636
  return;
1563
1637
  }
1564
1638
  setErrorMessage(null);
1639
+ setIsSubmitting(true);
1565
1640
  const normalizedAnswers = Object.fromEntries(
1566
1641
  questionnaire.questions.flatMap((question) => {
1567
1642
  const value = normalizeQuestionAnswer(question, answers[question.id]);
@@ -1578,11 +1653,18 @@ var PDEAIQuestionnaireCardInner = ({
1578
1653
  return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
1579
1654
  })
1580
1655
  ];
1581
- onSubmit?.({
1582
- questionnaireId: questionnaire.questionnaireId,
1583
- answers: normalizedAnswers,
1584
- content: contentLines.join("\n")
1585
- });
1656
+ try {
1657
+ await onSubmit?.({
1658
+ questionnaireId: questionnaire.questionnaireId,
1659
+ answers: normalizedAnswers,
1660
+ content: contentLines.join("\n")
1661
+ });
1662
+ setIsSubmitted(true);
1663
+ } catch (error) {
1664
+ setErrorMessage(error instanceof Error ? error.message : resolvedLabels.submitFailed);
1665
+ } finally {
1666
+ setIsSubmitting(false);
1667
+ }
1586
1668
  };
1587
1669
  const renderQuestion = (question) => {
1588
1670
  const renderOptionChoice = ({
@@ -1597,13 +1679,13 @@ var PDEAIQuestionnaireCardInner = ({
1597
1679
  OptionChoiceItem,
1598
1680
  {
1599
1681
  role: "button",
1600
- tabIndex: interactive ? 0 : -1,
1682
+ tabIndex: isInteractionLocked ? -1 : 0,
1601
1683
  "aria-pressed": isSelected,
1602
1684
  "data-selected": isSelected,
1603
1685
  "data-tone": tone,
1604
- "data-testid": `pde-ai-question-option-${questionId}-${index}`,
1686
+ "data-testid": `question-option-${questionId}-${index}`,
1605
1687
  onClick: (event) => {
1606
- if (!interactive) {
1688
+ if (isInteractionLocked) {
1607
1689
  return;
1608
1690
  }
1609
1691
  if (event.target instanceof HTMLElement && event.target.closest("input")) {
@@ -1612,7 +1694,7 @@ var PDEAIQuestionnaireCardInner = ({
1612
1694
  onClick();
1613
1695
  },
1614
1696
  onKeyDown: (event) => {
1615
- if (!interactive) {
1697
+ if (isInteractionLocked) {
1616
1698
  return;
1617
1699
  }
1618
1700
  if (event.key !== "Enter" && event.key !== " ") {
@@ -1671,11 +1753,11 @@ var PDEAIQuestionnaireCardInner = ({
1671
1753
  inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1672
1754
  InlineOtherInput,
1673
1755
  {
1674
- "data-testid": `pde-ai-question-input-${question.id}`,
1756
+ "data-testid": `question-input-${question.id}`,
1675
1757
  type: "text",
1676
1758
  value: singleSelectDraft.otherValue,
1677
1759
  placeholder: "Other",
1678
- readOnly: !interactive,
1760
+ readOnly: isInteractionLocked,
1679
1761
  onClick: (event) => {
1680
1762
  event.stopPropagation();
1681
1763
  },
@@ -1696,11 +1778,11 @@ var PDEAIQuestionnaireCardInner = ({
1696
1778
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1697
1779
  TextInput,
1698
1780
  {
1699
- "data-testid": `pde-ai-question-input-${question.id}`,
1781
+ "data-testid": `question-input-${question.id}`,
1700
1782
  type: "text",
1701
1783
  value: getTextInputValue(answers[question.id]),
1702
1784
  placeholder: question.placeholder,
1703
- readOnly: !interactive,
1785
+ readOnly: isInteractionLocked,
1704
1786
  onChange: (event) => {
1705
1787
  setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
1706
1788
  }
@@ -1711,11 +1793,11 @@ var PDEAIQuestionnaireCardInner = ({
1711
1793
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1712
1794
  TextInput,
1713
1795
  {
1714
- "data-testid": `pde-ai-question-input-${question.id}`,
1796
+ "data-testid": `question-input-${question.id}`,
1715
1797
  type: "number",
1716
1798
  value: getNumberInputValue(answers[question.id]),
1717
1799
  placeholder: question.placeholder,
1718
- readOnly: !interactive,
1800
+ readOnly: isInteractionLocked,
1719
1801
  onChange: (event) => {
1720
1802
  setAnswers(
1721
1803
  (current) => updateAnswerValue(
@@ -1750,7 +1832,7 @@ var PDEAIQuestionnaireCardInner = ({
1750
1832
  return null;
1751
1833
  }
1752
1834
  };
1753
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "pde-ai-questionnaire-card", children: [
1835
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "questionnaire-card", children: [
1754
1836
  questionnaire.title ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Title3, { children: questionnaire.title }) : null,
1755
1837
  questionnaire.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Description, { children: questionnaire.description }) : null,
1756
1838
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionCard, { children: [
@@ -1760,24 +1842,28 @@ var PDEAIQuestionnaireCardInner = ({
1760
1842
  ] }),
1761
1843
  renderQuestion(question)
1762
1844
  ] }, question.id)) }),
1763
- errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "pde-ai-questionnaire-error", children: errorMessage }) : null,
1764
- interactive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1845
+ visibleErrorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
1846
+ isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1765
1847
  SubmitButton,
1766
1848
  {
1767
1849
  type: "button",
1768
- "data-testid": "pde-ai-questionnaire-submit",
1769
- onClick: handleSubmit,
1770
- children: questionnaire.submitLabel ?? "Submit"
1850
+ "data-testid": "questionnaire-submit",
1851
+ disabled: isInteractionLocked,
1852
+ onClick: () => {
1853
+ void handleSubmit();
1854
+ },
1855
+ children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
1771
1856
  }
1772
1857
  ) : null
1773
1858
  ] });
1774
1859
  };
1775
1860
  var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
1776
1861
  questionnaire.questionnaireId,
1777
- questionnaire.answers ?? {},
1778
- questionnaire.questions
1862
+ questionnaire.questions,
1863
+ questionnaire.status,
1864
+ questionnaire.statusMessage
1779
1865
  ]);
1780
- var PDEAIQuestionnaireCard = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PDEAIQuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
1866
+ var QuestionnaireCard = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
1781
1867
  var Card4 = import_styled4.default.section`
1782
1868
  display: grid;
1783
1869
  gap: 14px;
@@ -1925,6 +2011,10 @@ var ErrorMessage = import_styled4.default.div`
1925
2011
  color: rgba(255, 145, 145, 0.96);
1926
2012
  font-size: 12px;
1927
2013
  `;
2014
+ var SuccessMessage = import_styled4.default.div`
2015
+ color: rgba(164, 255, 210, 0.96);
2016
+ font-size: 12px;
2017
+ `;
1928
2018
  var SubmitButton = import_styled4.default.button`
1929
2019
  justify-self: flex-start;
1930
2020
  border: none;
@@ -1935,12 +2025,17 @@ var SubmitButton = import_styled4.default.button`
1935
2025
  font-weight: 700;
1936
2026
  padding: 10px 14px;
1937
2027
  cursor: pointer;
2028
+
2029
+ &:disabled {
2030
+ cursor: default;
2031
+ opacity: 0.72;
2032
+ }
1938
2033
  `;
1939
2034
 
1940
- // src/components/chat-thread/components/pde-ai-result-summary-card.tsx
2035
+ // src/components/chat-thread/components/result-summary-card.tsx
1941
2036
  var import_styled5 = __toESM(require("@emotion/styled"));
1942
2037
  var import_jsx_runtime6 = require("@emotion/react/jsx-runtime");
1943
- var PDEAIResultSummaryCard = ({ summary }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card5, { "data-testid": "pde-ai-result-summary-card", "data-status": summary.status, children: [
2038
+ var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
1944
2039
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Eyebrow2, { children: summary.status }),
1945
2040
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Headline, { children: summary.headline }),
1946
2041
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Details, { children: summary.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Detail, { children: detail }, detail)) })
@@ -2036,6 +2131,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
2036
2131
  var import_jsx_runtime8 = require("@emotion/react/jsx-runtime");
2037
2132
  var MARKDOWN_REMARK_PLUGINS = [import_remark_gfm.default, import_remark_math.default];
2038
2133
  var MARKDOWN_REHYPE_PLUGINS = [import_rehype_katex.default];
2134
+ var USER_MESSAGE_COLLAPSE_HEIGHT_PX = 120;
2039
2135
  var MARKDOWN_COMPONENTS = {
2040
2136
  table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { ...props }) })
2041
2137
  };
@@ -2048,10 +2144,101 @@ var renderMarkdownContent = (content) => /* @__PURE__ */ (0, import_jsx_runtime8
2048
2144
  children: content
2049
2145
  }
2050
2146
  );
2147
+ var renderPlainTextContent = (content) => content;
2148
+ var CollapseIcon = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2149
+ "svg",
2150
+ {
2151
+ "aria-hidden": "true",
2152
+ width: "16",
2153
+ height: "16",
2154
+ viewBox: "0 0 16 16",
2155
+ fill: "none",
2156
+ xmlns: "http://www.w3.org/2000/svg",
2157
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2158
+ "path",
2159
+ {
2160
+ d: "M4 6l4 4 4-4",
2161
+ stroke: "currentColor",
2162
+ strokeWidth: "1.6",
2163
+ strokeLinecap: "round",
2164
+ strokeLinejoin: "round",
2165
+ transform: expanded ? "rotate(180 8 8)" : void 0
2166
+ }
2167
+ )
2168
+ }
2169
+ );
2170
+ var useUserMessageCollapse = ({
2171
+ blocks,
2172
+ displayedBlocks,
2173
+ displayedContent,
2174
+ enabled,
2175
+ freshContent,
2176
+ settledContent
2177
+ }) => {
2178
+ const [isCollapsible, setIsCollapsible] = (0, import_react9.useState)(false);
2179
+ const [isExpanded, setIsExpanded] = (0, import_react9.useState)(false);
2180
+ const [bodyStackElement, setBodyStackElement] = (0, import_react9.useState)(null);
2181
+ const syncCollapseState = (0, import_react9.useCallback)(
2182
+ (element) => {
2183
+ const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
2184
+ setIsCollapsible(nextCollapsible);
2185
+ if (!nextCollapsible) {
2186
+ setIsExpanded(false);
2187
+ }
2188
+ },
2189
+ [enabled]
2190
+ );
2191
+ const bodyStackRef = (0, import_react9.useCallback)(
2192
+ (node) => {
2193
+ setBodyStackElement(node);
2194
+ syncCollapseState(node);
2195
+ },
2196
+ [syncCollapseState]
2197
+ );
2198
+ (0, import_react9.useLayoutEffect)(() => {
2199
+ if (!bodyStackElement) {
2200
+ return;
2201
+ }
2202
+ const frameId = requestAnimationFrame(() => {
2203
+ syncCollapseState(bodyStackElement);
2204
+ });
2205
+ return () => {
2206
+ cancelAnimationFrame(frameId);
2207
+ };
2208
+ }, [
2209
+ blocks,
2210
+ bodyStackElement,
2211
+ displayedBlocks,
2212
+ displayedContent,
2213
+ enabled,
2214
+ freshContent,
2215
+ settledContent,
2216
+ syncCollapseState
2217
+ ]);
2218
+ (0, import_react9.useLayoutEffect)(() => {
2219
+ if (!bodyStackElement || !enabled || typeof ResizeObserver === "undefined") {
2220
+ return;
2221
+ }
2222
+ const observer = new ResizeObserver(() => {
2223
+ syncCollapseState(bodyStackElement);
2224
+ });
2225
+ observer.observe(bodyStackElement);
2226
+ return () => {
2227
+ observer.disconnect();
2228
+ };
2229
+ }, [bodyStackElement, enabled, syncCollapseState]);
2230
+ return {
2231
+ bodyStackRef,
2232
+ isCollapsed: isCollapsible && !isExpanded,
2233
+ isCollapsible,
2234
+ isExpanded,
2235
+ toggleExpanded: () => setIsExpanded((current) => !current)
2236
+ };
2237
+ };
2051
2238
  var createExecutionConfirmationContent = (proposal) => [
2052
2239
  "Execution confirmed",
2053
- `- Equation: ${proposal.equationName}`,
2054
- ...proposal.solverName ? [`- Solver: ${proposal.solverName}`] : [],
2240
+ `- Equation: ${proposal.resourceName}`,
2241
+ ...proposal.executorName ? [`- Solver: ${proposal.executorName}`] : [],
2055
2242
  `- Proposal ID: ${proposal.proposalId}`
2056
2243
  ].join("\n");
2057
2244
  var areChatAttachmentsEqual = (previousAttachments, nextAttachments) => {
@@ -2073,10 +2260,10 @@ var areParameterSummaryItemsEqual = (previousItems, nextItems) => previousItems.
2073
2260
  const nextItem = nextItems[index];
2074
2261
  return item.label === nextItem?.label && item.value === nextItem.value && item.fieldPath === nextItem.fieldPath;
2075
2262
  });
2076
- var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.equationKey === nextProposal.equationKey && previousProposal.equationName === nextProposal.equationName && previousProposal.solverName === nextProposal.solverName && previousProposal.requiresConfirmation === nextProposal.requiresConfirmation && areParameterSummaryItemsEqual(previousProposal.parameterSummary, nextProposal.parameterSummary) && (previousProposal.warnings ?? []).length === (nextProposal.warnings ?? []).length && (previousProposal.warnings ?? []).every(
2263
+ var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.resourceKey === nextProposal.resourceKey && previousProposal.resourceName === nextProposal.resourceName && previousProposal.executorName === nextProposal.executorName && previousProposal.requiresConfirmation === nextProposal.requiresConfirmation && areParameterSummaryItemsEqual(previousProposal.parameterSummary, nextProposal.parameterSummary) && (previousProposal.warnings ?? []).length === (nextProposal.warnings ?? []).length && (previousProposal.warnings ?? []).every(
2077
2264
  (warning, index) => warning === nextProposal.warnings?.[index]
2078
2265
  );
2079
- var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.taskId === nextSummary.taskId && previousSummary.status === nextSummary.status && previousSummary.headline === nextSummary.headline && previousSummary.details.length === nextSummary.details.length && previousSummary.details.every((detail, index) => detail === nextSummary.details[index]);
2266
+ var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.summaryId === nextSummary.summaryId && previousSummary.status === nextSummary.status && previousSummary.headline === nextSummary.headline && previousSummary.details.length === nextSummary.details.length && previousSummary.details.every((detail, index) => detail === nextSummary.details[index]);
2080
2267
  var areStringArraysEqual = (previousValues, nextValues) => previousValues.length === nextValues.length && previousValues.every((value, index) => value === nextValues[index]);
2081
2268
  var areQuestionAnswersEqual = (previousAnswer, nextAnswer) => {
2082
2269
  if (Array.isArray(previousAnswer) || Array.isArray(nextAnswer)) {
@@ -2117,7 +2304,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
2117
2304
  return false;
2118
2305
  }
2119
2306
  };
2120
- var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.questions.length === nextQuestionnaire.questions.length && previousQuestionnaire.questions.every(
2307
+ var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.status === nextQuestionnaire.status && previousQuestionnaire.statusMessage === nextQuestionnaire.statusMessage && previousQuestionnaire.questions.length === nextQuestionnaire.questions.length && previousQuestionnaire.questions.every(
2121
2308
  (question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
2122
2309
  ) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
2123
2310
  var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
@@ -2198,6 +2385,8 @@ var ChatMessageItemView = ({
2198
2385
  const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
2199
2386
  const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
2200
2387
  const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
2388
+ const isUserMessage = message.role === "user";
2389
+ const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
2201
2390
  const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
2202
2391
  const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
2203
2392
  const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
@@ -2214,6 +2403,21 @@ var ChatMessageItemView = ({
2214
2403
  message,
2215
2404
  messageRenderOrder
2216
2405
  });
2406
+ const {
2407
+ bodyStackRef,
2408
+ isCollapsed: isUserMessageCollapsed,
2409
+ isCollapsible: isUserMessageCollapsible,
2410
+ isExpanded: isUserMessageExpanded,
2411
+ toggleExpanded: toggleUserMessageExpanded
2412
+ } = useUserMessageCollapse({
2413
+ blocks,
2414
+ displayedBlocks,
2415
+ displayedContent,
2416
+ enabled: isUserMessage,
2417
+ freshContent,
2418
+ settledContent
2419
+ });
2420
+ const renderMessageContent = (content) => messageRenderMode === "plain-text" ? renderPlainTextContent(content) : renderMarkdownContent(content);
2217
2421
  const renderChatMessageBlock = (block, index) => {
2218
2422
  switch (block.type) {
2219
2423
  case "markdown":
@@ -2222,17 +2426,18 @@ var ChatMessageItemView = ({
2222
2426
  {
2223
2427
  "data-testid": `chat-message-block-${index}`,
2224
2428
  "data-block-tone": "settled",
2225
- children: renderMarkdownContent(block.text)
2429
+ "data-render-mode": messageRenderMode,
2430
+ children: renderMessageContent(block.text)
2226
2431
  },
2227
2432
  `markdown-${index}`
2228
2433
  );
2229
2434
  case "notice":
2230
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAINoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
2435
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
2231
2436
  case "parameter_summary":
2232
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAIParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
2437
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
2233
2438
  case "confirmation_card":
2234
2439
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2235
- PDEAIExecutionConfirmationCard,
2440
+ ExecutionConfirmationCard,
2236
2441
  {
2237
2442
  proposal: block.proposal,
2238
2443
  interactive: isPlanMode,
@@ -2244,13 +2449,19 @@ var ChatMessageItemView = ({
2244
2449
  }
2245
2450
  ) }, `confirmation-card-${index}`);
2246
2451
  case "result_summary":
2247
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAIResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
2452
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
2248
2453
  case "questionnaire":
2249
2454
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2250
- PDEAIQuestionnaireCard,
2455
+ QuestionnaireCard,
2251
2456
  {
2252
2457
  questionnaire: block.questionnaire,
2253
2458
  interactive: canSubmitQuestionnaire,
2459
+ labels: {
2460
+ submitting: labels.questionnaireSubmitting,
2461
+ submitted: labels.questionnaireSubmitted,
2462
+ validationPrefix: labels.questionnaireValidationPrefix,
2463
+ submitFailed: labels.questionnaireSubmitFailed
2464
+ },
2254
2465
  onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
2255
2466
  ...submission,
2256
2467
  sourceMessageId: message.id
@@ -2283,14 +2494,31 @@ var ChatMessageItemView = ({
2283
2494
  "data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
2284
2495
  "data-block-tone": block.tone,
2285
2496
  "data-block-index": index,
2286
- children: renderMarkdownContent(block.content)
2497
+ "data-render-mode": messageRenderMode,
2498
+ children: renderMessageContent(block.content)
2287
2499
  },
2288
2500
  `${block.tone}-${index}`
2289
2501
  )),
2290
- !textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(textContent) }) : null
2502
+ !textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2503
+ ContentBlock,
2504
+ {
2505
+ "data-testid": "chat-message-settled-block",
2506
+ "data-block-tone": "settled",
2507
+ "data-render-mode": messageRenderMode,
2508
+ children: renderMessageContent(textContent)
2509
+ }
2510
+ ) : null
2291
2511
  ] });
2292
2512
  };
2293
- const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(content) });
2513
+ const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2514
+ ContentBlock,
2515
+ {
2516
+ "data-testid": "chat-message-settled-block",
2517
+ "data-block-tone": "settled",
2518
+ "data-render-mode": messageRenderMode,
2519
+ children: renderMessageContent(content)
2520
+ }
2521
+ );
2294
2522
  const bodySegments = (() => {
2295
2523
  if (!shouldRenderStructuredBlocks && hasTextContent) {
2296
2524
  return [{ type: "text" }];
@@ -2348,21 +2576,40 @@ var ChatMessageItemView = ({
2348
2576
  }
2349
2577
  ) : null,
2350
2578
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Role, { children: message.role === "user" ? labels.userRoleLabel : labels.assistantRoleLabel }),
2579
+ isUserMessageCollapsible ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2580
+ CollapseToggle,
2581
+ {
2582
+ type: "button",
2583
+ "data-testid": "chat-message-collapse-toggle",
2584
+ "aria-label": isUserMessageExpanded ? labels.collapseMessageAriaLabel : labels.expandMessageAriaLabel,
2585
+ "aria-expanded": isUserMessageExpanded,
2586
+ onClick: toggleUserMessageExpanded,
2587
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CollapseIcon, { expanded: isUserMessageExpanded })
2588
+ }
2589
+ ) : null,
2351
2590
  isStoppedAssistant ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
2352
2591
  ] }),
2353
2592
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Content, { "data-testid": "chat-message-content", children: [
2354
- shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentStack, { "data-testid": "chat-message-body-stack", children: bodySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2355
- ContentSegment,
2593
+ shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2594
+ ContentStack,
2356
2595
  {
2357
- "data-testid": "chat-message-content-segment",
2358
- children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
2359
- content: segment.content,
2360
- displayedBlocks: segment.displayedBlocks,
2361
- useTimelineSegmentation: true
2362
- }) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
2363
- },
2364
- segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
2365
- )) }) : null,
2596
+ ref: bodyStackRef,
2597
+ "data-testid": "chat-message-body-stack",
2598
+ "data-collapsed": isUserMessageCollapsed,
2599
+ children: bodySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2600
+ ContentSegment,
2601
+ {
2602
+ "data-testid": "chat-message-content-segment",
2603
+ children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
2604
+ content: segment.content,
2605
+ displayedBlocks: segment.displayedBlocks,
2606
+ useTimelineSegmentation: true
2607
+ }) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
2608
+ },
2609
+ segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
2610
+ ))
2611
+ }
2612
+ ) : null,
2366
2613
  attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AttachmentGrid, { "data-testid": "chat-message-attachment-grid", children: attachments.map((attachment) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2367
2614
  AttachmentButton,
2368
2615
  {
@@ -2447,6 +2694,29 @@ var StatusTag = import_styled7.default.span`
2447
2694
  letter-spacing: 0.02em;
2448
2695
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
2449
2696
  `;
2697
+ var CollapseToggle = import_styled7.default.button`
2698
+ margin-left: auto;
2699
+ width: 28px;
2700
+ height: 28px;
2701
+ display: inline-flex;
2702
+ align-items: center;
2703
+ justify-content: center;
2704
+ border: 1px solid rgba(255, 255, 255, 0.12);
2705
+ border-radius: 999px;
2706
+ background: rgba(255, 255, 255, 0.06);
2707
+ color: rgba(255, 255, 255, 0.72);
2708
+ cursor: pointer;
2709
+ transition:
2710
+ background 160ms ease-out,
2711
+ border-color 160ms ease-out,
2712
+ color 160ms ease-out;
2713
+
2714
+ &:hover {
2715
+ background: rgba(255, 255, 255, 0.1);
2716
+ border-color: rgba(255, 255, 255, 0.18);
2717
+ color: rgba(255, 255, 255, 0.92);
2718
+ }
2719
+ `;
2450
2720
  var Content = import_styled7.default.div`
2451
2721
  color: rgba(255, 255, 255, 0.92);
2452
2722
  line-height: 1.6;
@@ -2491,6 +2761,11 @@ var ContentStack = import_styled7.default.div`
2491
2761
  display: flex;
2492
2762
  flex-direction: column;
2493
2763
  gap: 16px;
2764
+
2765
+ &[data-collapsed='true'] {
2766
+ max-height: ${USER_MESSAGE_COLLAPSE_HEIGHT_PX}px;
2767
+ overflow: hidden;
2768
+ }
2494
2769
  `;
2495
2770
  var ContentSegment = import_styled7.default.div`
2496
2771
  min-width: 0;
@@ -2504,6 +2779,11 @@ var ContentBlock = import_styled7.default.div`
2504
2779
  margin-top: 16px;
2505
2780
  }
2506
2781
 
2782
+ &[data-render-mode='plain-text'] {
2783
+ white-space: pre-wrap;
2784
+ overflow-wrap: anywhere;
2785
+ }
2786
+
2507
2787
  &[data-block-tone='fresh'] {
2508
2788
  opacity: 0.85;
2509
2789
  filter: brightness(0.82) saturate(0.88);
@@ -2911,7 +3191,14 @@ var ChatThread = () => {
2911
3191
  const error = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
2912
3192
  const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
2913
3193
  const clearSessionError = useChatStore((s) => s.clearSessionError);
2914
- const { sendRef, retryRef, renderMessageBlock, labels } = useChatContext();
3194
+ const {
3195
+ sendRef,
3196
+ retryRef,
3197
+ renderMessageBlock,
3198
+ handleQuestionnaireSubmit: customQuestionnaireSubmit,
3199
+ handleConfirmationSubmit: customConfirmationSubmit,
3200
+ labels
3201
+ } = useChatContext();
2915
3202
  const handleRetry = (0, import_react11.useCallback)(() => {
2916
3203
  if (!activeSessionId)
2917
3204
  return;
@@ -2919,7 +3206,25 @@ var ChatThread = () => {
2919
3206
  void retryRef.current();
2920
3207
  }, [activeSessionId, clearSessionError, retryRef]);
2921
3208
  const handleQuestionnaireSubmit = (0, import_react11.useCallback)(
2922
- (submission) => {
3209
+ async (submission) => {
3210
+ if (customQuestionnaireSubmit) {
3211
+ const handled = await customQuestionnaireSubmit(submission, {
3212
+ sessionId: activeSessionId ?? void 0,
3213
+ mode: activeSessionMode
3214
+ });
3215
+ if (handled !== false) {
3216
+ if (activeSessionId && submission.sourceMessageId) {
3217
+ updateQA(
3218
+ activeSessionId,
3219
+ submission.sourceMessageId,
3220
+ submission.questionnaireId,
3221
+ submission.answers
3222
+ );
3223
+ }
3224
+ return;
3225
+ }
3226
+ }
3227
+ await sendRef.current(submission.content);
2923
3228
  if (activeSessionId && submission.sourceMessageId) {
2924
3229
  updateQA(
2925
3230
  activeSessionId,
@@ -2928,15 +3233,23 @@ var ChatThread = () => {
2928
3233
  submission.answers
2929
3234
  );
2930
3235
  }
2931
- void sendRef.current(submission.content);
2932
3236
  },
2933
- [activeSessionId, updateQA, sendRef]
3237
+ [activeSessionId, activeSessionMode, updateQA, sendRef, customQuestionnaireSubmit]
2934
3238
  );
2935
- const handleConfirmationSubmit = (0, import_react11.useCallback)(
2936
- (submission) => {
2937
- void sendRef.current(submission.content);
3239
+ const handleConfirmation = (0, import_react11.useCallback)(
3240
+ async (submission) => {
3241
+ if (customConfirmationSubmit) {
3242
+ const handled = await customConfirmationSubmit(submission, {
3243
+ sessionId: activeSessionId ?? void 0,
3244
+ mode: activeSessionMode
3245
+ });
3246
+ if (handled !== false) {
3247
+ return;
3248
+ }
3249
+ }
3250
+ await sendRef.current(submission.content);
2938
3251
  },
2939
- [sendRef]
3252
+ [activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
2940
3253
  );
2941
3254
  if (!hasSessions || messages.length === 0 && !streamingMessage) {
2942
3255
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatThreadEmptyState, {});
@@ -2950,7 +3263,7 @@ var ChatThread = () => {
2950
3263
  error,
2951
3264
  retryButtonLabel: labels.retryButton,
2952
3265
  onRetry: handleRetry,
2953
- onConfirmationSubmit: handleConfirmationSubmit,
3266
+ onConfirmationSubmit: handleConfirmation,
2954
3267
  onQuestionnaireSubmit: handleQuestionnaireSubmit,
2955
3268
  renderMessageBlock
2956
3269
  }
@@ -2964,6 +3277,7 @@ var Container = import_styled9.default.div`
2964
3277
  min-height: 0;
2965
3278
  overflow: auto;
2966
3279
  padding: 24px;
3280
+ margin-bottom: 24px;
2967
3281
  overscroll-behavior: contain;
2968
3282
 
2969
3283
  &::-webkit-scrollbar {
@@ -4043,6 +4357,27 @@ var StopSpinner = import_styled13.default.span`
4043
4357
 
4044
4358
  // src/components/chat-composer/index.tsx
4045
4359
  var import_jsx_runtime15 = require("@emotion/react/jsx-runtime");
4360
+ var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
4361
+ var CHAT_COMPOSER_MAX_ROWS = 7;
4362
+ var CHAT_COMPOSER_PADDING_TOP_PX = 8;
4363
+ var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
4364
+ var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
4365
+ var CHAT_COMPOSER_MIN_ROWS = 4;
4366
+ var CHAT_COMPOSER_EXPANDED_MAX_ROWS = 60;
4367
+ var CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO = 0.7;
4368
+ var CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX = 96;
4369
+ var CHAT_COMPOSER_MAX_HEIGHT_PX = CHAT_COMPOSER_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
4370
+ var CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX = CHAT_COMPOSER_EXPANDED_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
4371
+ var getExpandedComposerHeightPx = () => {
4372
+ if (typeof window === "undefined") {
4373
+ return CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX;
4374
+ }
4375
+ const viewportLimitedHeight = window.innerHeight * CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO - CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX;
4376
+ return Math.max(
4377
+ CHAT_COMPOSER_MAX_HEIGHT_PX,
4378
+ Math.floor(Math.min(CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX, viewportLimitedHeight))
4379
+ );
4380
+ };
4046
4381
  var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4047
4382
  "svg",
4048
4383
  {
@@ -4055,6 +4390,36 @@ var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4055
4390
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
4056
4391
  }
4057
4392
  );
4393
+ var ComposerExpandIcon = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4394
+ "svg",
4395
+ {
4396
+ "aria-hidden": "true",
4397
+ width: "16",
4398
+ height: "16",
4399
+ viewBox: "0 0 16 16",
4400
+ fill: "none",
4401
+ xmlns: "http://www.w3.org/2000/svg",
4402
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4403
+ "path",
4404
+ {
4405
+ d: "M14 6h-4V2M10 6l4-4M2 10h4v4M6 10l-4 4",
4406
+ stroke: "currentColor",
4407
+ strokeWidth: "1.5",
4408
+ strokeLinecap: "round",
4409
+ strokeLinejoin: "round"
4410
+ }
4411
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4412
+ "path",
4413
+ {
4414
+ d: "M10 2h4v4M14 2L9 7M6 14H2v-4M2 14l5-5",
4415
+ stroke: "currentColor",
4416
+ strokeWidth: "1.5",
4417
+ strokeLinecap: "round",
4418
+ strokeLinejoin: "round"
4419
+ }
4420
+ )
4421
+ }
4422
+ );
4058
4423
  var ChatComposerView = ({
4059
4424
  value,
4060
4425
  placeholder,
@@ -4071,6 +4436,8 @@ var ChatComposerView = ({
4071
4436
  isStopping,
4072
4437
  enableImageAttachments,
4073
4438
  modeLabels,
4439
+ expandComposerAriaLabel,
4440
+ collapseComposerAriaLabel,
4074
4441
  onValueChange,
4075
4442
  onPickImages,
4076
4443
  onPasteImages,
@@ -4082,6 +4449,9 @@ var ChatComposerView = ({
4082
4449
  onSend
4083
4450
  }) => {
4084
4451
  const imageInputRef = (0, import_react15.useRef)(null);
4452
+ const inputRef = (0, import_react15.useRef)(null);
4453
+ const [isComposerExpandable, setIsComposerExpandable] = (0, import_react15.useState)(false);
4454
+ const [isComposerExpanded, setIsComposerExpanded] = (0, import_react15.useState)(false);
4085
4455
  const canSend = canSendChatMessage({
4086
4456
  value,
4087
4457
  attachmentCount: attachments.length,
@@ -4089,6 +4459,26 @@ var ChatComposerView = ({
4089
4459
  isModelsError,
4090
4460
  hasModels
4091
4461
  });
4462
+ (0, import_react15.useLayoutEffect)(() => {
4463
+ const element = inputRef.current;
4464
+ if (!element) {
4465
+ return;
4466
+ }
4467
+ if (!isComposerExpanded) {
4468
+ element.style.height = "0px";
4469
+ }
4470
+ const scrollHeight = element.scrollHeight;
4471
+ const nextExpandable = scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX;
4472
+ const expandedHeight = getExpandedComposerHeightPx();
4473
+ const nextHeight = isComposerExpanded ? expandedHeight : Math.min(scrollHeight, CHAT_COMPOSER_MAX_HEIGHT_PX);
4474
+ setIsComposerExpandable(nextExpandable);
4475
+ element.style.height = `${nextHeight}px`;
4476
+ element.style.overflowY = !isComposerExpanded && scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX ? "auto" : "hidden";
4477
+ }, [isComposerExpanded, value]);
4478
+ const handleSend = async () => {
4479
+ setIsComposerExpanded(false);
4480
+ await onSend();
4481
+ };
4092
4482
  const handleKeyDown = (event) => {
4093
4483
  if (shouldStopChatComposer({ key: event.key, shiftKey: event.shiftKey, isStreaming })) {
4094
4484
  event.preventDefault();
@@ -4098,7 +4488,7 @@ var ChatComposerView = ({
4098
4488
  if (!shouldSubmitChatComposer({ key: event.key, shiftKey: event.shiftKey, canSend }))
4099
4489
  return;
4100
4490
  event.preventDefault();
4101
- void onSend();
4491
+ void handleSend();
4102
4492
  };
4103
4493
  const handlePickImages = (event) => {
4104
4494
  if (event.target.files?.length)
@@ -4133,60 +4523,77 @@ var ChatComposerView = ({
4133
4523
  }
4134
4524
  ),
4135
4525
  attachmentNotice === "limit_reached" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
4136
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4137
- Input,
4138
- {
4139
- "data-testid": "chat-composer-input",
4140
- value,
4141
- onChange: (event) => onValueChange(event.target.value),
4142
- onKeyDown: handleKeyDown,
4143
- onPaste: enableImageAttachments ? handlePaste : void 0,
4144
- placeholder
4145
- }
4146
- ),
4147
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Footer, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Actions2, { "data-testid": "chat-composer-actions", children: [
4148
- enableImageAttachments ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4149
- AttachButton,
4526
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(InputArea, { "data-testid": "chat-composer-input-area", children: [
4527
+ isComposerExpanded || isComposerExpandable ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4528
+ ComposerExpandButton,
4150
4529
  {
4151
4530
  type: "button",
4152
- "data-testid": "chat-composer-attach-image",
4153
- "aria-label": "Attach image",
4154
- onClick: () => imageInputRef.current?.click(),
4155
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PlusIcon, {})
4531
+ "data-testid": "chat-composer-expand-toggle",
4532
+ "aria-label": isComposerExpanded ? collapseComposerAriaLabel : expandComposerAriaLabel,
4533
+ "aria-expanded": isComposerExpanded,
4534
+ onClick: () => setIsComposerExpanded((current) => !current),
4535
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ComposerExpandIcon, { expanded: isComposerExpanded })
4156
4536
  }
4157
4537
  ) : null,
4158
4538
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4159
- ChatModeControl,
4160
- {
4161
- value: selectedMode,
4162
- disabled: isStreaming,
4163
- labels: modeLabels,
4164
- onChange: onSelectedModeChange
4165
- }
4166
- ),
4167
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4168
- ChatModelControl,
4539
+ Input,
4169
4540
  {
4170
- selectedModel,
4171
- availableModels,
4172
- isModelsLoading,
4173
- isModelsError,
4174
- hasModels,
4175
- onSelectedModelChange,
4176
- onReloadModels
4541
+ ref: inputRef,
4542
+ "data-testid": "chat-composer-input",
4543
+ "data-expanded": isComposerExpanded,
4544
+ value,
4545
+ onChange: (event) => onValueChange(event.target.value),
4546
+ onKeyDown: handleKeyDown,
4547
+ onPaste: enableImageAttachments ? handlePaste : void 0,
4548
+ placeholder
4177
4549
  }
4178
- ),
4179
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4180
- ChatSendActions,
4550
+ )
4551
+ ] }),
4552
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Footer, { children: [
4553
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: enableImageAttachments ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4554
+ AttachButton,
4181
4555
  {
4182
- canSend,
4183
- isStreaming,
4184
- isStopping,
4185
- onStop,
4186
- onSend
4556
+ type: "button",
4557
+ "data-testid": "chat-composer-attach-image",
4558
+ "aria-label": "Attach image",
4559
+ onClick: () => imageInputRef.current?.click(),
4560
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PlusIcon, {})
4187
4561
  }
4188
- )
4189
- ] }) })
4562
+ ) : null }),
4563
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(TrailingActions, { "data-testid": "chat-composer-trailing-actions", children: [
4564
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4565
+ ChatModeControl,
4566
+ {
4567
+ value: selectedMode,
4568
+ disabled: isStreaming,
4569
+ labels: modeLabels,
4570
+ onChange: onSelectedModeChange
4571
+ }
4572
+ ),
4573
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4574
+ ChatModelControl,
4575
+ {
4576
+ selectedModel,
4577
+ availableModels,
4578
+ isModelsLoading,
4579
+ isModelsError,
4580
+ hasModels,
4581
+ onSelectedModelChange,
4582
+ onReloadModels
4583
+ }
4584
+ ),
4585
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4586
+ ChatSendActions,
4587
+ {
4588
+ canSend,
4589
+ isStreaming,
4590
+ isStopping,
4591
+ onStop,
4592
+ onSend: handleSend
4593
+ }
4594
+ )
4595
+ ] })
4596
+ ] })
4190
4597
  ] }) });
4191
4598
  };
4192
4599
  var ChatComposer = () => {
@@ -4222,6 +4629,8 @@ var ChatComposer = () => {
4222
4629
  isStopping: state.isStopping,
4223
4630
  enableImageAttachments,
4224
4631
  modeLabels,
4632
+ expandComposerAriaLabel: labels.expandComposerAriaLabel,
4633
+ collapseComposerAriaLabel: labels.collapseComposerAriaLabel,
4225
4634
  onValueChange: actions.setValue,
4226
4635
  onPickImages: actions.pickImages,
4227
4636
  onPasteImages: actions.pasteImages,
@@ -4238,6 +4647,16 @@ var Container2 = import_styled14.default.div`
4238
4647
  padding: 0 16px 16px;
4239
4648
  `;
4240
4649
  var Surface = import_styled14.default.div`
4650
+ display: grid;
4651
+ grid-template-columns: minmax(0, 1fr);
4652
+ grid-template-areas:
4653
+ 'attachments'
4654
+ 'notice'
4655
+ 'input'
4656
+ 'footer';
4657
+ width: 100%;
4658
+ max-width: 760px;
4659
+ margin: 0 auto;
4241
4660
  background: var(--border-color);
4242
4661
  border-radius: 20px;
4243
4662
  border: 1px solid var(--border-hover);
@@ -4247,6 +4666,7 @@ var Surface = import_styled14.default.div`
4247
4666
  backdrop-filter: blur(10px);
4248
4667
  `;
4249
4668
  var AttachmentNotice = import_styled14.default.div`
4669
+ grid-area: notice;
4250
4670
  margin: 10px 12px 0;
4251
4671
  padding: 8px 10px;
4252
4672
  border-radius: 10px;
@@ -4256,19 +4676,45 @@ var AttachmentNotice = import_styled14.default.div`
4256
4676
  font-size: 12px;
4257
4677
  line-height: 1.4;
4258
4678
  `;
4679
+ var InputArea = import_styled14.default.div`
4680
+ grid-area: input;
4681
+ position: relative;
4682
+ `;
4259
4683
  var Input = import_styled14.default.textarea`
4684
+ --textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
4685
+ --textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
4686
+ --textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
4687
+ --textarea-expanded-max-rows: ${CHAT_COMPOSER_EXPANDED_MAX_ROWS};
4688
+ --textarea-padding-top: ${CHAT_COMPOSER_PADDING_TOP_PX}px;
4689
+ --textarea-padding-bottom: ${CHAT_COMPOSER_PADDING_BOTTOM_PX}px;
4690
+ --textarea-padding-block: calc(var(--textarea-padding-top) + var(--textarea-padding-bottom));
4691
+ --textarea-max-height: calc(
4692
+ var(--textarea-max-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
4693
+ );
4694
+ --textarea-expanded-max-height: min(
4695
+ calc(
4696
+ var(--textarea-expanded-max-rows) * var(--textarea-line-height) +
4697
+ var(--textarea-padding-block)
4698
+ ),
4699
+ calc(70vh - ${CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX}px)
4700
+ );
4260
4701
  width: 100%;
4261
- min-height: 96px;
4702
+ min-height: calc(
4703
+ var(--textarea-min-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
4704
+ );
4705
+ max-height: var(--textarea-max-height);
4706
+ box-sizing: border-box;
4262
4707
  resize: none;
4263
4708
  appearance: none;
4264
4709
  border: 0;
4265
4710
  outline: 0;
4266
4711
  background: transparent;
4267
- padding: 8px 12px 12px 12px;
4712
+ padding: var(--textarea-padding-top) 44px var(--textarea-padding-bottom) 12px;
4268
4713
  font-weight: 400;
4269
4714
  font-size: 14px;
4270
4715
  color: var(--text-primary);
4271
- line-height: 20px;
4716
+ line-height: var(--textarea-line-height);
4717
+ overflow-y: hidden;
4272
4718
 
4273
4719
  &::placeholder {
4274
4720
  color: var(--text-secondary);
@@ -4277,19 +4723,50 @@ var Input = import_styled14.default.textarea`
4277
4723
  &::-webkit-resizer {
4278
4724
  display: none;
4279
4725
  }
4726
+
4727
+ &[data-expanded='true'] {
4728
+ max-height: var(--textarea-expanded-max-height);
4729
+ }
4730
+ `;
4731
+ var ComposerExpandButton = import_styled14.default.button`
4732
+ position: absolute;
4733
+ top: 8px;
4734
+ right: 10px;
4735
+ width: 28px;
4736
+ height: 28px;
4737
+ display: grid;
4738
+ place-items: center;
4739
+ border: none;
4740
+ border-radius: 999px;
4741
+ background: transparent;
4742
+ color: rgba(255, 255, 255, 0.72);
4743
+ cursor: pointer;
4744
+ z-index: 1;
4745
+
4746
+ &:hover {
4747
+ background: rgba(255, 255, 255, 0.08);
4748
+ color: rgba(255, 255, 255, 0.92);
4749
+ }
4280
4750
  `;
4281
4751
  var Footer = import_styled14.default.div`
4282
- display: flex;
4752
+ grid-area: footer;
4753
+ display: grid;
4754
+ grid-template-columns: minmax(0, 1fr) auto;
4283
4755
  align-items: flex-end;
4284
- justify-content: stretch;
4285
4756
  gap: 16px;
4286
4757
  padding: 0 14px 14px;
4287
4758
  `;
4288
- var Actions2 = import_styled14.default.div`
4759
+ var LeadingActions = import_styled14.default.div`
4760
+ display: flex;
4761
+ align-items: center;
4762
+ justify-content: flex-start;
4763
+ gap: 8px;
4764
+ min-width: 0;
4765
+ `;
4766
+ var TrailingActions = import_styled14.default.div`
4289
4767
  display: flex;
4290
4768
  align-items: center;
4291
4769
  flex-wrap: wrap;
4292
- width: 100%;
4293
4770
  min-width: 0;
4294
4771
  justify-content: flex-end;
4295
4772
  gap: 8px;