@inploi/plugin-chatbot 3.7.0 → 3.9.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.
@@ -1,6 +1,6 @@
1
1
  import { FlowNode } from '@inploi/core/flows';
2
2
  import { AnalyticsService, ApiClient, Logger } from '@inploi/sdk';
3
- import { ChatInput } from './ui/chat-input/chat-input';
3
+ import { ChatInput } from './components/chat-input/chat-input';
4
4
  import { ApplicationSubmission, ChatMessage, KeyToSubmissionMap } from './chatbot.state';
5
5
  export declare const followNodes: ({ node, nodes, stopWhen, }: {
6
6
  node: FlowNode;
@@ -23,11 +23,11 @@ export type ChatService = {
23
23
  type: TType;
24
24
  }>>;
25
25
  };
26
- type ChatbotInterpreterParams = {
26
+ type ChatbotInterpreterParams<TContext extends Record<string, unknown>> = {
27
27
  apiClient: ApiClient;
28
28
  analytics: AnalyticsService;
29
29
  logger: Logger;
30
- context: Record<string, unknown>;
30
+ context: TContext;
31
31
  flow: FlowNode[];
32
32
  getSubmissions: () => KeyToSubmissionMap | undefined;
33
33
  chatService: ChatService;
@@ -38,8 +38,9 @@ type ChatbotInterpreterParams = {
38
38
  /** When node is interpreted */
39
39
  onInterpret?: (node: FlowNode, prevNode?: FlowNode) => void;
40
40
  };
41
- export declare const createFlowInterpreter: ({ flow, analytics, logger, context, apiClient, getSubmissions, chatService, onFlowEnd, onInterpret, }: ChatbotInterpreterParams) => {
41
+ export declare const createFlowInterpreter: <TContext extends Record<string, unknown>>({ flow, analytics, logger, context, apiClient, getSubmissions, chatService, onFlowEnd, onInterpret, }: ChatbotInterpreterParams<TContext>) => {
42
42
  interpret: (startFromNodeId?: string) => Promise<void>;
43
43
  abort: () => void;
44
44
  };
45
+ export declare const interpolateString: (str: string, context: KeyToSubmissionMap | undefined) => string;
45
46
  export {};
@@ -1,5 +1,6 @@
1
- import { _, N, i as invariant, o as o$1, c as clsx, a as _$1, p, b as parse, d as picklist, y, e as application, h, k, C as Cn, f as parseAsync, V as ValiError, g as object, t as transform, m as maxLength, j as minLength, r as record, l as boolean, s as string, n as email, u as url, q as regex, T, v as inputHeight, w as m, A as AnimatePresence, F, x as viewState, E as ERROR_MESSAGES } from "./index-1808db67.js";
1
+ import { N, _, h as hasProp, i as invariant, o as o$1, c as clsx, a as _$1, p, b as parse, d as picklist, y, e as application, f as h, k, C as Cn, g as parseAsync, V as ValiError, j as object, t as transform, m as maxLength, l as minLength, r as record, n as boolean, s as string, q as email, u as url, v as regex, T, w as inputHeight, x as m, A as AnimatePresence, F, z as viewState, E as ERROR_MESSAGES } from "./index-6a43f107.js";
2
2
  import "@inploi/sdk";
3
+ const kbToReadableSize = (kb) => N(kb).with(_.number.lte(1e3), () => `${Math.round(kb)}KB`).with(_.number.lt(1e3 * 10), () => `${(kb / 1e3).toFixed(1)}MB`).otherwise(() => `${Math.round(kb / 1e3)}MB`);
3
4
  const getHeadOrThrow = (nodes) => {
4
5
  const head = nodes.find((n2) => n2.isHead);
5
6
  if (!head)
@@ -233,8 +234,6 @@ async function interpretSubmitNode({
233
234
  method: "POST",
234
235
  body: JSON.stringify({
235
236
  ...context,
236
- type: node.data.type,
237
- ats: node.data.ats,
238
237
  integration_id: node.data.integrationId,
239
238
  anonymous_id: analytics.getAnonymousId(),
240
239
  submissions: getApplicationSubmissionsPayload(submissions || {})
@@ -285,12 +284,13 @@ async function interpretSubmitNode({
285
284
  async function interpretLinkNode({
286
285
  chat,
287
286
  next,
288
- node
287
+ node,
288
+ submissions
289
289
  }) {
290
290
  await chat.sendMessage({
291
291
  type: "link",
292
292
  href: node.data.href,
293
- text: node.data.cta
293
+ text: interpolateString(node.data.cta, submissions)
294
294
  });
295
295
  next(node.nextId);
296
296
  }
@@ -305,12 +305,13 @@ async function interpretIfBlockNode({
305
305
  async function interpretTextNode({
306
306
  chat,
307
307
  next,
308
- node
308
+ node,
309
+ submissions
309
310
  }) {
310
311
  await chat.sendMessage({
311
312
  author: "bot",
312
313
  type: "text",
313
- text: node.data.text
314
+ text: interpolateString(node.data.text, submissions)
314
315
  });
315
316
  next(node.nextId);
316
317
  }
@@ -331,12 +332,13 @@ async function interpretImageNode({
331
332
  async function interpretQuestionTextNode({
332
333
  chat,
333
334
  next,
334
- node
335
+ node,
336
+ submissions
335
337
  }) {
336
338
  await chat.sendMessage({
337
339
  author: "bot",
338
340
  type: "text",
339
- text: node.data.question
341
+ text: interpolateString(node.data.question, submissions)
340
342
  });
341
343
  const reply = await chat.userInput({
342
344
  key: node.data.key,
@@ -365,12 +367,13 @@ async function interpretQuestionTextNode({
365
367
  async function interpretQuestionNumberNode({
366
368
  chat,
367
369
  next,
368
- node
370
+ node,
371
+ submissions
369
372
  }) {
370
373
  await chat.sendMessage({
371
374
  author: "bot",
372
375
  type: "text",
373
- text: node.data.question
376
+ text: interpolateString(node.data.question, submissions)
374
377
  });
375
378
  const reply = await chat.userInput({
376
379
  key: node.data.key,
@@ -399,12 +402,13 @@ async function interpretQuestionNumberNode({
399
402
  async function interpretQuestionEnumNode({
400
403
  chat,
401
404
  next,
402
- node
405
+ node,
406
+ submissions
403
407
  }) {
404
408
  await chat.sendMessage({
405
409
  author: "bot",
406
410
  type: "text",
407
- text: node.data.question
411
+ text: interpolateString(node.data.question, submissions)
408
412
  });
409
413
  const reply = await chat.userInput({
410
414
  key: node.data.key,
@@ -429,12 +433,13 @@ async function interpretQuestionEnumNode({
429
433
  async function interpretQuestionBooleanNode({
430
434
  chat,
431
435
  next,
432
- node
436
+ node,
437
+ submissions
433
438
  }) {
434
439
  await chat.sendMessage({
435
440
  author: "bot",
436
441
  type: "text",
437
- text: node.data.question
442
+ text: interpolateString(node.data.question, submissions)
438
443
  });
439
444
  const input = await chat.userInput({
440
445
  key: node.data.key,
@@ -466,27 +471,205 @@ async function interpretQuestionBooleanNode({
466
471
  }
467
472
  next(node.nextId);
468
473
  }
474
+ const dummyDivBecauseGoogleRequiresIt = document.createElement("div");
475
+ const keyToAddressComponnents = {
476
+ line1: ["street_number", "floor", "room", "premise"],
477
+ line2: ["subpremise", "street_address", "route"],
478
+ line3: ["sublocality", "neighborhood"],
479
+ city: ["locality", "postal_town"],
480
+ state: ["administrative_area_level_1"],
481
+ postcode: ["postal_code"],
482
+ country: ["country"]
483
+ };
484
+ const fieldMapKeys = Object.keys(keyToAddressComponnents);
469
485
  async function interpretQuestionAddressNode({
470
486
  chat,
471
487
  next,
472
- node
488
+ node,
489
+ logger
473
490
  }) {
491
+ const {
492
+ google
493
+ } = window;
474
494
  await chat.sendMessage({
475
495
  author: "bot",
476
496
  type: "text",
477
- text: "Address questions are not implemented yet"
497
+ text: node.data.question
478
498
  });
479
- next(node.nextId);
499
+ const askForAddress = async (defaultValues) => {
500
+ const addressFields = [{
501
+ label: "Postcode",
502
+ key: node.data.keys.postcode,
503
+ optional: false,
504
+ defaultValue: defaultValues.postcode
505
+ }, {
506
+ label: "Line 1",
507
+ key: node.data.keys.line1,
508
+ optional: false,
509
+ defaultValue: defaultValues.line1
510
+ }, {
511
+ label: "Line 2",
512
+ key: node.data.keys.line2,
513
+ optional: true,
514
+ defaultValue: defaultValues.line2
515
+ }, {
516
+ label: "Line 3",
517
+ key: node.data.keys.line3,
518
+ optional: true,
519
+ defaultValue: defaultValues.line3
520
+ }, {
521
+ label: "City",
522
+ key: node.data.keys.city,
523
+ optional: false,
524
+ defaultValue: defaultValues.city
525
+ }, {
526
+ label: "State/County/Province",
527
+ key: node.data.keys.state,
528
+ optional: true,
529
+ defaultValue: defaultValues.state
530
+ }, {
531
+ label: "Country",
532
+ key: node.data.keys.country,
533
+ optional: false,
534
+ defaultValue: defaultValues.country
535
+ }];
536
+ for (const field of addressFields) {
537
+ await chat.sendMessage({
538
+ author: "bot",
539
+ type: "text",
540
+ text: field.label
541
+ });
542
+ const {
543
+ value
544
+ } = await chat.userInput({
545
+ type: "text",
546
+ key: field.key,
547
+ config: {
548
+ format: "text",
549
+ optional: field.optional,
550
+ defaultValue: field.defaultValue
551
+ }
552
+ });
553
+ if (value === null) {
554
+ await chat.sendMessage({
555
+ type: "system",
556
+ variant: "info",
557
+ text: "Skipped"
558
+ });
559
+ } else {
560
+ await chat.sendMessage({
561
+ author: "user",
562
+ type: "text",
563
+ text: value
564
+ });
565
+ }
566
+ }
567
+ };
568
+ if (!hasProp(window, "google") || !hasProp(window.google, "maps") || !hasProp(window.google.maps, "places")) {
569
+ logger.warn("Google maps not available, falling back to manual input.");
570
+ logger.info("If you’d like to use the address autocomplete, please insert the google maps API snippet in your website and make sure it has access to the *places* library.");
571
+ await askForAddress({});
572
+ return next(node.nextId);
573
+ }
574
+ const autocomplete = new google.maps.places.AutocompleteService();
575
+ const places = new google.maps.places.PlacesService(dummyDivBecauseGoogleRequiresIt);
576
+ const {
577
+ value: search
578
+ } = await chat.userInput({
579
+ type: "text",
580
+ key: "_internal-address-search",
581
+ config: {
582
+ format: "text",
583
+ optional: false,
584
+ placeholder: "Search for your address"
585
+ }
586
+ });
587
+ if (search === null)
588
+ return next(node.id);
589
+ await chat.sendMessage({
590
+ author: "user",
591
+ type: "text",
592
+ text: `Search for “${search}”`
593
+ });
594
+ const {
595
+ predictions
596
+ } = await autocomplete.getPlacePredictions({
597
+ input: search
598
+ });
599
+ const {
600
+ value: [selected]
601
+ } = await chat.userInput({
602
+ type: "multiple-choice",
603
+ key: void 0,
604
+ config: {
605
+ options: predictions.slice(0, 4).map((p2) => ({
606
+ label: p2.description,
607
+ value: p2.place_id
608
+ })).concat({
609
+ label: "None of these",
610
+ value: "none"
611
+ }),
612
+ maxSelected: 1,
613
+ minSelected: 1
614
+ }
615
+ });
616
+ if (!selected || selected === "none") {
617
+ return next(node.id);
618
+ }
619
+ const result = await new Promise((resolve, reject) => places.getDetails({
620
+ placeId: selected,
621
+ fields: ["address_components"]
622
+ }, (result2, status) => {
623
+ if (status !== google.maps.places.PlacesServiceStatus["OK"])
624
+ return reject(status);
625
+ if (result2 === null)
626
+ return reject("ZERO_RESULTS");
627
+ return resolve({
628
+ ok: true,
629
+ place: result2
630
+ });
631
+ })).catch(async (e) => {
632
+ logger.error("Failed to get address details", e);
633
+ return {
634
+ ok: false
635
+ };
636
+ });
637
+ if (result.ok === false) {
638
+ await chat.sendMessage({
639
+ type: "system",
640
+ variant: "error",
641
+ text: "Failed to get address details"
642
+ });
643
+ await askForAddress({});
644
+ return next(node.id);
645
+ }
646
+ const addressComponents = result.place.address_components;
647
+ const autoFilledInputs = addressComponents ? fieldMapKeys.reduce((acc, key) => {
648
+ const componentTypes = keyToAddressComponnents[key];
649
+ const value = addressComponents.filter((component) => component.types.some((type) => componentTypes.includes(type))).map((component) => component.long_name).join(", ");
650
+ if (value) {
651
+ acc[key] = value;
652
+ }
653
+ return acc;
654
+ }, {}) : {};
655
+ await chat.sendMessage({
656
+ author: "bot",
657
+ type: "text",
658
+ text: "Please confirm or adjust your address:"
659
+ });
660
+ await askForAddress(autoFilledInputs);
661
+ return next(node.nextId);
480
662
  }
481
663
  async function interpretQuestionFileNode({
482
664
  node,
483
665
  chat,
484
- next
666
+ next,
667
+ submissions
485
668
  }) {
486
669
  await chat.sendMessage({
487
670
  author: "bot",
488
671
  type: "text",
489
- text: node.data.question
672
+ text: interpolateString(node.data.question, submissions)
490
673
  });
491
674
  const files = await chat.userInput({
492
675
  key: node.data.key,
@@ -575,11 +758,33 @@ const isIfBlockConditionMet = (ifBlock, submissions) => {
575
758
  }
576
759
  }, () => false).exhaustive();
577
760
  };
761
+ const interpolateString = (str, context) => {
762
+ const regex2 = /{{\s*([^}]+?)\s*(?:\|\s*([^}]+?)\s*)?}}/g;
763
+ return str.replace(regex2, (match2, key, defaultValue = "") => {
764
+ key = key.trim();
765
+ const submission = context == null ? void 0 : context[key];
766
+ if (!submission)
767
+ return defaultValue;
768
+ switch (submission.type) {
769
+ case "boolean":
770
+ return submission.value === "true" ? "true" : "false";
771
+ case "file":
772
+ if (!submission.value)
773
+ return "no files";
774
+ return submission.value.map((file) => `${file.name} (${kbToReadableSize(file.sizeKb)})`).join(", ");
775
+ case "multiple-choice":
776
+ return submission.value.join(", ");
777
+ default:
778
+ return submission.value || defaultValue;
779
+ }
780
+ });
781
+ };
578
782
  const SendButton = ({
579
783
  class: className,
580
784
  ...props
581
785
  }) => o$1("button", {
582
- class: clsx("bg-accent-7 active:bg-accent-10 active:text-accent-2 text-lowest pointer-coarse:touch-hitbox focus-visible:ring-accent-7/50 flex-shrink-0 rounded-full p-2 transition-all focus:outline-none focus-visible:ring-4 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className),
786
+ class: clsx("bg-accent-9 active:bg-accent-10 pointer-coarse:touch-hitbox fr flex-shrink-0 rounded-full p-2 text-white transition-all disabled:cursor-not-allowed disabled:opacity-50", className),
787
+ type: "submit",
583
788
  ...props,
584
789
  children: o$1("svg", {
585
790
  class: "block",
@@ -603,7 +808,8 @@ const SkipButton = ({
603
808
  class: className,
604
809
  ...props
605
810
  }) => o$1("button", {
606
- class: clsx("focus-visible:ring-accent-7/50 text-neutral-9 flex flex-shrink-0 items-center justify-center gap-1 rounded-full py-[6px] pl-2 pr-3 text-sm underline-offset-2 transition-all focus:outline-none focus-visible:ring-4 focus-visible:ring-offset-2", className),
811
+ type: "button",
812
+ class: clsx("fr text-neutral-9 flex flex-shrink-0 items-center justify-center gap-1 rounded-full py-[6px] pl-2 pr-3 text-sm underline-offset-2 transition-all", className),
607
813
  ...props,
608
814
  children: [o$1("svg", {
609
815
  class: "block",
@@ -666,7 +872,7 @@ const ChatInputBoolean = ({
666
872
  type: "submit",
667
873
  name: FIELD_NAME,
668
874
  value,
669
- class: "bg-lowest ease-expo-out ring-neutral-12/5 text-neutral-12 active:ring-accent-7 active:bg-accent-2 active:text-accent-11 fr duration-snappy block flex-1 overflow-hidden rounded-2xl px-2.5 py-2.5 ring-2 transition-all selection:bg-transparent",
875
+ class: "bg-lowest ease-expo-out ring-divider text-neutral-12 active:ring-accent-7 active:bg-accent-2 active:text-accent-11 fr block flex-1 overflow-hidden rounded-2xl px-2.5 py-2.5 ring-2 transition-all selection:bg-transparent",
670
876
  children: o$1("p", {
671
877
  class: "truncate text-center text-base",
672
878
  children: input.config.labels[value]
@@ -698,7 +904,7 @@ const InputError = ({
698
904
  role: "alert",
699
905
  class: "text-error-11 flex max-w-full items-center gap-1 overflow-hidden rounded-full px-2 py-2",
700
906
  children: [o$1("svg", {
701
- class: "text-error-10 h-4 w-4",
907
+ class: "text-error-9 h-4 w-4",
702
908
  viewBox: "0 0 16 16",
703
909
  fill: "none",
704
910
  xmlns: "http://www.w3.org/2000/svg",
@@ -737,7 +943,6 @@ const toBase64 = (file) => new Promise((resolve, reject) => {
737
943
  };
738
944
  reader.onerror = reject;
739
945
  });
740
- const kbToReadableSize = (kb) => N(kb).with(_.number.lte(1e3), () => `${Math.round(kb)}KB`).with(_.number.lt(1e3 * 10), () => `${(kb / 1e3).toFixed(1)}MB`).otherwise(() => `${Math.round(kb / 1e3)}MB`);
741
946
  const addFileSizesKb = (files) => files.reduce((acc, cur) => acc + cur.sizeKb, 0);
742
947
  const isFileSubmission = isSubmissionOfType("file");
743
948
  const FILENAMES_TO_SHOW_QTY = 3;
@@ -749,7 +954,7 @@ const FileThumbnail = ({
749
954
  const extension = file.name.split(".").pop();
750
955
  const fileName = file.name.replace(new RegExp(`.${extension}$`), "");
751
956
  return o$1("div", {
752
- class: clsx("bg-accent-1 outline-neutral-4 flex max-w-full gap-2 overflow-hidden rounded-lg px-3 py-2 text-sm outline", className),
957
+ class: clsx("bg-accent-1 outline-accent-4 flex max-w-full gap-2 overflow-hidden rounded-lg px-3 py-2 text-sm outline", className),
753
958
  ...props,
754
959
  children: [o$1("p", {
755
960
  "aria-label": "File name",
@@ -762,7 +967,7 @@ const FileThumbnail = ({
762
967
  })]
763
968
  }), o$1("p", {
764
969
  "aria-label": "File size",
765
- class: "text-neutral-10",
970
+ class: "text-accent-11",
766
971
  children: kbToReadableSize(file.sizeKb)
767
972
  })]
768
973
  });
@@ -856,7 +1061,7 @@ const ChatInputFile = ({
856
1061
  d: "M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
857
1062
  })
858
1063
  }), o$1("p", {
859
- class: "text-neutral-12 tracking-[-0.01em] dark:text-gray-400",
1064
+ class: "text-neutral-12 tracking-[-0.01em]",
860
1065
  children: [input.config.allowMultiple ? "Select files" : "Select a file", " to upload"]
861
1066
  }), input.config.fileSizeLimitKib ? o$1("p", {
862
1067
  class: "text-neutral-10 text-xs",
@@ -2422,7 +2627,7 @@ const ChatInputMultipleChoice = ({
2422
2627
  resolver: getResolver$1(input.config)
2423
2628
  });
2424
2629
  const focusRef = useFocusOnMount();
2425
- const isSingleChoice = input.config.minSelected === 1 && input.config.maxSelected === 1;
2630
+ const isSingleChoice = (input.config.minSelected === 1 || input.config.minSelected === void 0) && input.config.maxSelected === 1;
2426
2631
  return o$1("form", {
2427
2632
  noValidate: true,
2428
2633
  class: "flex flex-col gap-1 pr-2.5",
@@ -2465,7 +2670,7 @@ const ChatInputMultipleChoice = ({
2465
2670
  class: "peer sr-only h-full",
2466
2671
  type: "checkbox"
2467
2672
  }), o$1("label", {
2468
- class: "bg-lowest peer-focus-visible:ring-accent-7 active:outline-neutral-10 ease-expo-out outline-neutral-12/5 text-neutral-11 peer-checked:outline-accent-7 peer-checked:bg-accent-2 peer-checked:text-accent-9 duration-snappy block rounded-2xl px-2.5 py-1 outline outline-2 ring-0 ring-transparent transition-all selection:bg-transparent peer-focus-visible:ring-4 peer-focus-visible:ring-offset-2",
2673
+ class: "bg-lowest peer-focus-visible:ring-accent-7 active:outline-neutral-10 ease-expo-out outline-divider text-neutral-11 peer-checked:outline-accent-7 peer-checked:bg-accent-2 peer-checked:text-accent-9 block rounded-2xl px-2.5 py-1 outline outline-2 ring-0 ring-transparent transition-all selection:bg-transparent peer-focus-visible:ring-4 peer-focus-visible:ring-offset-2",
2469
2674
  htmlFor: id,
2470
2675
  children: option.label
2471
2676
  })]
@@ -2530,6 +2735,7 @@ const ChatInputText = ({
2530
2735
  }) => {
2531
2736
  var _a;
2532
2737
  const submission = input.key ? (_a = application.current$.value.application) == null ? void 0 : _a.data.submissions[input.key] : void 0;
2738
+ const defaultValue = input.config.defaultValue;
2533
2739
  const {
2534
2740
  register,
2535
2741
  handleSubmit,
@@ -2538,7 +2744,7 @@ const ChatInputText = ({
2538
2744
  }
2539
2745
  } = useForm({
2540
2746
  defaultValues: {
2541
- text: isTextSubmission(submission) ? submission.value : ""
2747
+ text: defaultValue ? defaultValue : isTextSubmission(submission) ? submission.value : ""
2542
2748
  },
2543
2749
  resolver: getResolver(input.config)
2544
2750
  });
@@ -2580,7 +2786,7 @@ const ChatInputText = ({
2580
2786
  }
2581
2787
  setRef(element);
2582
2788
  },
2583
- class: "outline-neutral-12/5 ease-expo-out placeholder:text-neutral-5 focus-visible:outline-accent-7 caret-accent-9 duration-snappy w-full rounded-full px-3 py-1 text-base outline outline-2 transition-all",
2789
+ class: "outline-divider ease-expo-out placeholder:text-neutral-10 text-neutral-12 focus-visible:outline-accent-7 caret-accent-9 bg-lowest w-full rounded-full px-3 py-1 text-base outline outline-2 transition-all",
2584
2790
  placeholder: input.config.placeholder
2585
2791
  }), input.config.optional && o$1(SkipButton, {
2586
2792
  class: "absolute right-0 top-0",
@@ -2624,10 +2830,10 @@ const ChatInput = ({
2624
2830
  height: 0,
2625
2831
  opacity: 0
2626
2832
  },
2627
- class: "bg-neutral-2/80 absolute bottom-0 w-full overflow-hidden rounded-b-3xl backdrop-blur-md backdrop-saturate-150",
2833
+ class: "bg-statusbar absolute bottom-0 w-full overflow-hidden rounded-b-3xl backdrop-blur-md backdrop-saturate-150",
2628
2834
  children: o$1("div", {
2629
2835
  ref: inputWrapperRef,
2630
- class: "border-neutral-12/5 border-t",
2836
+ class: "border-divider border-t",
2631
2837
  children: N({
2632
2838
  application,
2633
2839
  input,
@@ -2639,7 +2845,7 @@ const ChatInput = ({
2639
2845
  children: [o$1("input", {
2640
2846
  "aria-hidden": "true",
2641
2847
  id: "chat-input",
2642
- class: "outline-neutral-12/5 placeholder:text-neutral-4 focus-visible:outline-accent-9 caret-accent-9 flex-grow rounded-full px-3 py-1 text-base outline outline-2",
2848
+ class: "outline-divider flex-grow rounded-full bg-transparent px-3 py-1 text-base outline outline-2",
2643
2849
  disabled: true
2644
2850
  }), o$1(SendButton, {
2645
2851
  disabled: true,
@@ -2722,11 +2928,11 @@ const cva = (base, config) => {
2722
2928
  return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
2723
2929
  };
2724
2930
  };
2725
- const chatBubbleVariants = cva("max-w-[min(100%,24rem)] [text-wrap:pretty] leading-snug flex-shrink-1 min-w-[2rem] text-md py-2 px-3 rounded-[18px] min-h-[36px] break-words", {
2931
+ const chatBubbleVariants = cva("max-w-[min(100%,24rem)] [text-wrap:pretty] leading-snug flex-shrink min-w-[2rem] py-2 px-3 rounded-[18px] min-h-[36px] break-words", {
2726
2932
  variants: {
2727
2933
  side: {
2728
- left: "bg-lowest text-neutral-12 shadow-surface-sm outline outline-1 outline-neutral-11/[.08] rounded-bl-md",
2729
- right: "ml-auto bg-accent-7 text-lowest rounded-br-md bubble-right"
2934
+ left: "bg-bubble-weak-bg text-neutral-12 shadow-surface-sm outline outline-1 outline-bubble-weak rounded-bl-md",
2935
+ right: "ml-auto bg-accent-9 text-white rounded-br-md shadow-surface-sm shadow-bubble-strong-shadow"
2730
2936
  },
2731
2937
  transitionState: {
2732
2938
  entering: "opacity-0 translate-y-8",
@@ -2789,7 +2995,7 @@ const TypingIndicator = ({
2789
2995
  children: Array.from({
2790
2996
  length: 3
2791
2997
  }, (_2, i2) => o$1("div", {
2792
- class: "bg-accent-7 h-1.5 w-1.5 animate-bounce rounded-full",
2998
+ class: "bg-accent-9 h-1.5 w-1.5 animate-bounce rounded-full",
2793
2999
  style: {
2794
3000
  animationDelay: `${-i2 * 200}ms`
2795
3001
  }
@@ -2800,7 +3006,7 @@ const authorToSide = {
2800
3006
  bot: "left",
2801
3007
  user: "right"
2802
3008
  };
2803
- const systemMessageStyle = cva("w-full select-none py-2 text-center text-[10px] uppercase tracking-widest drop-shadow-[0_1.5px_white]", {
3009
+ const systemMessageStyle = cva("w-full select-none py-2 text-center text-[10px] uppercase tracking-widest drop-shadow-[0_1.5px_var(--i-color-n-1)]", {
2804
3010
  variants: {
2805
3011
  variant: {
2806
3012
  info: "text-neutral-8",
@@ -2810,7 +3016,7 @@ const systemMessageStyle = cva("w-full select-none py-2 text-center text-[10px]
2810
3016
  }
2811
3017
  }
2812
3018
  });
2813
- const JobApplicationMessages = ({
3019
+ const Conversation = ({
2814
3020
  messages,
2815
3021
  isBotTyping
2816
3022
  }) => {
@@ -2840,9 +3046,9 @@ const JobApplicationMessages = ({
2840
3046
  type: "link"
2841
3047
  }, (message2) => {
2842
3048
  return o$1("div", {
2843
- class: "bg-accent-8/5 flex w-full items-center justify-center overflow-hidden rounded-xl py-2",
3049
+ class: "bg-accent-3 flex w-full items-center justify-center overflow-hidden rounded-xl py-2",
2844
3050
  children: o$1("a", {
2845
- class: "bg-lowest shadow-surface-sm ring-accent-8/20 hover:ring-accent-8 active:bg-accent-2 active:text-accent-10 text-accent-9 focus-visible:ring-accent-7/50 flex items-center gap-1.5 truncate rounded-full py-2 pl-4 pr-2.5 no-underline ring-1 transition-all focus:outline-none focus-visible:ring-4 focus-visible:ring-offset-2",
3051
+ class: "bg-lowest shadow-surface-sm ring-accent-6 hover:ring-accent-8 active:bg-accent-2 active:text-accent-10 text-accent-9 focus-visible:ring-accent-7/50 flex items-center gap-1.5 truncate rounded-full py-2 pl-4 pr-2.5 no-underline ring-1 transition-all focus:outline-none focus-visible:ring-4 focus-visible:ring-offset-2",
2846
3052
  target: "_blank",
2847
3053
  href: message2.href,
2848
3054
  children: [message2.text, o$1("svg", {
@@ -3064,7 +3270,7 @@ const JobApplicationContent = ({
3064
3270
  paddingBottom: inputHeight.value
3065
3271
  },
3066
3272
  children: o$1(AnimatePresence, {
3067
- children: o$1(JobApplicationMessages, {
3273
+ children: o$1(Conversation, {
3068
3274
  isBotTyping,
3069
3275
  messages: currentApplication.data.messages
3070
3276
  })