vanilla-agent 1.19.0 → 1.21.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.cjs +20 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +370 -4
- package/dist/index.d.ts +370 -4
- package/dist/index.global.js +35 -35
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +20 -20
- package/dist/index.js.map +1 -1
- package/dist/widget.css +282 -5
- package/package.json +1 -1
- package/src/components/launcher.ts +10 -1
- package/src/defaults.ts +18 -0
- package/src/index.ts +10 -2
- package/src/postprocessors.ts +124 -6
- package/src/styles/widget.css +282 -5
- package/src/types.ts +311 -0
- package/src/ui.ts +16 -2
package/dist/widget.css
CHANGED
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
all: initial;
|
|
7
7
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif;
|
|
8
8
|
line-height: 1.5;
|
|
9
|
+
|
|
10
|
+
/* Theme-aware markdown variables - inherit from theme colors set by JavaScript */
|
|
11
|
+
--cw-md-code-block-bg: var(--cw-container, #f3f4f6);
|
|
12
|
+
--cw-md-code-block-border-color: var(--cw-border, #e5e7eb);
|
|
13
|
+
--cw-md-inline-code-bg: var(--cw-container, #f3f4f6);
|
|
14
|
+
--cw-md-table-border-color: var(--cw-border, #e5e7eb);
|
|
15
|
+
--cw-md-table-header-bg: var(--cw-container, #f8fafc);
|
|
16
|
+
--cw-md-hr-color: var(--cw-divider, #e5e7eb);
|
|
17
|
+
--cw-md-blockquote-border-color: var(--cw-accent, #3b82f6);
|
|
18
|
+
--cw-md-blockquote-text-color: var(--cw-muted, #6b7280);
|
|
9
19
|
}
|
|
10
20
|
|
|
11
21
|
#vanilla-agent-root * {
|
|
@@ -86,6 +96,71 @@
|
|
|
86
96
|
--cw-radius-lg: 1.5rem;
|
|
87
97
|
--cw-launcher-radius: 9999px;
|
|
88
98
|
--cw-button-radius: 9999px;
|
|
99
|
+
|
|
100
|
+
/* Markdown Header Variables */
|
|
101
|
+
--cw-md-h1-size: 1.5rem;
|
|
102
|
+
--cw-md-h1-weight: 700;
|
|
103
|
+
--cw-md-h1-margin: 1rem 0 0.5rem;
|
|
104
|
+
--cw-md-h1-line-height: 1.25;
|
|
105
|
+
--cw-md-h2-size: 1.25rem;
|
|
106
|
+
--cw-md-h2-weight: 700;
|
|
107
|
+
--cw-md-h2-margin: 0.875rem 0 0.5rem;
|
|
108
|
+
--cw-md-h2-line-height: 1.3;
|
|
109
|
+
--cw-md-h3-size: 1.125rem;
|
|
110
|
+
--cw-md-h3-weight: 600;
|
|
111
|
+
--cw-md-h3-margin: 0.75rem 0 0.375rem;
|
|
112
|
+
--cw-md-h3-line-height: 1.4;
|
|
113
|
+
--cw-md-h4-size: 1rem;
|
|
114
|
+
--cw-md-h4-weight: 600;
|
|
115
|
+
--cw-md-h4-margin: 0.625rem 0 0.25rem;
|
|
116
|
+
--cw-md-h4-line-height: 1.5;
|
|
117
|
+
--cw-md-h5-size: 0.875rem;
|
|
118
|
+
--cw-md-h5-weight: 600;
|
|
119
|
+
--cw-md-h5-margin: 0.5rem 0 0.25rem;
|
|
120
|
+
--cw-md-h5-line-height: 1.5;
|
|
121
|
+
--cw-md-h6-size: 0.75rem;
|
|
122
|
+
--cw-md-h6-weight: 600;
|
|
123
|
+
--cw-md-h6-margin: 0.5rem 0 0.25rem;
|
|
124
|
+
--cw-md-h6-line-height: 1.5;
|
|
125
|
+
|
|
126
|
+
/* Markdown Table Variables (defaults - theme-aware values set on #vanilla-agent-root) */
|
|
127
|
+
--cw-md-table-border-color: #e5e7eb;
|
|
128
|
+
--cw-md-table-header-bg: #f8fafc;
|
|
129
|
+
--cw-md-table-header-weight: 600;
|
|
130
|
+
--cw-md-table-cell-padding: 0.5rem 0.75rem;
|
|
131
|
+
--cw-md-table-border-radius: 0.375rem;
|
|
132
|
+
|
|
133
|
+
/* Markdown Horizontal Rule Variables (defaults - theme-aware values set on #vanilla-agent-root) */
|
|
134
|
+
--cw-md-hr-color: #e5e7eb;
|
|
135
|
+
--cw-md-hr-height: 1px;
|
|
136
|
+
--cw-md-hr-margin: 1rem 0;
|
|
137
|
+
|
|
138
|
+
/* Markdown Blockquote Variables (defaults - theme-aware values set on #vanilla-agent-root) */
|
|
139
|
+
--cw-md-blockquote-border-color: #3b82f6;
|
|
140
|
+
--cw-md-blockquote-border-width: 3px;
|
|
141
|
+
--cw-md-blockquote-padding: 0.5rem 1rem;
|
|
142
|
+
--cw-md-blockquote-margin: 0.5rem 0;
|
|
143
|
+
--cw-md-blockquote-bg: transparent;
|
|
144
|
+
--cw-md-blockquote-text-color: #6b7280;
|
|
145
|
+
--cw-md-blockquote-font-style: italic;
|
|
146
|
+
|
|
147
|
+
/* Markdown Code Block Variables (defaults - theme-aware values set on #vanilla-agent-root) */
|
|
148
|
+
--cw-md-code-block-bg: #f3f4f6;
|
|
149
|
+
--cw-md-code-block-border-color: #e5e7eb;
|
|
150
|
+
--cw-md-code-block-text-color: inherit;
|
|
151
|
+
--cw-md-code-block-padding: 0.75rem;
|
|
152
|
+
--cw-md-code-block-border-radius: 0.375rem;
|
|
153
|
+
--cw-md-code-block-font-size: 0.875rem;
|
|
154
|
+
|
|
155
|
+
/* Markdown Inline Code Variables (defaults - theme-aware values set on #vanilla-agent-root) */
|
|
156
|
+
--cw-md-inline-code-bg: #f3f4f6;
|
|
157
|
+
--cw-md-inline-code-padding: 0.125rem 0.375rem;
|
|
158
|
+
--cw-md-inline-code-border-radius: 0.25rem;
|
|
159
|
+
--cw-md-inline-code-font-size: 0.875em;
|
|
160
|
+
|
|
161
|
+
/* Markdown Strong/Em Variables */
|
|
162
|
+
--cw-md-strong-weight: 600;
|
|
163
|
+
--cw-md-em-style: italic;
|
|
89
164
|
}
|
|
90
165
|
|
|
91
166
|
.tvw-rounded-xl {
|
|
@@ -803,13 +878,14 @@ form:focus-within textarea {
|
|
|
803
878
|
word-wrap: break-word;
|
|
804
879
|
word-break: break-word;
|
|
805
880
|
white-space: pre-wrap;
|
|
806
|
-
background-color:
|
|
807
|
-
|
|
808
|
-
|
|
881
|
+
background-color: var(--cw-md-code-block-bg);
|
|
882
|
+
color: var(--cw-md-code-block-text-color);
|
|
883
|
+
padding: var(--cw-md-code-block-padding);
|
|
884
|
+
border-radius: var(--cw-md-code-block-border-radius);
|
|
809
885
|
margin: 0.5rem 0;
|
|
810
|
-
font-size:
|
|
886
|
+
font-size: var(--cw-md-code-block-font-size);
|
|
811
887
|
line-height: 1.5;
|
|
812
|
-
border: 1px solid
|
|
888
|
+
border: 1px solid var(--cw-md-code-block-border-color);
|
|
813
889
|
}
|
|
814
890
|
|
|
815
891
|
.vanilla-message-bubble code {
|
|
@@ -938,3 +1014,204 @@ form:focus-within textarea {
|
|
|
938
1014
|
margin: 0.25rem 0;
|
|
939
1015
|
padding-left: 0.25rem;
|
|
940
1016
|
}
|
|
1017
|
+
|
|
1018
|
+
/* ============================================
|
|
1019
|
+
Markdown Header Styles
|
|
1020
|
+
============================================ */
|
|
1021
|
+
.vanilla-message-bubble h1 {
|
|
1022
|
+
font-size: var(--cw-md-h1-size);
|
|
1023
|
+
font-weight: var(--cw-md-h1-weight);
|
|
1024
|
+
margin: var(--cw-md-h1-margin);
|
|
1025
|
+
line-height: var(--cw-md-h1-line-height);
|
|
1026
|
+
color: inherit;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
.vanilla-message-bubble h2 {
|
|
1030
|
+
font-size: var(--cw-md-h2-size);
|
|
1031
|
+
font-weight: var(--cw-md-h2-weight);
|
|
1032
|
+
margin: var(--cw-md-h2-margin);
|
|
1033
|
+
line-height: var(--cw-md-h2-line-height);
|
|
1034
|
+
color: inherit;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
.vanilla-message-bubble h3 {
|
|
1038
|
+
font-size: var(--cw-md-h3-size);
|
|
1039
|
+
font-weight: var(--cw-md-h3-weight);
|
|
1040
|
+
margin: var(--cw-md-h3-margin);
|
|
1041
|
+
line-height: var(--cw-md-h3-line-height);
|
|
1042
|
+
color: inherit;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
.vanilla-message-bubble h4 {
|
|
1046
|
+
font-size: var(--cw-md-h4-size);
|
|
1047
|
+
font-weight: var(--cw-md-h4-weight);
|
|
1048
|
+
margin: var(--cw-md-h4-margin);
|
|
1049
|
+
line-height: var(--cw-md-h4-line-height);
|
|
1050
|
+
color: inherit;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
.vanilla-message-bubble h5 {
|
|
1054
|
+
font-size: var(--cw-md-h5-size);
|
|
1055
|
+
font-weight: var(--cw-md-h5-weight);
|
|
1056
|
+
margin: var(--cw-md-h5-margin);
|
|
1057
|
+
line-height: var(--cw-md-h5-line-height);
|
|
1058
|
+
color: inherit;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.vanilla-message-bubble h6 {
|
|
1062
|
+
font-size: var(--cw-md-h6-size);
|
|
1063
|
+
font-weight: var(--cw-md-h6-weight);
|
|
1064
|
+
margin: var(--cw-md-h6-margin);
|
|
1065
|
+
line-height: var(--cw-md-h6-line-height);
|
|
1066
|
+
color: inherit;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/* Remove top margin on first heading */
|
|
1070
|
+
.vanilla-message-bubble h1:first-child,
|
|
1071
|
+
.vanilla-message-bubble h2:first-child,
|
|
1072
|
+
.vanilla-message-bubble h3:first-child,
|
|
1073
|
+
.vanilla-message-bubble h4:first-child,
|
|
1074
|
+
.vanilla-message-bubble h5:first-child,
|
|
1075
|
+
.vanilla-message-bubble h6:first-child {
|
|
1076
|
+
margin-top: 0;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/* ============================================
|
|
1080
|
+
Markdown Table Styles
|
|
1081
|
+
============================================ */
|
|
1082
|
+
.vanilla-message-bubble table {
|
|
1083
|
+
width: 100%;
|
|
1084
|
+
border-collapse: collapse;
|
|
1085
|
+
margin: 0.5rem 0;
|
|
1086
|
+
font-size: 0.875rem;
|
|
1087
|
+
overflow: hidden;
|
|
1088
|
+
border-radius: var(--cw-md-table-border-radius);
|
|
1089
|
+
border: 1px solid var(--cw-md-table-border-color);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
.vanilla-message-bubble thead {
|
|
1093
|
+
background-color: var(--cw-md-table-header-bg);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
.vanilla-message-bubble th {
|
|
1097
|
+
font-weight: var(--cw-md-table-header-weight);
|
|
1098
|
+
text-align: left;
|
|
1099
|
+
padding: var(--cw-md-table-cell-padding);
|
|
1100
|
+
border-bottom: 1px solid var(--cw-md-table-border-color);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
.vanilla-message-bubble td {
|
|
1104
|
+
padding: var(--cw-md-table-cell-padding);
|
|
1105
|
+
border-bottom: 1px solid var(--cw-md-table-border-color);
|
|
1106
|
+
text-align: left;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.vanilla-message-bubble tr:last-child td {
|
|
1110
|
+
border-bottom: none;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
.vanilla-message-bubble tbody tr:nth-child(even) {
|
|
1114
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
/* ============================================
|
|
1118
|
+
Markdown Horizontal Rule Styles
|
|
1119
|
+
============================================ */
|
|
1120
|
+
.vanilla-message-bubble hr {
|
|
1121
|
+
border: none;
|
|
1122
|
+
height: var(--cw-md-hr-height);
|
|
1123
|
+
background-color: var(--cw-md-hr-color);
|
|
1124
|
+
margin: var(--cw-md-hr-margin);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/* ============================================
|
|
1128
|
+
Markdown Blockquote Styles
|
|
1129
|
+
============================================ */
|
|
1130
|
+
.vanilla-message-bubble blockquote {
|
|
1131
|
+
border-left: var(--cw-md-blockquote-border-width) solid var(--cw-md-blockquote-border-color);
|
|
1132
|
+
padding: var(--cw-md-blockquote-padding);
|
|
1133
|
+
margin: var(--cw-md-blockquote-margin);
|
|
1134
|
+
background-color: var(--cw-md-blockquote-bg);
|
|
1135
|
+
color: var(--cw-md-blockquote-text-color);
|
|
1136
|
+
font-style: var(--cw-md-blockquote-font-style);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
.vanilla-message-bubble blockquote p {
|
|
1140
|
+
margin: 0;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
.vanilla-message-bubble blockquote p + p {
|
|
1144
|
+
margin-top: 0.5rem;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/* Nested blockquotes */
|
|
1148
|
+
.vanilla-message-bubble blockquote blockquote {
|
|
1149
|
+
margin-left: 0.5rem;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/* ============================================
|
|
1153
|
+
Markdown Inline Code Styles (not in pre)
|
|
1154
|
+
============================================ */
|
|
1155
|
+
.vanilla-message-bubble code:not(pre code) {
|
|
1156
|
+
background-color: var(--cw-md-inline-code-bg);
|
|
1157
|
+
padding: var(--cw-md-inline-code-padding);
|
|
1158
|
+
border-radius: var(--cw-md-inline-code-border-radius);
|
|
1159
|
+
font-size: var(--cw-md-inline-code-font-size);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/* ============================================
|
|
1163
|
+
Markdown Strong/Emphasis Styles
|
|
1164
|
+
============================================ */
|
|
1165
|
+
.vanilla-message-bubble strong,
|
|
1166
|
+
.vanilla-message-bubble b {
|
|
1167
|
+
font-weight: var(--cw-md-strong-weight);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.vanilla-message-bubble em,
|
|
1171
|
+
.vanilla-message-bubble i {
|
|
1172
|
+
font-style: var(--cw-md-em-style);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/* ============================================
|
|
1176
|
+
User Message Markdown Overrides
|
|
1177
|
+
Ensure styles work in user bubbles too
|
|
1178
|
+
============================================ */
|
|
1179
|
+
.vanilla-message-user-bubble h1,
|
|
1180
|
+
.vanilla-message-user-bubble h2,
|
|
1181
|
+
.vanilla-message-user-bubble h3,
|
|
1182
|
+
.vanilla-message-user-bubble h4,
|
|
1183
|
+
.vanilla-message-user-bubble h5,
|
|
1184
|
+
.vanilla-message-user-bubble h6 {
|
|
1185
|
+
color: inherit;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
.vanilla-message-user-bubble table {
|
|
1189
|
+
border-color: rgba(255, 255, 255, 0.3);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
.vanilla-message-user-bubble th,
|
|
1193
|
+
.vanilla-message-user-bubble td {
|
|
1194
|
+
border-color: rgba(255, 255, 255, 0.3);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
.vanilla-message-user-bubble thead {
|
|
1198
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
.vanilla-message-user-bubble tbody tr:nth-child(even) {
|
|
1202
|
+
background-color: rgba(255, 255, 255, 0.05);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
.vanilla-message-user-bubble hr {
|
|
1206
|
+
background-color: rgba(255, 255, 255, 0.3);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
.vanilla-message-user-bubble blockquote {
|
|
1210
|
+
border-left-color: rgba(255, 255, 255, 0.5);
|
|
1211
|
+
color: inherit;
|
|
1212
|
+
opacity: 0.9;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.vanilla-message-user-bubble code:not(pre code) {
|
|
1216
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
1217
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Themeable, plugable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -158,10 +158,19 @@ export const createLauncherButton = (
|
|
|
158
158
|
? positionMap[launcher.position]
|
|
159
159
|
: positionMap["bottom-right"];
|
|
160
160
|
|
|
161
|
+
// Removed hardcoded border/shadow classes (tvw-shadow-lg, tvw-border, tvw-border-gray-200)
|
|
162
|
+
// These are now applied via inline styles from config
|
|
161
163
|
const base =
|
|
162
|
-
"tvw-fixed tvw-flex tvw-items-center tvw-gap-3 tvw-rounded-launcher tvw-bg-cw-surface tvw-py-2.5 tvw-pl-3 tvw-pr-3 tvw-
|
|
164
|
+
"tvw-fixed tvw-flex tvw-items-center tvw-gap-3 tvw-rounded-launcher tvw-bg-cw-surface tvw-py-2.5 tvw-pl-3 tvw-pr-3 tvw-transition hover:tvw-translate-y-[-2px] tvw-cursor-pointer tvw-z-50";
|
|
163
165
|
|
|
164
166
|
button.className = `${base} ${positionClass}`;
|
|
167
|
+
|
|
168
|
+
// Apply launcher border and shadow from config (with defaults matching previous Tailwind classes)
|
|
169
|
+
const defaultBorder = "1px solid #e5e7eb";
|
|
170
|
+
const defaultShadow = "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)";
|
|
171
|
+
|
|
172
|
+
button.style.border = launcher.border ?? defaultBorder;
|
|
173
|
+
button.style.boxShadow = launcher.shadow ?? defaultShadow;
|
|
165
174
|
};
|
|
166
175
|
|
|
167
176
|
const destroy = () => {
|
package/src/defaults.ts
CHANGED
|
@@ -48,6 +48,7 @@ export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
|
|
|
48
48
|
agentIconText: "💬",
|
|
49
49
|
position: "bottom-right",
|
|
50
50
|
width: "min(400px, calc(100vw - 24px))",
|
|
51
|
+
heightOffset: 0,
|
|
51
52
|
autoExpand: false,
|
|
52
53
|
callToActionIconHidden: false,
|
|
53
54
|
agentIconSize: "40px",
|
|
@@ -75,6 +76,8 @@ export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
|
|
|
75
76
|
paddingY: "0px",
|
|
76
77
|
},
|
|
77
78
|
headerIconHidden: false,
|
|
79
|
+
border: "1px solid #e5e7eb",
|
|
80
|
+
shadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
|
|
78
81
|
},
|
|
79
82
|
copy: {
|
|
80
83
|
welcomeTitle: "Hello 👋",
|
|
@@ -158,6 +161,13 @@ export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
|
|
|
158
161
|
},
|
|
159
162
|
slots: {},
|
|
160
163
|
},
|
|
164
|
+
markdown: {
|
|
165
|
+
options: {
|
|
166
|
+
gfm: true,
|
|
167
|
+
breaks: true,
|
|
168
|
+
},
|
|
169
|
+
disableDefaultStyles: false,
|
|
170
|
+
},
|
|
161
171
|
debug: false,
|
|
162
172
|
};
|
|
163
173
|
|
|
@@ -234,5 +244,13 @@ export function mergeWithDefaults(
|
|
|
234
244
|
...config.layout?.slots,
|
|
235
245
|
},
|
|
236
246
|
},
|
|
247
|
+
markdown: {
|
|
248
|
+
...DEFAULT_WIDGET_CONFIG.markdown,
|
|
249
|
+
...config.markdown,
|
|
250
|
+
options: {
|
|
251
|
+
...DEFAULT_WIDGET_CONFIG.markdown?.options,
|
|
252
|
+
...config.markdown?.options,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
237
255
|
};
|
|
238
256
|
}
|
package/src/index.ts
CHANGED
|
@@ -28,7 +28,11 @@ export type {
|
|
|
28
28
|
SlotRenderer,
|
|
29
29
|
SlotRenderContext,
|
|
30
30
|
HeaderRenderContext,
|
|
31
|
-
MessageRenderContext
|
|
31
|
+
MessageRenderContext,
|
|
32
|
+
// Markdown types
|
|
33
|
+
AgentWidgetMarkdownConfig,
|
|
34
|
+
AgentWidgetMarkdownOptions,
|
|
35
|
+
AgentWidgetMarkdownRendererOverrides
|
|
32
36
|
} from "./types";
|
|
33
37
|
|
|
34
38
|
export { initAgentWidgetFn as initAgentWidget };
|
|
@@ -50,8 +54,12 @@ export {
|
|
|
50
54
|
export {
|
|
51
55
|
markdownPostprocessor,
|
|
52
56
|
escapeHtml,
|
|
53
|
-
directivePostprocessor
|
|
57
|
+
directivePostprocessor,
|
|
58
|
+
createMarkdownProcessor,
|
|
59
|
+
createMarkdownProcessorFromConfig,
|
|
60
|
+
createDirectivePostprocessor
|
|
54
61
|
} from "./postprocessors";
|
|
62
|
+
export type { MarkdownProcessorOptions } from "./postprocessors";
|
|
55
63
|
export {
|
|
56
64
|
createPlainTextParser,
|
|
57
65
|
createJsonStreamParser,
|
package/src/postprocessors.ts
CHANGED
|
@@ -1,13 +1,100 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Marked, type RendererObject } from "marked";
|
|
2
|
+
import type { AgentWidgetMarkdownConfig, AgentWidgetMarkdownRendererOverrides, AgentWidgetMarkdownOptions } from "./types";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Options for creating a markdown processor
|
|
6
|
+
*/
|
|
7
|
+
export type MarkdownProcessorOptions = {
|
|
8
|
+
/** Marked parsing options */
|
|
9
|
+
markedOptions?: AgentWidgetMarkdownOptions;
|
|
10
|
+
/** Custom renderer overrides */
|
|
11
|
+
renderer?: AgentWidgetMarkdownRendererOverrides;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Converts AgentWidgetMarkdownRendererOverrides to marked's RendererObject format
|
|
16
|
+
*/
|
|
17
|
+
const convertRendererOverrides = (
|
|
18
|
+
overrides?: AgentWidgetMarkdownRendererOverrides
|
|
19
|
+
): Partial<RendererObject> | undefined => {
|
|
20
|
+
if (!overrides) return undefined;
|
|
21
|
+
|
|
22
|
+
// The token-based API in marked v12+ matches our type definitions
|
|
23
|
+
// We can pass through the overrides directly
|
|
24
|
+
return overrides as Partial<RendererObject>;
|
|
25
|
+
};
|
|
4
26
|
|
|
5
27
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
28
|
+
* Creates a configured markdown processor with custom options and renderers.
|
|
29
|
+
*
|
|
30
|
+
* @param options - Configuration options for the markdown processor
|
|
31
|
+
* @returns A function that converts markdown text to HTML
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* // Basic usage with defaults
|
|
36
|
+
* const processor = createMarkdownProcessor();
|
|
37
|
+
* const html = processor("# Hello World");
|
|
38
|
+
*
|
|
39
|
+
* // With custom options
|
|
40
|
+
* const processor = createMarkdownProcessor({
|
|
41
|
+
* markedOptions: { gfm: true, breaks: true },
|
|
42
|
+
* renderer: {
|
|
43
|
+
* link(token) {
|
|
44
|
+
* return `<a href="${token.href}" target="_blank">${token.text}</a>`;
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export const createMarkdownProcessor = (options?: MarkdownProcessorOptions) => {
|
|
51
|
+
const opts = options?.markedOptions;
|
|
52
|
+
const markedInstance = new Marked({
|
|
53
|
+
gfm: opts?.gfm ?? true,
|
|
54
|
+
breaks: opts?.breaks ?? true,
|
|
55
|
+
pedantic: opts?.pedantic,
|
|
56
|
+
silent: opts?.silent,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const rendererOverrides = convertRendererOverrides(options?.renderer);
|
|
60
|
+
if (rendererOverrides) {
|
|
61
|
+
markedInstance.use({ renderer: rendererOverrides });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return (text: string): string => {
|
|
65
|
+
return markedInstance.parse(text) as string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Creates a markdown processor from AgentWidgetMarkdownConfig.
|
|
71
|
+
* This is a convenience function that maps the widget config to processor options.
|
|
72
|
+
*
|
|
73
|
+
* @param config - The markdown configuration from widget config
|
|
74
|
+
* @returns A function that converts markdown text to HTML
|
|
75
|
+
*/
|
|
76
|
+
export const createMarkdownProcessorFromConfig = (config?: AgentWidgetMarkdownConfig) => {
|
|
77
|
+
if (!config) {
|
|
78
|
+
return createMarkdownProcessor();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return createMarkdownProcessor({
|
|
82
|
+
markedOptions: config.options,
|
|
83
|
+
renderer: config.renderer,
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Create default markdown processor instance
|
|
88
|
+
const defaultMarkdownProcessor = createMarkdownProcessor();
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Basic markdown renderer using default settings.
|
|
92
|
+
* Remember to sanitize the returned HTML if you render untrusted content in your host page.
|
|
93
|
+
*
|
|
94
|
+
* For custom configuration, use `createMarkdownProcessor()` or `createMarkdownProcessorFromConfig()`.
|
|
8
95
|
*/
|
|
9
96
|
export const markdownPostprocessor = (text: string): string => {
|
|
10
|
-
return
|
|
97
|
+
return defaultMarkdownProcessor(text);
|
|
11
98
|
};
|
|
12
99
|
|
|
13
100
|
/**
|
|
@@ -54,11 +141,42 @@ const directiveReplacer = (source: string, placeholders: Array<{ token: string;
|
|
|
54
141
|
return working;
|
|
55
142
|
};
|
|
56
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Creates a directive postprocessor with custom markdown configuration.
|
|
146
|
+
* Converts special directives (either `<Form type="init" />` or
|
|
147
|
+
* `<Directive>{"component":"form","type":"init"}</Directive>`) into placeholder
|
|
148
|
+
* elements that the widget upgrades after render. Remaining text is rendered as
|
|
149
|
+
* Markdown with the provided configuration.
|
|
150
|
+
*
|
|
151
|
+
* @param markdownConfig - Optional markdown configuration
|
|
152
|
+
* @returns A function that processes text with directives and markdown
|
|
153
|
+
*/
|
|
154
|
+
export const createDirectivePostprocessor = (markdownConfig?: AgentWidgetMarkdownConfig) => {
|
|
155
|
+
const processor = createMarkdownProcessorFromConfig(markdownConfig);
|
|
156
|
+
|
|
157
|
+
return (text: string): string => {
|
|
158
|
+
const placeholders: Array<{ token: string; type: string }> = [];
|
|
159
|
+
const withTokens = directiveReplacer(text, placeholders);
|
|
160
|
+
let html = processor(withTokens);
|
|
161
|
+
|
|
162
|
+
placeholders.forEach(({ token, type }) => {
|
|
163
|
+
const tokenRegex = new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
|
|
164
|
+
const safeType = escapeAttribute(type);
|
|
165
|
+
const replacement = `<div class="tvw-form-directive" data-tv-form="${safeType}"></div>`;
|
|
166
|
+
html = html.replace(tokenRegex, replacement);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return html;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
|
|
57
173
|
/**
|
|
58
174
|
* Converts special directives (either `<Form type="init" />` or
|
|
59
175
|
* `<Directive>{"component":"form","type":"init"}</Directive>`) into placeholder
|
|
60
176
|
* elements that the widget upgrades after render. Remaining text is rendered as
|
|
61
|
-
* Markdown.
|
|
177
|
+
* Markdown using default settings.
|
|
178
|
+
*
|
|
179
|
+
* For custom markdown configuration, use `createDirectivePostprocessor()`.
|
|
62
180
|
*/
|
|
63
181
|
export const directivePostprocessor = (text: string): string => {
|
|
64
182
|
const placeholders: Array<{ token: string; type: string }> = [];
|