@kieksme/csp-plugin-chat 0.12.1 → 0.13.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/README.md CHANGED
@@ -31,3 +31,7 @@ Users can mark a chat **Problem gelöst** and start a new chat afterward. With a
31
31
  The assistant asks one short clarifying question for vague requests (for example “Hallo, meine Email”) before offering tickets. It uses supplied help/status facts and reserves ticket links for escalation or an explicit ticket request. Model behaviour requires a real-provider acceptance test.
32
32
 
33
33
  Long histories follow new messages while the visitor reads at the bottom; scrolling up preserves the reading position and offers **Neue Nachrichten ↓**. Real OpenAI providers expose editable dictation through the server-only transcription API. With a support transport, **Ich möchte mit einer echten Person sprechen** pauses the bot immediately and queues a persistent, directed support request. See [chat behaviour and APIs](../../docs/chat.md) and [runtime options](../../docs/configuration.md#spracheingabe-und-supportanfragen).
34
+
35
+ Both chat modes share a service-chat header and composer. Visitor messages align to the right, assistant and human replies to the left with visible sender labels. Customer theme colours, dark mode and mobile layouts apply throughout. See [chat design](../../docs/chat.md#gestaltung).
36
+
37
+ Dictation uses an icon-only microphone button with the accessible name and tooltip “Nachricht diktieren”. Its privacy notice stays visible alongside the button, and mobile touch targets remain 44 × 44 px.
package/dist/browser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cspPlugin
3
- } from "./chunk-U2H5BQCV.js";
3
+ } from "./chunk-B7EKNOQK.js";
4
4
 
5
5
  // src/tools.ts
