@dataverse-kit/agent-kit 0.2.0 → 0.2.1
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 +106 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -5
- package/dist/index.d.ts +18 -5
- package/dist/index.mjs +113 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -94,19 +94,26 @@ interface ComposerProps {
|
|
|
94
94
|
maxLength?: number;
|
|
95
95
|
/** 'enter' sends on Enter; 'mod+enter' needs Ctrl/Cmd. */
|
|
96
96
|
sendOn?: 'enter' | 'mod+enter';
|
|
97
|
-
/** Rendered left of the send button — attachments, formatting,
|
|
97
|
+
/** Rendered inside the box, left of the send button — attachments, formatting, emoji. */
|
|
98
98
|
toolbar?: React$1.ReactNode;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
|
-
* The send box
|
|
101
|
+
* The send box, shaped like the Teams composer: one rounded container holding a borderless
|
|
102
|
+
* field, the host's affordances, and the send button behind a divider.
|
|
102
103
|
*
|
|
103
104
|
* ★ `sendOn` is configurable, and defaults to Enter only because that is what users expect
|
|
104
105
|
* from Teams. Enter-to-send in a multiline field is hostile to dictation and voice control,
|
|
105
|
-
* and Shift+Enter is undiscoverable — hence the `aria-describedby` hint
|
|
106
|
-
*
|
|
106
|
+
* and Shift+Enter is undiscoverable — hence the `aria-describedby` hint. The hint is
|
|
107
|
+
* VISUALLY HIDDEN, not removed: Teams does not print it, but a screen-reader user has no
|
|
108
|
+
* other way to learn the contract.
|
|
109
|
+
*
|
|
110
|
+
* ★ Growth is by HARD NEWLINE only, to `MAX_ROWS`, then the field scrolls. It does not grow on
|
|
111
|
+
* soft wrap — that needs measurement, and a ResizeObserver here would be untestable in jsdom
|
|
112
|
+
* (a stubbed one never fires). Stated rather than implied, because Teams does grow on wrap.
|
|
107
113
|
*
|
|
108
114
|
* ★ Deliberately NOT Fluent's `Toolbar` for the affordance row: it reaches
|
|
109
115
|
* `useArrowNavigationGroup`. Consumers pass plain buttons, or the in-tree ActionToolbar.
|
|
116
|
+
* The kit ships no emoji/GIF/format pickers — those are host concerns; `toolbar` is the slot.
|
|
110
117
|
*/
|
|
111
118
|
declare function Composer(props: ComposerProps): React$1.ReactElement;
|
|
112
119
|
|
|
@@ -114,10 +121,16 @@ interface SuggestedPromptsProps {
|
|
|
114
121
|
prompts: readonly string[];
|
|
115
122
|
onPick: (prompt: string) => void;
|
|
116
123
|
heading?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Row alignment. Defaults to `'start'`, which is right above a composer where the chips read as
|
|
126
|
+
* a continuation of the transcript. `'center'` is for a centred zero state — see
|
|
127
|
+
* `EmptyConversation`, where left-packed chips under a centred heading looked like a defect.
|
|
128
|
+
*/
|
|
129
|
+
align?: 'start' | 'center';
|
|
117
130
|
}
|
|
118
131
|
/** ★ Plain Buttons in a labelled list, not Fluent's `TagGroup` — `react-tags` reaches
|
|
119
132
|
* `useArrowNavigationGroup`, and chips gain nothing from it here. */
|
|
120
|
-
declare function SuggestedPrompts({ prompts, onPick, heading, }: SuggestedPromptsProps): React$1.ReactElement | null;
|
|
133
|
+
declare function SuggestedPrompts({ prompts, onPick, heading, align, }: SuggestedPromptsProps): React$1.ReactElement | null;
|
|
121
134
|
|
|
122
135
|
interface EmptyConversationProps {
|
|
123
136
|
title?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -94,19 +94,26 @@ interface ComposerProps {
|
|
|
94
94
|
maxLength?: number;
|
|
95
95
|
/** 'enter' sends on Enter; 'mod+enter' needs Ctrl/Cmd. */
|
|
96
96
|
sendOn?: 'enter' | 'mod+enter';
|
|
97
|
-
/** Rendered left of the send button — attachments, formatting,
|
|
97
|
+
/** Rendered inside the box, left of the send button — attachments, formatting, emoji. */
|
|
98
98
|
toolbar?: React$1.ReactNode;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
|
-
* The send box
|
|
101
|
+
* The send box, shaped like the Teams composer: one rounded container holding a borderless
|
|
102
|
+
* field, the host's affordances, and the send button behind a divider.
|
|
102
103
|
*
|
|
103
104
|
* ★ `sendOn` is configurable, and defaults to Enter only because that is what users expect
|
|
104
105
|
* from Teams. Enter-to-send in a multiline field is hostile to dictation and voice control,
|
|
105
|
-
* and Shift+Enter is undiscoverable — hence the `aria-describedby` hint
|
|
106
|
-
*
|
|
106
|
+
* and Shift+Enter is undiscoverable — hence the `aria-describedby` hint. The hint is
|
|
107
|
+
* VISUALLY HIDDEN, not removed: Teams does not print it, but a screen-reader user has no
|
|
108
|
+
* other way to learn the contract.
|
|
109
|
+
*
|
|
110
|
+
* ★ Growth is by HARD NEWLINE only, to `MAX_ROWS`, then the field scrolls. It does not grow on
|
|
111
|
+
* soft wrap — that needs measurement, and a ResizeObserver here would be untestable in jsdom
|
|
112
|
+
* (a stubbed one never fires). Stated rather than implied, because Teams does grow on wrap.
|
|
107
113
|
*
|
|
108
114
|
* ★ Deliberately NOT Fluent's `Toolbar` for the affordance row: it reaches
|
|
109
115
|
* `useArrowNavigationGroup`. Consumers pass plain buttons, or the in-tree ActionToolbar.
|
|
116
|
+
* The kit ships no emoji/GIF/format pickers — those are host concerns; `toolbar` is the slot.
|
|
110
117
|
*/
|
|
111
118
|
declare function Composer(props: ComposerProps): React$1.ReactElement;
|
|
112
119
|
|
|
@@ -114,10 +121,16 @@ interface SuggestedPromptsProps {
|
|
|
114
121
|
prompts: readonly string[];
|
|
115
122
|
onPick: (prompt: string) => void;
|
|
116
123
|
heading?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Row alignment. Defaults to `'start'`, which is right above a composer where the chips read as
|
|
126
|
+
* a continuation of the transcript. `'center'` is for a centred zero state — see
|
|
127
|
+
* `EmptyConversation`, where left-packed chips under a centred heading looked like a defect.
|
|
128
|
+
*/
|
|
129
|
+
align?: 'start' | 'center';
|
|
117
130
|
}
|
|
118
131
|
/** ★ Plain Buttons in a labelled list, not Fluent's `TagGroup` — `react-tags` reaches
|
|
119
132
|
* `useArrowNavigationGroup`, and chips gain nothing from it here. */
|
|
120
|
-
declare function SuggestedPrompts({ prompts, onPick, heading, }: SuggestedPromptsProps): React$1.ReactElement | null;
|
|
133
|
+
declare function SuggestedPrompts({ prompts, onPick, heading, align, }: SuggestedPromptsProps): React$1.ReactElement | null;
|
|
121
134
|
|
|
122
135
|
interface EmptyConversationProps {
|
|
123
136
|
title?: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1190,19 +1190,76 @@ function MessageList(props) {
|
|
|
1190
1190
|
|
|
1191
1191
|
// src/conversation/Composer.tsx
|
|
1192
1192
|
import * as React11 from "react";
|
|
1193
|
-
import { Button as Button4, Textarea, makeStyles as makeStyles11, tokens as tokens10, Tooltip as Tooltip2 } from "@fluentui/react-components";
|
|
1193
|
+
import { Button as Button4, Textarea, makeStyles as makeStyles11, mergeClasses as mergeClasses5, tokens as tokens10, Tooltip as Tooltip2 } from "@fluentui/react-components";
|
|
1194
1194
|
import { SendRegular, StopRegular } from "@fluentui/react-icons";
|
|
1195
1195
|
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1196
|
+
var MAX_ROWS = 6;
|
|
1196
1197
|
var useStyles10 = makeStyles11({
|
|
1197
|
-
|
|
1198
|
-
display: "flex",
|
|
1199
|
-
gap: tokens10.spacingHorizontalS,
|
|
1200
|
-
alignItems: "flex-end",
|
|
1198
|
+
wrapper: {
|
|
1201
1199
|
padding: tokens10.spacingVerticalS,
|
|
1202
1200
|
borderTop: `1px solid ${tokens10.colorNeutralStroke2}`
|
|
1203
1201
|
},
|
|
1204
|
-
|
|
1205
|
-
|
|
1202
|
+
// The Teams send box: ONE rounded container holding the field and the affordances.
|
|
1203
|
+
box: {
|
|
1204
|
+
display: "flex",
|
|
1205
|
+
alignItems: "flex-end",
|
|
1206
|
+
gap: tokens10.spacingHorizontalXXS,
|
|
1207
|
+
paddingLeft: tokens10.spacingHorizontalS,
|
|
1208
|
+
paddingRight: tokens10.spacingHorizontalXXS,
|
|
1209
|
+
paddingTop: tokens10.spacingVerticalXXS,
|
|
1210
|
+
paddingBottom: tokens10.spacingVerticalXXS,
|
|
1211
|
+
borderRadius: tokens10.borderRadiusXLarge,
|
|
1212
|
+
border: `1px solid ${tokens10.colorNeutralStroke1}`,
|
|
1213
|
+
backgroundColor: tokens10.colorNeutralBackground1,
|
|
1214
|
+
// ★ The ring moves to the CONTAINER because the field's own indicator is suppressed below.
|
|
1215
|
+
// It is an `outline`, not a box-shadow, so forced-colors still paints it (a11y rule 5).
|
|
1216
|
+
":focus-within": {
|
|
1217
|
+
border: `1px solid ${tokens10.colorCompoundBrandStroke}`,
|
|
1218
|
+
outline: `2px solid ${tokens10.colorCompoundBrandStroke}`,
|
|
1219
|
+
outlineOffset: "-1px"
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
boxDisabled: {
|
|
1223
|
+
backgroundColor: tokens10.colorNeutralBackgroundDisabled,
|
|
1224
|
+
border: `1px solid ${tokens10.colorNeutralStrokeDisabled}`
|
|
1225
|
+
},
|
|
1226
|
+
// Fluent's Textarea has no transparent appearance, so its chrome is removed here and the
|
|
1227
|
+
// container above supplies it. `::after` is Fluent's focus underline.
|
|
1228
|
+
field: {
|
|
1229
|
+
flexGrow: 1,
|
|
1230
|
+
minWidth: 0,
|
|
1231
|
+
backgroundColor: "transparent",
|
|
1232
|
+
border: "none",
|
|
1233
|
+
borderRadius: 0,
|
|
1234
|
+
"::after": { display: "none" }
|
|
1235
|
+
},
|
|
1236
|
+
fieldInner: {
|
|
1237
|
+
backgroundColor: "transparent",
|
|
1238
|
+
// ★ Fluent's Textarea ships `min-height: 52px` (measured). The affordance buttons are 32px,
|
|
1239
|
+
// so the default left the placeholder on one line and the icons on another — the single
|
|
1240
|
+
// visible difference from the Teams reference. Matching the button height puts them on
|
|
1241
|
+
// one baseline; growth past one row is then driven by `rows`, up to maxHeight.
|
|
1242
|
+
minHeight: "32px",
|
|
1243
|
+
maxHeight: "160px",
|
|
1244
|
+
paddingLeft: 0,
|
|
1245
|
+
paddingRight: 0
|
|
1246
|
+
},
|
|
1247
|
+
actions: {
|
|
1248
|
+
display: "flex",
|
|
1249
|
+
alignItems: "center",
|
|
1250
|
+
gap: tokens10.spacingHorizontalXXS
|
|
1251
|
+
// ★ No extra bottom padding: `alignItems: flex-end` on the box already pins this row to the
|
|
1252
|
+
// field's last line, and padding on top of it pushed the send glyph visibly below the
|
|
1253
|
+
// baseline on a single-row box (measured against the Teams reference).
|
|
1254
|
+
},
|
|
1255
|
+
divider: {
|
|
1256
|
+
width: "1px",
|
|
1257
|
+
alignSelf: "center",
|
|
1258
|
+
height: "20px",
|
|
1259
|
+
marginLeft: tokens10.spacingHorizontalXXS,
|
|
1260
|
+
marginRight: tokens10.spacingHorizontalXXS,
|
|
1261
|
+
backgroundColor: tokens10.colorNeutralStroke2
|
|
1262
|
+
}
|
|
1206
1263
|
});
|
|
1207
1264
|
function Composer(props) {
|
|
1208
1265
|
const {
|
|
@@ -1218,6 +1275,7 @@ function Composer(props) {
|
|
|
1218
1275
|
toolbar
|
|
1219
1276
|
} = props;
|
|
1220
1277
|
const styles = useStyles10();
|
|
1278
|
+
const vh = useVisuallyHiddenStyles();
|
|
1221
1279
|
const hintId = React11.useId();
|
|
1222
1280
|
const submit = () => {
|
|
1223
1281
|
const text = value.trim();
|
|
@@ -1232,56 +1290,77 @@ function Composer(props) {
|
|
|
1232
1290
|
submit();
|
|
1233
1291
|
};
|
|
1234
1292
|
const hint = sendOn === "enter" ? "Press Enter to send, Shift plus Enter for a new line." : "Press Control or Command plus Enter to send.";
|
|
1235
|
-
|
|
1236
|
-
|
|
1293
|
+
const rows = Math.min(MAX_ROWS, Math.max(1, value.split("\n").length));
|
|
1294
|
+
return /* @__PURE__ */ jsxs9("div", { className: styles.wrapper, children: [
|
|
1295
|
+
/* @__PURE__ */ jsxs9("div", { className: mergeClasses5(styles.box, disabled && styles.boxDisabled), children: [
|
|
1237
1296
|
/* @__PURE__ */ jsx12(
|
|
1238
1297
|
Textarea,
|
|
1239
1298
|
{
|
|
1299
|
+
className: styles.field,
|
|
1240
1300
|
value,
|
|
1241
1301
|
onChange: (_, data) => onChange(data.value),
|
|
1242
1302
|
onKeyDown,
|
|
1243
1303
|
placeholder,
|
|
1244
1304
|
disabled,
|
|
1245
1305
|
maxLength,
|
|
1246
|
-
resize: "
|
|
1306
|
+
resize: "none",
|
|
1307
|
+
appearance: "outline",
|
|
1247
1308
|
"aria-label": placeholder,
|
|
1248
1309
|
"aria-describedby": hintId,
|
|
1249
|
-
textarea: { "aria-multiline": true }
|
|
1310
|
+
textarea: { "aria-multiline": true, rows, className: styles.fieldInner }
|
|
1250
1311
|
}
|
|
1251
1312
|
),
|
|
1252
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ jsxs9("div", { className: styles.actions, children: [
|
|
1314
|
+
toolbar,
|
|
1315
|
+
toolbar ? /* @__PURE__ */ jsx12("span", { className: styles.divider, "aria-hidden": "true" }) : null,
|
|
1316
|
+
busy && onStop ? /* @__PURE__ */ jsx12(Tooltip2, { content: "Stop generating", relationship: "label", withArrow: true, children: /* @__PURE__ */ jsx12(Button4, { appearance: "subtle", icon: /* @__PURE__ */ jsx12(StopRegular, {}), onClick: onStop }) }) : /* @__PURE__ */ jsx12(Tooltip2, { content: "Send", relationship: "label", withArrow: true, children: /* @__PURE__ */ jsx12(
|
|
1317
|
+
Button4,
|
|
1318
|
+
{
|
|
1319
|
+
appearance: "subtle",
|
|
1320
|
+
icon: /* @__PURE__ */ jsx12(SendRegular, {}),
|
|
1321
|
+
onClick: submit,
|
|
1322
|
+
disabled: !value.trim() || busy || disabled
|
|
1323
|
+
}
|
|
1324
|
+
) })
|
|
1325
|
+
] })
|
|
1253
1326
|
] }),
|
|
1254
|
-
|
|
1255
|
-
busy && onStop ? /* @__PURE__ */ jsx12(Tooltip2, { content: "Stop generating", relationship: "label", withArrow: true, children: /* @__PURE__ */ jsx12(Button4, { appearance: "secondary", icon: /* @__PURE__ */ jsx12(StopRegular, {}), onClick: onStop }) }) : /* @__PURE__ */ jsx12(Tooltip2, { content: "Send", relationship: "label", withArrow: true, children: /* @__PURE__ */ jsx12(
|
|
1256
|
-
Button4,
|
|
1257
|
-
{
|
|
1258
|
-
appearance: "primary",
|
|
1259
|
-
icon: /* @__PURE__ */ jsx12(SendRegular, {}),
|
|
1260
|
-
onClick: submit,
|
|
1261
|
-
disabled: !value.trim() || busy || disabled
|
|
1262
|
-
}
|
|
1263
|
-
) })
|
|
1327
|
+
/* @__PURE__ */ jsx12("span", { id: hintId, className: vh.root, children: hint })
|
|
1264
1328
|
] });
|
|
1265
1329
|
}
|
|
1266
1330
|
|
|
1267
1331
|
// src/conversation/SuggestedPrompts.tsx
|
|
1268
|
-
import { Button as Button5, makeStyles as makeStyles12, tokens as tokens11 } from "@fluentui/react-components";
|
|
1332
|
+
import { Button as Button5, makeStyles as makeStyles12, mergeClasses as mergeClasses6, tokens as tokens11 } from "@fluentui/react-components";
|
|
1269
1333
|
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1270
1334
|
var useStyles11 = makeStyles12({
|
|
1271
1335
|
root: { display: "flex", flexWrap: "wrap", gap: tokens11.spacingHorizontalXS, padding: tokens11.spacingVerticalXS },
|
|
1336
|
+
// ★ The heading is `width: 100%`, so it takes the PARENT's text-align while the chips take the
|
|
1337
|
+
// flex row's justification. That split is why the label could look centred while the chips
|
|
1338
|
+
// stayed left-packed — the two are aligned by different mechanisms and must both be set.
|
|
1339
|
+
center: { justifyContent: "center" },
|
|
1340
|
+
headingCenter: { textAlign: "center" },
|
|
1272
1341
|
heading: { width: "100%", fontSize: tokens11.fontSizeBase200, color: tokens11.colorNeutralForeground3 }
|
|
1273
1342
|
});
|
|
1274
1343
|
function SuggestedPrompts({
|
|
1275
1344
|
prompts,
|
|
1276
1345
|
onPick,
|
|
1277
|
-
heading = "Suggested follow-ups"
|
|
1346
|
+
heading = "Suggested follow-ups",
|
|
1347
|
+
align = "start"
|
|
1278
1348
|
}) {
|
|
1279
1349
|
const styles = useStyles11();
|
|
1280
1350
|
if (prompts.length === 0) return null;
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1351
|
+
const centered = align === "center";
|
|
1352
|
+
return /* @__PURE__ */ jsxs10(
|
|
1353
|
+
"div",
|
|
1354
|
+
{
|
|
1355
|
+
className: mergeClasses6(styles.root, centered && styles.center),
|
|
1356
|
+
role: "group",
|
|
1357
|
+
"aria-label": heading,
|
|
1358
|
+
children: [
|
|
1359
|
+
/* @__PURE__ */ jsx13("span", { className: mergeClasses6(styles.heading, centered && styles.headingCenter), children: heading }),
|
|
1360
|
+
prompts.map((prompt) => /* @__PURE__ */ jsx13(Button5, { size: "small", appearance: "outline", onClick: () => onPick(prompt), children: prompt }, prompt))
|
|
1361
|
+
]
|
|
1362
|
+
}
|
|
1363
|
+
);
|
|
1285
1364
|
}
|
|
1286
1365
|
|
|
1287
1366
|
// src/conversation/EmptyConversation.tsx
|
|
@@ -1310,7 +1389,7 @@ function EmptyConversation({
|
|
|
1310
1389
|
return /* @__PURE__ */ jsxs11("div", { className: styles.root, children: [
|
|
1311
1390
|
/* @__PURE__ */ jsx14(Text2, { as: "h2", size: 500, weight: "semibold", children: title }),
|
|
1312
1391
|
/* @__PURE__ */ jsx14(Text2, { children: description }),
|
|
1313
|
-
onPick && prompts.length > 0 ? /* @__PURE__ */ jsx14(SuggestedPrompts, { prompts, onPick, heading: "Try one of these" }) : null
|
|
1392
|
+
onPick && prompts.length > 0 ? /* @__PURE__ */ jsx14(SuggestedPrompts, { prompts, onPick, heading: "Try one of these", align: "center" }) : null
|
|
1314
1393
|
] });
|
|
1315
1394
|
}
|
|
1316
1395
|
|
|
@@ -1760,7 +1839,7 @@ import {
|
|
|
1760
1839
|
MenuItem,
|
|
1761
1840
|
Tooltip as Tooltip4,
|
|
1762
1841
|
makeStyles as makeStyles19,
|
|
1763
|
-
mergeClasses as
|
|
1842
|
+
mergeClasses as mergeClasses7,
|
|
1764
1843
|
tokens as tokens18
|
|
1765
1844
|
} from "@fluentui/react-components";
|
|
1766
1845
|
import { MoreHorizontalRegular } from "@fluentui/react-icons";
|
|
@@ -1807,7 +1886,7 @@ function AppRail(props) {
|
|
|
1807
1886
|
{
|
|
1808
1887
|
appearance: "subtle",
|
|
1809
1888
|
icon: item.icon,
|
|
1810
|
-
className:
|
|
1889
|
+
className: mergeClasses7(styles.button, item.id === selectedId && styles.selected),
|
|
1811
1890
|
"aria-pressed": item.id === selectedId,
|
|
1812
1891
|
"aria-label": item.badgeCount ? `${item.label}, ${item.badgeCount} unread` : item.label,
|
|
1813
1892
|
onClick: () => onSelect(item.id),
|
|
@@ -1836,7 +1915,7 @@ import * as React15 from "react";
|
|
|
1836
1915
|
import { makeStyles as makeStyles21, tokens as tokens20, Text as Text6 } from "@fluentui/react-components";
|
|
1837
1916
|
|
|
1838
1917
|
// src/shell/ConversationListItem.tsx
|
|
1839
|
-
import { makeStyles as makeStyles20, mergeClasses as
|
|
1918
|
+
import { makeStyles as makeStyles20, mergeClasses as mergeClasses8, tokens as tokens19 } from "@fluentui/react-components";
|
|
1840
1919
|
|
|
1841
1920
|
// src/shell/AgentAvatar.tsx
|
|
1842
1921
|
import { Avatar as Avatar2 } from "@fluentui/react-components";
|
|
@@ -1935,13 +2014,13 @@ function ConversationListItem(props) {
|
|
|
1935
2014
|
role: "option",
|
|
1936
2015
|
"aria-selected": selected,
|
|
1937
2016
|
"aria-label": conversationAccessibleName(summary, locale),
|
|
1938
|
-
className:
|
|
2017
|
+
className: mergeClasses8(styles.row, selected && styles.selected, active && styles.active),
|
|
1939
2018
|
onClick: () => onSelect(summary.id),
|
|
1940
2019
|
"data-conversation-option": true,
|
|
1941
2020
|
children: [
|
|
1942
2021
|
/* @__PURE__ */ jsx28(AgentAvatar, { participant: summary.participant, presence: summary.presence, size: 32 }),
|
|
1943
2022
|
/* @__PURE__ */ jsxs21("div", { className: styles.body, "aria-hidden": "true", children: [
|
|
1944
|
-
/* @__PURE__ */ jsx28("span", { className:
|
|
2023
|
+
/* @__PURE__ */ jsx28("span", { className: mergeClasses8(styles.title, summary.muted && styles.muted), children: summary.title }),
|
|
1945
2024
|
summary.preview ? /* @__PURE__ */ jsx28("span", { className: styles.preview, children: summary.preview }) : null
|
|
1946
2025
|
] }),
|
|
1947
2026
|
/* @__PURE__ */ jsxs21("div", { className: styles.meta, "aria-hidden": "true", children: [
|