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.
@@ -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: #f3f4f6;
807
- padding: 0.75rem;
808
- border-radius: 0.375rem;
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: 0.875rem;
886
+ font-size: var(--cw-md-code-block-font-size);
811
887
  line-height: 1.5;
812
- border: 1px solid #e5e7eb;
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/src/types.ts CHANGED
@@ -217,6 +217,14 @@ export type AgentWidgetLauncherConfig = {
217
217
  * @default "420px"
218
218
  */
219
219
  sidebarWidth?: string;
220
+ /**
221
+ * Offset (in pixels) to subtract from the calculated panel height.
222
+ * Useful for adjusting the panel height when there are other fixed elements on the page.
223
+ * Only applies when not in fullHeight or sidebarMode.
224
+ *
225
+ * @default 0
226
+ */
227
+ heightOffset?: number;
220
228
  callToActionIconText?: string;
221
229
  callToActionIconName?: string;
222
230
  callToActionIconColor?: string;
@@ -242,6 +250,18 @@ export type AgentWidgetLauncherConfig = {
242
250
  closeButtonTooltipText?: string;
243
251
  closeButtonShowTooltip?: boolean;
244
252
  clearChat?: AgentWidgetClearChatConfig;
253
+ /**
254
+ * Border style for the launcher button.
255
+ * @example "1px solid #e5e7eb" | "2px solid #3b82f6" | "none"
256
+ * @default "1px solid #e5e7eb"
257
+ */
258
+ border?: string;
259
+ /**
260
+ * Box shadow for the launcher button.
261
+ * @example "0 10px 15px -3px rgba(0,0,0,0.1)" | "none"
262
+ * @default "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)"
263
+ */
264
+ shadow?: string;
245
265
  };
246
266
 
247
267
  export type AgentWidgetSendButtonConfig = {
@@ -602,6 +622,271 @@ export type AgentWidgetLayoutConfig = {
602
622
  slots?: Partial<Record<WidgetLayoutSlot, SlotRenderer>>;
603
623
  };
604
624
 
625
+ // ============================================================================
626
+ // Markdown Configuration Types
627
+ // ============================================================================
628
+
629
+ /**
630
+ * Token types for marked renderer methods
631
+ */
632
+ export type AgentWidgetMarkdownHeadingToken = {
633
+ type: "heading";
634
+ raw: string;
635
+ depth: 1 | 2 | 3 | 4 | 5 | 6;
636
+ text: string;
637
+ tokens: unknown[];
638
+ };
639
+
640
+ export type AgentWidgetMarkdownCodeToken = {
641
+ type: "code";
642
+ raw: string;
643
+ text: string;
644
+ lang?: string;
645
+ escaped?: boolean;
646
+ };
647
+
648
+ export type AgentWidgetMarkdownBlockquoteToken = {
649
+ type: "blockquote";
650
+ raw: string;
651
+ text: string;
652
+ tokens: unknown[];
653
+ };
654
+
655
+ export type AgentWidgetMarkdownTableToken = {
656
+ type: "table";
657
+ raw: string;
658
+ header: Array<{ text: string; tokens: unknown[] }>;
659
+ rows: Array<Array<{ text: string; tokens: unknown[] }>>;
660
+ align: Array<"left" | "center" | "right" | null>;
661
+ };
662
+
663
+ export type AgentWidgetMarkdownLinkToken = {
664
+ type: "link";
665
+ raw: string;
666
+ href: string;
667
+ title: string | null;
668
+ text: string;
669
+ tokens: unknown[];
670
+ };
671
+
672
+ export type AgentWidgetMarkdownImageToken = {
673
+ type: "image";
674
+ raw: string;
675
+ href: string;
676
+ title: string | null;
677
+ text: string;
678
+ };
679
+
680
+ export type AgentWidgetMarkdownListToken = {
681
+ type: "list";
682
+ raw: string;
683
+ ordered: boolean;
684
+ start: number | "";
685
+ loose: boolean;
686
+ items: unknown[];
687
+ };
688
+
689
+ export type AgentWidgetMarkdownListItemToken = {
690
+ type: "list_item";
691
+ raw: string;
692
+ task: boolean;
693
+ checked?: boolean;
694
+ loose: boolean;
695
+ text: string;
696
+ tokens: unknown[];
697
+ };
698
+
699
+ export type AgentWidgetMarkdownParagraphToken = {
700
+ type: "paragraph";
701
+ raw: string;
702
+ text: string;
703
+ tokens: unknown[];
704
+ };
705
+
706
+ export type AgentWidgetMarkdownCodespanToken = {
707
+ type: "codespan";
708
+ raw: string;
709
+ text: string;
710
+ };
711
+
712
+ export type AgentWidgetMarkdownStrongToken = {
713
+ type: "strong";
714
+ raw: string;
715
+ text: string;
716
+ tokens: unknown[];
717
+ };
718
+
719
+ export type AgentWidgetMarkdownEmToken = {
720
+ type: "em";
721
+ raw: string;
722
+ text: string;
723
+ tokens: unknown[];
724
+ };
725
+
726
+ /**
727
+ * Custom renderer overrides for markdown elements.
728
+ * Each method receives the token and should return an HTML string.
729
+ * Return `false` to use the default renderer.
730
+ *
731
+ * @example
732
+ * ```typescript
733
+ * renderer: {
734
+ * heading(token) {
735
+ * return `<h${token.depth} class="custom-heading">${token.text}</h${token.depth}>`;
736
+ * },
737
+ * link(token) {
738
+ * return `<a href="${token.href}" target="_blank" rel="noopener">${token.text}</a>`;
739
+ * }
740
+ * }
741
+ * ```
742
+ */
743
+ export type AgentWidgetMarkdownRendererOverrides = {
744
+ /** Override heading rendering (h1-h6) */
745
+ heading?: (token: AgentWidgetMarkdownHeadingToken) => string | false;
746
+ /** Override code block rendering */
747
+ code?: (token: AgentWidgetMarkdownCodeToken) => string | false;
748
+ /** Override blockquote rendering */
749
+ blockquote?: (token: AgentWidgetMarkdownBlockquoteToken) => string | false;
750
+ /** Override table rendering */
751
+ table?: (token: AgentWidgetMarkdownTableToken) => string | false;
752
+ /** Override link rendering */
753
+ link?: (token: AgentWidgetMarkdownLinkToken) => string | false;
754
+ /** Override image rendering */
755
+ image?: (token: AgentWidgetMarkdownImageToken) => string | false;
756
+ /** Override list rendering (ul/ol) */
757
+ list?: (token: AgentWidgetMarkdownListToken) => string | false;
758
+ /** Override list item rendering */
759
+ listitem?: (token: AgentWidgetMarkdownListItemToken) => string | false;
760
+ /** Override paragraph rendering */
761
+ paragraph?: (token: AgentWidgetMarkdownParagraphToken) => string | false;
762
+ /** Override inline code rendering */
763
+ codespan?: (token: AgentWidgetMarkdownCodespanToken) => string | false;
764
+ /** Override strong/bold rendering */
765
+ strong?: (token: AgentWidgetMarkdownStrongToken) => string | false;
766
+ /** Override emphasis/italic rendering */
767
+ em?: (token: AgentWidgetMarkdownEmToken) => string | false;
768
+ /** Override horizontal rule rendering */
769
+ hr?: () => string | false;
770
+ /** Override line break rendering */
771
+ br?: () => string | false;
772
+ /** Override deleted/strikethrough rendering */
773
+ del?: (token: { type: "del"; raw: string; text: string; tokens: unknown[] }) => string | false;
774
+ /** Override checkbox rendering (in task lists) */
775
+ checkbox?: (token: { checked: boolean }) => string | false;
776
+ /** Override HTML passthrough */
777
+ html?: (token: { type: "html"; raw: string; text: string }) => string | false;
778
+ /** Override text rendering */
779
+ text?: (token: { type: "text"; raw: string; text: string }) => string | false;
780
+ };
781
+
782
+ /**
783
+ * Markdown parsing options (subset of marked options)
784
+ */
785
+ export type AgentWidgetMarkdownOptions = {
786
+ /**
787
+ * Enable GitHub Flavored Markdown (tables, strikethrough, autolinks).
788
+ * @default true
789
+ */
790
+ gfm?: boolean;
791
+ /**
792
+ * Convert \n in paragraphs into <br>.
793
+ * @default true
794
+ */
795
+ breaks?: boolean;
796
+ /**
797
+ * Conform to original markdown.pl as much as possible.
798
+ * @default false
799
+ */
800
+ pedantic?: boolean;
801
+ /**
802
+ * Add id attributes to headings.
803
+ * @default false
804
+ */
805
+ headerIds?: boolean;
806
+ /**
807
+ * Prefix for heading id attributes.
808
+ * @default ""
809
+ */
810
+ headerPrefix?: string;
811
+ /**
812
+ * Mangle email addresses for spam protection.
813
+ * @default true
814
+ */
815
+ mangle?: boolean;
816
+ /**
817
+ * Silent mode - don't throw on parse errors.
818
+ * @default false
819
+ */
820
+ silent?: boolean;
821
+ };
822
+
823
+ /**
824
+ * Markdown configuration for customizing how markdown is rendered in chat messages.
825
+ * Provides three levels of control:
826
+ *
827
+ * 1. **CSS Variables** - Override styles via `--cw-md-*` CSS custom properties
828
+ * 2. **Parsing Options** - Configure marked behavior via `options`
829
+ * 3. **Custom Renderers** - Full control via `renderer` overrides
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * // Level 2: Configure parsing options
834
+ * config: {
835
+ * markdown: {
836
+ * options: {
837
+ * gfm: true,
838
+ * breaks: true,
839
+ * headerIds: true
840
+ * }
841
+ * }
842
+ * }
843
+ * ```
844
+ *
845
+ * @example
846
+ * ```typescript
847
+ * // Level 3: Custom renderers
848
+ * config: {
849
+ * markdown: {
850
+ * renderer: {
851
+ * heading(token) {
852
+ * return `<h${token.depth} class="custom-h${token.depth}">${token.text}</h${token.depth}>`;
853
+ * },
854
+ * link(token) {
855
+ * return `<a href="${token.href}" target="_blank">${token.text}</a>`;
856
+ * },
857
+ * table(token) {
858
+ * // Wrap tables in a scrollable container
859
+ * return `<div class="table-scroll">${this.parser.parse(token.tokens)}</div>`;
860
+ * }
861
+ * }
862
+ * }
863
+ * }
864
+ * ```
865
+ */
866
+ export type AgentWidgetMarkdownConfig = {
867
+ /**
868
+ * Markdown parsing options.
869
+ * These are passed directly to the marked parser.
870
+ */
871
+ options?: AgentWidgetMarkdownOptions;
872
+
873
+ /**
874
+ * Custom renderer overrides for specific markdown elements.
875
+ * Each method receives a token object and should return an HTML string.
876
+ * Return `false` to fall back to the default renderer.
877
+ */
878
+ renderer?: AgentWidgetMarkdownRendererOverrides;
879
+
880
+ /**
881
+ * Disable default markdown CSS styles.
882
+ * When true, the widget won't apply any default styles to markdown elements,
883
+ * allowing you to provide your own CSS.
884
+ *
885
+ * @default false
886
+ */
887
+ disableDefaultStyles?: boolean;
888
+ };
889
+
605
890
  export type AgentWidgetConfig = {
606
891
  apiUrl?: string;
607
892
  flowId?: string;
@@ -811,6 +1096,32 @@ export type AgentWidgetConfig = {
811
1096
  * ```
812
1097
  */
813
1098
  layout?: AgentWidgetLayoutConfig;
1099
+
1100
+ /**
1101
+ * Markdown rendering configuration.
1102
+ * Customize how markdown is parsed and rendered in chat messages.
1103
+ *
1104
+ * Override methods:
1105
+ * 1. **CSS Variables** - Override `--cw-md-*` variables in your stylesheet
1106
+ * 2. **Options** - Configure marked parser behavior
1107
+ * 3. **Renderers** - Custom rendering functions for specific elements
1108
+ * 4. **postprocessMessage** - Complete control over message transformation
1109
+ *
1110
+ * @example
1111
+ * ```typescript
1112
+ * config: {
1113
+ * markdown: {
1114
+ * options: { breaks: true, gfm: true },
1115
+ * renderer: {
1116
+ * link(token) {
1117
+ * return `<a href="${token.href}" target="_blank">${token.text}</a>`;
1118
+ * }
1119
+ * }
1120
+ * }
1121
+ * }
1122
+ * ```
1123
+ */
1124
+ markdown?: AgentWidgetMarkdownConfig;
814
1125
  };
815
1126
 
816
1127
  export type AgentWidgetMessageRole = "user" | "assistant" | "system";
package/src/ui.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { escapeHtml } from "./postprocessors";
1
+ import { escapeHtml, createMarkdownProcessorFromConfig } from "./postprocessors";
2
2
  import { AgentWidgetSession, AgentWidgetSessionStatus } from "./session";
3
3
  import {
4
4
  AgentWidgetConfig,
@@ -96,6 +96,12 @@ const buildPostprocessor = (
96
96
  cfg: AgentWidgetConfig | undefined,
97
97
  actionManager?: ReturnType<typeof createActionManager>
98
98
  ): MessageTransform => {
99
+ // Create markdown processor from config if markdown config is provided
100
+ // This allows users to enable markdown rendering via config.markdown
101
+ const markdownProcessor = cfg?.markdown
102
+ ? createMarkdownProcessorFromConfig(cfg.markdown)
103
+ : null;
104
+
99
105
  return (context) => {
100
106
  let nextText = context.text ?? "";
101
107
  const rawPayload = context.message.rawContent ?? null;
@@ -116,6 +122,7 @@ const buildPostprocessor = (
116
122
  }
117
123
  }
118
124
 
125
+ // Priority: postprocessMessage > markdown config > escapeHtml
119
126
  if (cfg?.postprocessMessage) {
120
127
  return cfg.postprocessMessage({
121
128
  ...context,
@@ -124,6 +131,11 @@ const buildPostprocessor = (
124
131
  });
125
132
  }
126
133
 
134
+ // Use markdown processor if markdown config is provided
135
+ if (markdownProcessor) {
136
+ return markdownProcessor(nextText);
137
+ }
138
+
127
139
  return escapeHtml(nextText);
128
140
  };
129
141
  };
@@ -1592,9 +1604,11 @@ export const createAgentExperience = (
1592
1604
  if (!fullHeight) {
1593
1605
  const viewportHeight = window.innerHeight;
1594
1606
  const verticalMargin = 64; // leave space for launcher's offset
1607
+ const heightOffset = config.launcher?.heightOffset ?? 0;
1595
1608
  const available = Math.max(200, viewportHeight - verticalMargin);
1596
1609
  const clamped = Math.min(640, available);
1597
- panel.style.height = `${clamped}px`;
1610
+ const finalHeight = Math.max(200, clamped - heightOffset);
1611
+ panel.style.height = `${finalHeight}px`;
1598
1612
  }
1599
1613
  };
1600
1614