6
6
  import {
@@ -309,7 +309,7 @@ function sendShortcut(event, disabled) {
309
309
  function Shortcut({ id }) {
310
310
  const [mac, setMac] = useState(false);
311
311
  useEffect(() => setMac(/Mac|iPhone|iPad/.test(navigator.platform)), []);
312
- return /* @__PURE__ */ jsxs("span", { id, className: "block text-[0.6875rem] text-muted mt-2", children: [
312
+ return /* @__PURE__ */ jsxs("span", { id, className: "chat-shortcut", children: [
313
313
  mac ? "\u2318" : "Strg",
314
314
  " Enter zum Senden"
315
315
  ] });
@@ -353,15 +353,46 @@ function NewMessages({
353
353
  visible,
354
354
  follow
355
355
  }) {
356
- return visible ? /* @__PURE__ */ jsx(
357
- "button",
358
- {
359
- type: "button",
360
- className: "border border-line rounded-card px-3 py-2 mb-3 text-[0.8125rem]",
361
- onClick: follow,
362
- children: "Neue Nachrichten \u2193"
363
- }
364
- ) : null;
356
+ return visible ? /* @__PURE__ */ jsx("button", { type: "button", className: "chat-new-messages", onClick: follow, children: "Neue Nachrichten \u2193" }) : null;
357
+ }
358
+ function ChatHeading({
359
+ status,
360
+ state = "bot",
361
+ notice,
362
+ headingLevel = 2
363
+ }) {
364
+ const Heading = headingLevel === 2 ? "h2" : "h3";
365
+ return /* @__PURE__ */ jsxs("header", { className: "chat-heading", "data-state": state, children: [
366
+ /* @__PURE__ */ jsx("span", { className: "chat-emblem", "aria-hidden": "true", children: /* @__PURE__ */ jsxs(
367
+ "svg",
368
+ {
369
+ viewBox: "0 0 24 24",
370
+ fill: "none",
371
+ stroke: "currentColor",
372
+ strokeWidth: "1.6",
373
+ children: [
374
+ /* @__PURE__ */ jsx("path", { d: "M5 10a7 7 0 0 1 14 0v6a3 3 0 0 1-3 3h-4" }),
375
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "10", width: "4", height: "7", rx: "2" }),
376
+ /* @__PURE__ */ jsx("rect", { x: "17", y: "10", width: "4", height: "7", rx: "2" }),
377
+ /* @__PURE__ */ jsx("path", { d: "M10 19h3" })
378
+ ]
379
+ }
380
+ ) }),
381
+ /* @__PURE__ */ jsxs("div", { className: "chat-heading-copy", children: [
382
+ /* @__PURE__ */ jsx(Heading, { children: "Service-Chat" }),
383
+ /* @__PURE__ */ jsxs("p", { className: "chat-status", role: "status", children: [
384
+ /* @__PURE__ */ jsx("span", { className: "chat-status-dot", "aria-hidden": "true" }),
385
+ status
386
+ ] }),
387
+ notice && /* @__PURE__ */ jsx("p", { className: "chat-notice", children: notice })
388
+ ] })
389
+ ] });
390
+ }
391
+ function ChatWelcome() {
392
+ return /* @__PURE__ */ jsxs("div", { className: "chat-welcome", children: [
393
+ /* @__PURE__ */ jsx("p", { className: "chat-welcome-title", children: "Was k\xF6nnen wir f\xFCr Sie tun?" }),
394
+ /* @__PURE__ */ jsx("p", { children: "Beschreiben Sie kurz Ihr Anliegen. Wir helfen Ihnen Schritt f\xFCr Schritt weiter." })
395
+ ] });
365
396
  }
366
397
 
367
398
  // src/voice-input.tsx
@@ -543,67 +574,73 @@ function VoiceInput({
543
574
  }
544
575
  }
545
576
  if (!enabled) return null;
546
- return /* @__PURE__ */ jsxs2("div", { className: "mt-3 text-[0.8125rem]", children: [
547
- state === "idle" ? /* @__PURE__ */ jsxs2(
548
- "button",
549
- {
550
- type: "button",
551
- className: "border border-line rounded-card px-3 py-2",
552
- disabled,
553
- onClick: () => void start(),
554
- children: [
555
- /* @__PURE__ */ jsxs2(
556
- "svg",
577
+ return /* @__PURE__ */ jsxs2(
578
+ "div",
579
+ {
580
+ className: "chat-voice",
581
+ "data-state": state,
582
+ "data-recording": state === "recording",
583
+ children: [
584
+ state === "idle" ? /* @__PURE__ */ jsx2(
585
+ "button",
586
+ {
587
+ type: "button",
588
+ className: "chat-voice-button chat-microphone",
589
+ "aria-label": "Nachricht diktieren",
590
+ title: "Nachricht diktieren",
591
+ disabled,
592
+ onClick: () => void start(),
593
+ children: /* @__PURE__ */ jsxs2(
594
+ "svg",
595
+ {
596
+ "aria-hidden": "true",
597
+ viewBox: "0 0 24 24",
598
+ width: "16",
599
+ height: "16",
600
+ fill: "none",
601
+ stroke: "currentColor",
602
+ strokeWidth: "2",
603
+ children: [
604
+ /* @__PURE__ */ jsx2("rect", { x: "9", y: "2", width: "6", height: "12", rx: "3" }),
605
+ /* @__PURE__ */ jsx2("path", { d: "M5 10v2a7 7 0 0 0 14 0v-2M12 19v3M8 22h8" })
606
+ ]
607
+ }
608
+ )
609
+ }
610
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
611
+ /* @__PURE__ */ jsx2("span", { role: "status", className: "chat-voice-status", children: state === "recording" ? "\u25CF Aufnahme l\xE4uft \xB7 maximal 60 Sekunden" : state === "starting" ? "Mikrofon wird gestartet \u2026" : "Sprache wird in Text umgewandelt \u2026" }),
612
+ state === "recording" && /* @__PURE__ */ jsx2(
613
+ "button",
557
614
  {
558
- "aria-hidden": "true",
559
- viewBox: "0 0 24 24",
560
- width: "16",
561
- height: "16",
562
- className: "inline mr-2",
563
- fill: "none",
564
- stroke: "currentColor",
565
- strokeWidth: "2",
566
- children: [
567
- /* @__PURE__ */ jsx2("rect", { x: "9", y: "2", width: "6", height: "12", rx: "3" }),
568
- /* @__PURE__ */ jsx2("path", { d: "M5 10v2a7 7 0 0 0 14 0v-2M12 19v3M8 22h8" })
569
- ]
615
+ type: "button",
616
+ className: "chat-voice-button",
617
+ onClick: () => recorder.current?.stop(),
618
+ children: "Aufnahme stoppen"
570
619
  }
571
620
  ),
572
- "Nachricht diktieren"
573
- ]
574
- }
575
- ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
576
- /* @__PURE__ */ jsx2("span", { role: "status", children: state === "recording" ? "\u25CF Aufnahme l\xE4uft \xB7 maximal 60 Sekunden" : state === "starting" ? "Mikrofon wird gestartet \u2026" : "Sprache wird in Text umgewandelt \u2026" }),
577
- state === "recording" && /* @__PURE__ */ jsx2(
578
- "button",
579
- {
580
- type: "button",
581
- className: "border border-line rounded-card px-3 py-2 ml-2",
582
- onClick: () => recorder.current?.stop(),
583
- children: "Aufnahme stoppen"
584
- }
585
- ),
586
- /* @__PURE__ */ jsx2(
587
- "button",
588
- {
589
- type: "button",
590
- className: "underline ml-2",
591
- onClick: () => {
592
- operation.current++;
593
- cancelled.current = true;
594
- request.current?.abort();
595
- if (recorder.current?.state === "recording")
596
- recorder.current.stop();
597
- release();
598
- idle();
599
- },
600
- children: "Abbrechen"
601
- }
602
- )
603
- ] }),
604
- /* @__PURE__ */ jsx2("p", { className: "text-[0.6875rem] text-muted mt-2", children: "Die Aufnahme wird zur Texterkennung an OpenAI gesendet. Pr\xFCfen Sie den Text vor dem Senden." }),
605
- error && /* @__PURE__ */ jsx2("p", { role: "alert", className: "text-danger dark:text-warning mt-2", children: error })
606
- ] });
621
+ /* @__PURE__ */ jsx2(
622
+ "button",
623
+ {
624
+ type: "button",
625
+ className: "chat-voice-cancel",
626
+ onClick: () => {
627
+ operation.current++;
628
+ cancelled.current = true;
629
+ request.current?.abort();
630
+ if (recorder.current?.state === "recording")
631
+ recorder.current.stop();
632
+ release();
633
+ idle();
634
+ },
635
+ children: "Abbrechen"
636
+ }
637
+ )
638
+ ] }),
639
+ /* @__PURE__ */ jsx2("p", { className: "chat-voice-notice", children: "Die Aufnahme wird zur Texterkennung an OpenAI gesendet. Pr\xFCfen Sie den Text vor dem Senden." }),
640
+ error && /* @__PURE__ */ jsx2("p", { role: "alert", className: "text-danger dark:text-warning mt-2", children: error })
641
+ ]
642
+ }
643
+ );
607
644
  }
608
645
 
609
646
  // src/support-chat.tsx
@@ -825,25 +862,35 @@ function SupportChat(ctx) {
825
862
  }
826
863
  }
827
864
  return /* @__PURE__ */ jsxs3("div", { className: "chat-panel support-chat text-ink bg-card border border-line p-6 rounded-card compact:p-4", children: [
828
- /* @__PURE__ */ jsx3("p", { className: "text-[0.75rem] text-ink mb-3", children: demo ? "Synthetische Support-Demo. Keine \xDCbertragung an einen Support-Channel." : `Ihre Nachrichten und die Antworten werden an den Support in ${ctx.config.chatSupport?.mode === "slack" ? "Slack" : ctx.config.chatSupport?.mode === "telegram" ? "Telegram" : "Microsoft Teams"} weitergegeben.` }),
829
- /* @__PURE__ */ jsxs3("p", { role: "status", className: "text-[0.8125rem] mb-3", children: [
830
- current?.status === "support" ? `${current.support?.name} \xB7 Support` : current?.status === "waiting" ? current.supportRequest?.notification === "sent" ? "Support-Team informiert \xB7 KI pausiert" : current.supportRequest?.notification === "failed" ? "Zustellung verz\xF6gert \xB7 erneuter Versuch l\xE4uft \xB7 KI pausiert" : "Pers\xF6nlicher Support angefragt \xB7 KI pausiert" : current?.status === "closed" ? current.resolution ? "Problem gel\xF6st" : "Gespr\xE4ch abgeschlossen" : "Digitaler Assistent",
831
- auth && ready && !demo ? anonymous ? ` \xB7 ${auth.name}` : ` \xB7 Angemeldet als ${auth.name}` : ""
832
- ] }),
865
+ /* @__PURE__ */ jsx3(
866
+ ChatHeading,
867
+ {
868
+ headingLevel: ctx.surface === "hero" ? 2 : 3,
869
+ state: current?.status ?? "bot",
870
+ notice: demo ? "Synthetische Demo \xB7 keine Weiterleitung an den Support." : `Nachrichten werden mit dem Support in ${ctx.config.chatSupport?.mode === "slack" ? "Slack" : ctx.config.chatSupport?.mode === "telegram" ? "Telegram" : "Microsoft Teams"} geteilt.`,
871
+ status: /* @__PURE__ */ jsxs3(Fragment2, { children: [
872
+ current?.status === "support" ? `${current.support?.name} \xB7 Support` : current?.status === "waiting" ? current.supportRequest?.notification === "sent" ? "Support-Team informiert \xB7 KI pausiert" : current.supportRequest?.notification === "failed" ? "Zustellung verz\xF6gert \xB7 erneuter Versuch l\xE4uft \xB7 KI pausiert" : "Pers\xF6nlicher Support angefragt \xB7 KI pausiert" : current?.status === "closed" ? current.resolution ? "Problem gel\xF6st" : "Gespr\xE4ch abgeschlossen" : "Digitaler Assistent",
873
+ auth && ready && !demo ? anonymous ? ` \xB7 ${auth.name}` : ` \xB7 Angemeldet als ${auth.name}` : ""
874
+ ] })
875
+ }
876
+ ),
877
+ !current?.messages.length && /* @__PURE__ */ jsx3(ChatWelcome, {}),
833
878
  /* @__PURE__ */ jsx3(
834
879
  "div",
835
880
  {
836
881
  ref: scroll.history,
837
882
  onScroll: scroll.onScroll,
883
+ tabIndex: 0,
884
+ role: "log",
838
885
  className: "chat-history grid gap-3 max-h-[min(400px,45dvh)] overflow-auto overscroll-contain mb-4",
839
886
  "aria-live": "polite",
840
887
  "aria-label": "Gespr\xE4chsverlauf",
841
888
  children: current?.messages.map((m) => /* @__PURE__ */ jsxs3(
842
889
  "div",
843
890
  {
844
- className: `message ${m.kind === "user" ? "user bg-soft p-3 rounded-card" : "assistant border-l-2 border-accent pl-4"} text-[0.8125rem] whitespace-pre-wrap [overflow-wrap:anywhere]`,
891
+ className: `message ${m.kind === "user" ? "user" : m.kind === "system" ? "system" : m.kind === "support" ? "assistant human" : "assistant"} text-[0.8125rem] whitespace-pre-wrap [overflow-wrap:anywhere]`,
845
892
  children: [
846
- /* @__PURE__ */ jsx3("span", { className: "block text-[0.6875rem] text-ink mb-1", children: m.kind === "user" ? "Sie" : m.kind === "support" ? `${m.name} \xB7 Support` : m.kind === "bot" ? m.responder?.role === "on-duty" && m.responder.name ? `Digitaler Assistent von ${m.responder.name}` : "Digitaler Assistent des Service-Teams" : "Gespr\xE4ch" }),
893
+ /* @__PURE__ */ jsx3("span", { className: "chat-author", children: m.kind === "user" ? "Sie" : m.kind === "support" ? `${m.name} \xB7 Support` : m.kind === "bot" ? m.responder?.role === "on-duty" && m.responder.name ? `Digitaler Assistent von ${m.responder.name}` : "Digitaler Assistent des Service-Teams" : "Gespr\xE4ch" }),
847
894
  m.kind === "bot" ? answerParts(m.content, m.sources ?? [], !m.complete).map(
848
895
  (part, i) => part.href ? /* @__PURE__ */ jsx3(
849
896
  "a",
@@ -879,7 +926,7 @@ function SupportChat(ctx) {
879
926
  children: anonymous ? "Chat neu verbinden" : ctx.config.chatSupport?.auth === "session" ? "Portal-Anmeldung erneuern" : "Mit Microsoft anmelden"
880
927
  }
881
928
  ),
882
- ready && /* @__PURE__ */ jsxs3("div", { children: [
929
+ ready && /* @__PURE__ */ jsxs3("div", { className: "chat-composer", children: [
883
930
  /* @__PURE__ */ jsxs3("form", { onSubmit: submit, className: "chat-form flex gap-2.5 items-end", children: [
884
931
  /* @__PURE__ */ jsx3("label", { htmlFor: "support-chat-input", className: "sr-only", children: "Ihre Nachricht" }),
885
932
  /* @__PURE__ */ jsx3(
@@ -902,7 +949,7 @@ function SupportChat(ctx) {
902
949
  "button",
903
950
  {
904
951
  type: "submit",
905
- className: "bg-accent text-accent-ink rounded-card p-3",
952
+ className: "chat-send",
906
953
  disabled: blocked || !input.trim(),
907
954
  children: "Senden"
908
955
  }
@@ -921,21 +968,24 @@ function SupportChat(ctx) {
921
968
  }
922
969
  )
923
970
  ] }),
924
- ready && (!current || current.status === "bot") && /* @__PURE__ */ jsx3(
971
+ ready && (!current || current.status === "bot") && /* @__PURE__ */ jsxs3(
925
972
  "button",
926
973
  {
927
974
  type: "button",
928
- className: "border border-line rounded-card px-4 py-2 mt-3",
975
+ className: "chat-action chat-human-request",
929
976
  disabled: busy,
930
977
  onClick: () => void requestHuman(),
931
- children: "Ich m\xF6chte mit einer echten Person sprechen"
978
+ children: [
979
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "chat-action-icon", children: "\u2197" }),
980
+ "Ich m\xF6chte mit einer echten Person sprechen"
981
+ ]
932
982
  }
933
983
  ),
934
984
  ready && current && current.status !== "closed" && current.messages.some((m) => m.kind === "user") && /* @__PURE__ */ jsx3(
935
985
  "button",
936
986
  {
937
987
  type: "button",
938
- className: "border border-line rounded-card px-4 py-2 mt-3",
988
+ className: "chat-action",
939
989
  disabled: busy,
940
990
  onClick: () => void resolve(),
941
991
  children: "Problem gel\xF6st"
@@ -1153,104 +1203,104 @@ function LegacyChat(ctx) {
1153
1203
  /* @__PURE__ */ jsx4("p", { className: "data-state font-mono text-[0.625rem] text-muted m-[calc(var(--spacing)_*_3)_0_0] [&.warning]:text-warning", children: "\xD6ffentlicher Chat \xB7 Verlauf nur in dieser Sitzung" })
1154
1204
  ] }),
1155
1205
  /* @__PURE__ */ jsxs4("div", { className: "chat-panel text-ink compact:p-4 bg-card border border-line p-6 rounded-card", children: [
1156
- /* @__PURE__ */ jsxs4(
1206
+ /* @__PURE__ */ jsx4(
1207
+ ChatHeading,
1208
+ {
1209
+ headingLevel: ctx.surface === "hero" ? 2 : 3,
1210
+ state: resolved ? "closed" : "bot",
1211
+ status: resolved ? "Problem gel\xF6st" : "Digitaler Assistent",
1212
+ notice: "Ihre Frage wird automatisch beantwortet. Pers\xF6nlichen Kontakt finden Sie \xFCber die Hotline."
1213
+ }
1214
+ ),
1215
+ !messages.length && /* @__PURE__ */ jsx4(ChatWelcome, {}),
1216
+ /* @__PURE__ */ jsx4(
1157
1217
  "div",
1158
1218
  {
1159
1219
  ref: scroll.history,
1160
1220
  onScroll: scroll.onScroll,
1221
+ tabIndex: 0,
1222
+ role: "log",
1161
1223
  className: "chat-history empty:hidden grid gap-3.75 max-h-[min(400px,45dvh)] overflow-auto overscroll-contain mb-4",
1162
1224
  "aria-label": "Gespr\xE4chsverlauf",
1163
1225
  "aria-live": "polite",
1164
1226
  "aria-busy": busy,
1165
- children: [
1166
- !messages.length && ctx.surface !== "hero" && /* @__PURE__ */ jsx4("p", { className: "message assistant text-[0.8125rem] leading-[1.8] whitespace-pre-wrap [overflow-wrap:anywhere] [&.user]:bg-soft [&.user]:pt-3 [&.user]:pb-3 [&.user]:pl-4 [&.user]:pr-4 [&.user]:rounded-card [&.assistant]:[border-left:2px_solid_var(--accent)] [&.assistant]:pt-[0] [&.assistant]:pb-[0] [&.assistant]:pl-4 [&.assistant]:pr-4", children: "Wie kann ich Ihnen helfen?" }),
1167
- messages.map((m, i) => /* @__PURE__ */ jsxs4(
1168
- "div",
1169
- {
1170
- className: "message text-[0.8125rem] leading-[1.8] whitespace-pre-wrap [overflow-wrap:anywhere] [&.user]:bg-soft [&.user]:pt-3 [&.user]:pb-3 [&.user]:pl-4 [&.user]:pr-4 [&.user]:rounded-card [&.assistant]:[border-left:2px_solid_var(--accent)] [&.assistant]:pt-[0] [&.assistant]:pb-[0] [&.assistant]:pl-4 [&.assistant]:pr-4 " + m.role,
1171
- children: [
1172
- m.role === "user" ? /* @__PURE__ */ jsx4("span", { className: "sr-only", children: "Sie: " }) : /* @__PURE__ */ jsx4("span", { className: "block text-[0.6875rem] text-muted mb-1", children: m.responder?.role === "on-duty" && m.responder.name ? `Digitaler Assistent von ${m.responder.name}` : "Digitaler Assistent des Service-Teams" }),
1173
- m.role === "user" ? m.content : m.content ? answerParts(m.content, m.sources ?? [], !m.complete).map(
1174
- (part, index) => part.href ? /* @__PURE__ */ jsx4("a", { href: part.href, children: part.text }, index) : /* @__PURE__ */ jsx4("span", { children: part.text }, index)
1175
- ) : "Antwort wird vorbereitet \u2026",
1176
- m.role === "assistant" && !!m.sources?.length && /* @__PURE__ */ jsxs4("div", { className: "sources text-[0.6875rem] text-muted mt-3 mb-1 [&_a]:mr-3", children: [
1177
- "Referenzquellen:",
1178
- " ",
1179
- m.sources.map(
1180
- (source) => sourceHref(source.href) ? /* @__PURE__ */ jsxs4("a", { href: sourceHref(source.href), children: [
1181
- source.title,
1182
- source.stale ? " (veraltet)" : ""
1183
- ] }, source.id) : /* @__PURE__ */ jsxs4("span", { children: [
1184
- source.title,
1185
- " "
1186
- ] }, source.id)
1187
- )
1188
- ] })
1189
- ]
1190
- },
1191
- i
1192
- ))
1193
- ]
1227
+ children: messages.map((m, i) => /* @__PURE__ */ jsxs4("div", { className: "message " + m.role, children: [
1228
+ m.role === "user" ? /* @__PURE__ */ jsx4("span", { className: "chat-author", children: "Sie" }) : /* @__PURE__ */ jsx4("span", { className: "chat-author", children: m.responder?.role === "on-duty" && m.responder.name ? `Digitaler Assistent von ${m.responder.name}` : "Digitaler Assistent des Service-Teams" }),
1229
+ m.role === "user" ? m.content : m.content ? answerParts(m.content, m.sources ?? [], !m.complete).map(
1230
+ (part, index) => part.href ? /* @__PURE__ */ jsx4("a", { href: part.href, children: part.text }, index) : /* @__PURE__ */ jsx4("span", { children: part.text }, index)
1231
+ ) : "Antwort wird vorbereitet \u2026",
1232
+ m.role === "assistant" && !!m.sources?.length && /* @__PURE__ */ jsxs4("div", { className: "sources text-[0.6875rem] text-muted mt-3 mb-1 [&_a]:mr-3", children: [
1233
+ "Referenzquellen:",
1234
+ " ",
1235
+ m.sources.map(
1236
+ (source) => sourceHref(source.href) ? /* @__PURE__ */ jsxs4("a", { href: sourceHref(source.href), children: [
1237
+ source.title,
1238
+ source.stale ? " (veraltet)" : ""
1239
+ ] }, source.id) : /* @__PURE__ */ jsxs4("span", { children: [
1240
+ source.title,
1241
+ " "
1242
+ ] }, source.id)
1243
+ )
1244
+ ] })
1245
+ ] }, i))
1194
1246
  }
1195
1247
  ),
1196
1248
  /* @__PURE__ */ jsx4(NewMessages, { visible: scroll.unread, follow: scroll.follow }),
1197
- /* @__PURE__ */ jsxs4(
1198
- "form",
1199
- {
1200
- className: "chat-form flex gap-2.5 items-end [&_textarea]:resize-none [&_textarea]:min-h-[50px] [&_textarea]:[flex:1] [&_textarea]:min-w-0 [&_button]:bg-accent [&_button]:text-accent-ink [&_button]:[border:0] [&_button]:w-[50px] [&_button]:h-[50px] [&_button]:rounded-card [&_button]:text-[1.25rem] [&_button:disabled]:opacity-[0.5]",
1201
- onSubmit: submit,
1202
- children: [
1203
- /* @__PURE__ */ jsx4("label", { className: "sr-only", htmlFor: "chat-input", children: "Ihre Frage" }),
1204
- /* @__PURE__ */ jsxs4("div", { className: "relative flex-1 min-w-0", children: [
1205
- /* @__PURE__ */ jsx4(
1206
- "textarea",
1207
- {
1208
- id: "chat-input",
1209
- ref: inputField,
1210
- rows: 1,
1211
- autoFocus: true,
1212
- className: "search bg-card border border-line rounded-card pt-3.5 pb-7 px-4.5 text-ink w-full block max-h-[180px] overflow-auto",
1213
- value: input,
1214
- disabled: resolved,
1215
- maxLength: 4e3,
1216
- onChange: (e) => setInput(e.target.value),
1217
- onKeyDown: (e) => sendShortcut(e, busy || voiceBusy || resolved || !input.trim()),
1218
- "aria-keyshortcuts": "Control+Enter Meta+Enter",
1219
- "aria-describedby": "chat-shortcut",
1220
- placeholder: "Ihre Frage an unser Team \u2026",
1221
- required: true
1222
- }
1223
- ),
1224
- /* @__PURE__ */ jsx4(Shortcut, { id: "chat-shortcut" })
1225
- ] }),
1249
+ /* @__PURE__ */ jsxs4("div", { className: "chat-composer", children: [
1250
+ /* @__PURE__ */ jsxs4("form", { className: "chat-form flex gap-2.5 items-end", onSubmit: submit, children: [
1251
+ /* @__PURE__ */ jsx4("label", { className: "sr-only", htmlFor: "chat-input", children: "Ihre Frage" }),
1252
+ /* @__PURE__ */ jsxs4("div", { className: "relative flex-1 min-w-0", children: [
1226
1253
  /* @__PURE__ */ jsx4(
1227
- "button",
1254
+ "textarea",
1228
1255
  {
1229
- type: "submit",
1230
- disabled: busy || voiceBusy || resolved || !input.trim(),
1231
- "aria-label": "Frage senden",
1232
- children: "\u2191"
1256
+ id: "chat-input",
1257
+ ref: inputField,
1258
+ rows: 1,
1259
+ autoFocus: true,
1260
+ className: "search bg-card border border-line rounded-card pt-3.5 pb-7 px-4.5 text-ink w-full block max-h-[180px] overflow-auto",
1261
+ value: input,
1262
+ disabled: resolved,
1263
+ maxLength: 4e3,
1264
+ onChange: (e) => setInput(e.target.value),
1265
+ onKeyDown: (e) => sendShortcut(
1266
+ e,
1267
+ busy || voiceBusy || resolved || !input.trim()
1268
+ ),
1269
+ "aria-keyshortcuts": "Control+Enter Meta+Enter",
1270
+ "aria-describedby": "chat-shortcut",
1271
+ placeholder: "Ihre Frage an unser Team \u2026",
1272
+ required: true
1233
1273
  }
1234
- )
1235
- ]
1236
- }
1237
- ),
1238
- /* @__PURE__ */ jsx4(
1239
- VoiceInput,
1240
- {
1241
- ctx,
1242
- value: input,
1243
- setValue: setInput,
1244
- disabled: resolved,
1245
- onBusy: setVoiceBusy
1246
- }
1247
- ),
1248
- ctx.surface === "hero" && /* @__PURE__ */ jsx4("p", { className: "data-state font-mono text-[0.625rem] text-muted mt-3 mb-0", children: "Digitaler Assistent \xB7 Ihre Frage wird automatisch beantwortet. F\xFCr pers\xF6nlichen Kontakt nutzen Sie die Hotline." }),
1274
+ ),
1275
+ /* @__PURE__ */ jsx4(Shortcut, { id: "chat-shortcut" })
1276
+ ] }),
1277
+ /* @__PURE__ */ jsx4(
1278
+ "button",
1279
+ {
1280
+ type: "submit",
1281
+ disabled: busy || voiceBusy || resolved || !input.trim(),
1282
+ className: "chat-send",
1283
+ "aria-label": "Frage senden",
1284
+ children: "Senden"
1285
+ }
1286
+ )
1287
+ ] }),
1288
+ /* @__PURE__ */ jsx4(
1289
+ VoiceInput,
1290
+ {
1291
+ ctx,
1292
+ value: input,
1293
+ setValue: setInput,
1294
+ disabled: resolved,
1295
+ onBusy: setVoiceBusy
1296
+ }
1297
+ )
1298
+ ] }),
1249
1299
  messages.length > 0 && !resolved && /* @__PURE__ */ jsx4(
1250
1300
  "button",
1251
1301
  {
1252
1302
  type: "button",
1253
- className: "border border-line rounded-card px-4 py-2 mt-3",
1303
+ className: "chat-action",
1254
1304
  onClick: () => {
1255
1305
  abort.current?.abort();
1256
1306
  setResolved(true);
@@ -1269,25 +1319,22 @@ function LegacyChat(ctx) {
1269
1319
  children: "Problem gel\xF6st"
1270
1320
  }
1271
1321
  ),
1272
- resolved && /* @__PURE__ */ jsxs4("div", { className: "mt-3", children: [
1273
- /* @__PURE__ */ jsx4("p", { role: "status", children: "Problem gel\xF6st" }),
1274
- /* @__PURE__ */ jsx4(
1275
- "button",
1276
- {
1277
- type: "button",
1278
- className: "underline mt-2",
1279
- disabled: busy,
1280
- onClick: () => {
1281
- scroll.follow();
1282
- setMessages([]);
1283
- setResolved(false);
1284
- setInput("");
1285
- setError("");
1286
- },
1287
- children: "Neuen Chat starten"
1288
- }
1289
- )
1290
- ] }),
1322
+ resolved && /* @__PURE__ */ jsx4("div", { className: "mt-3", children: /* @__PURE__ */ jsx4(
1323
+ "button",
1324
+ {
1325
+ type: "button",
1326
+ className: "underline mt-2",
1327
+ disabled: busy,
1328
+ onClick: () => {
1329
+ scroll.follow();
1330
+ setMessages([]);
1331
+ setResolved(false);
1332
+ setInput("");
1333
+ setError("");
1334
+ },
1335
+ children: "Neuen Chat starten"
1336
+ }
1337
+ ) }),
1291
1338
  error && /* @__PURE__ */ jsx4(
1292
1339
  "p",
1293
1340
  {
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var cspPlugin = {
3
3
  id: "chat",
4
- sdkVersion: "^0.12.1",
4
+ sdkVersion: "^0.13.1",
5
5
  browser: "./browser",
6
6
  server: "./server"
7
7
  };
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cspPlugin
3
- } from "./chunk-U2H5BQCV.js";
3
+ } from "./chunk-B7EKNOQK.js";
4
4
 
5
5
  // src/server.ts
6
6
  import { z as z2 } from "zod";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kieksme/csp-plugin-chat",
3
- "version": "0.12.1",
3
+ "version": "0.13.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@azure/msal-browser": "^5.25.0",
26
- "@kieksme/csp-sdk": "^0.12.1",
26
+ "@kieksme/csp-sdk": "^0.13.1",
27
27
  "openai": "^6.3.0",
28
28
  "zod": "^3.25.76"
29
29
  },
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "cspPlugin": {
37
37
  "id": "chat",
38
- "sdkVersion": "^0.12.1",
38
+ "sdkVersion": "^0.13.1",
39
39
  "browser": "./browser",
40
40
  "server": "./server"
41
41
  },