@brainfish-ai/components 0.13.15 → 0.14.2

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.
Files changed (30) hide show
  1. package/dist/components/chat-search/PrimarySearch.d.ts +11 -5
  2. package/dist/components/chat-search/types.d.ts +8 -0
  3. package/dist/components/combobox/combobox.d.ts +9 -5
  4. package/dist/components/two-level-combobox/index.d.ts +1 -0
  5. package/dist/components/two-level-combobox/two-level-combobox.d.ts +15 -0
  6. package/dist/components/ui/div-button.d.ts +11 -0
  7. package/dist/esm/chunks/{ChatSearch.BdkUMxIG.js → ChatSearch.BVivOuWt.js} +123 -17
  8. package/dist/esm/chunks/ChatSearch.BVivOuWt.js.map +1 -0
  9. package/dist/esm/chunks/{combobox.B5aw7PrS.js → combobox.BRm6ZDEB.js} +18 -9
  10. package/dist/esm/chunks/combobox.BRm6ZDEB.js.map +1 -0
  11. package/dist/esm/chunks/index.tOGWkez1.js +123 -0
  12. package/dist/esm/chunks/index.tOGWkez1.js.map +1 -0
  13. package/dist/esm/chunks/two-level-combobox.DFonmrmc.js +132 -0
  14. package/dist/esm/chunks/two-level-combobox.DFonmrmc.js.map +1 -0
  15. package/dist/esm/components/chat-search.js +1 -1
  16. package/dist/esm/components/combobox.js +1 -1
  17. package/dist/esm/components/two-level-combobox.js +2 -0
  18. package/dist/esm/components/two-level-combobox.js.map +1 -0
  19. package/dist/esm/components/ui/button.js +1 -119
  20. package/dist/esm/components/ui/button.js.map +1 -1
  21. package/dist/esm/components/ui/div-button.js +59 -0
  22. package/dist/esm/components/ui/div-button.js.map +1 -0
  23. package/dist/esm/index.css +1 -1
  24. package/dist/esm/index.js +3 -2
  25. package/dist/esm/index.js.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/stats.html +1 -1
  28. package/package.json +3 -1
  29. package/dist/esm/chunks/ChatSearch.BdkUMxIG.js.map +0 -1
  30. package/dist/esm/chunks/combobox.B5aw7PrS.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { default as React } from 'react';
2
- import { Suggestion } from './types';
2
+ import { Collection, Suggestion } from './types';
3
3
  export declare const PrimarySearch: React.ForwardRefExoticComponent<{
4
4
  query: string;
5
5
  onQueryChange: (query: string) => void;
@@ -9,12 +9,18 @@ export declare const PrimarySearch: React.ForwardRefExoticComponent<{
9
9
  attachImageText?: string;
10
10
  allDocumentsText?: string;
11
11
  };
12
- collections?: {
13
- id: string;
14
- name: string;
15
- }[] | undefined;
12
+ collections?: Collection[] | undefined;
16
13
  currentCollectionId?: string | undefined;
17
14
  onCollectionChange?: ((collectionId: string) => void) | undefined;
15
+ allowedRegions?: string[] | undefined;
16
+ currentRegion?: string | undefined;
17
+ onRegionChange?: ((region: string) => void) | undefined;
18
+ apiKey?: string | undefined;
19
+ fetchRegionConfig?: ((apiKey: string, region: string) => Promise<{
20
+ settings?: {
21
+ collections?: Collection[];
22
+ };
23
+ } | null>) | undefined;
18
24
  disableImageAttachment?: boolean | undefined;
19
25
  attachedImages?: {
20
26
  file: File;
@@ -150,6 +150,14 @@ export interface ChatSearchProps {
150
150
  collections?: Array<Collection>;
151
151
  selectedCollectionId?: string;
152
152
  onCollectionChange?: (collectionId: string) => void;
153
+ selectedRegion?: string;
154
+ onRegionChange?: (region: string) => void;
155
+ apiKey?: string;
156
+ fetchRegionConfig?: (apiKey: string, region: string) => Promise<{
157
+ settings?: {
158
+ collections?: Collection[];
159
+ };
160
+ } | null>;
153
161
  searchEndpoint: string;
154
162
  answerEndpoint: string;
155
163
  answerStreamEndpoint: string;
@@ -1,14 +1,18 @@
1
1
  import * as React from 'react';
2
+ export interface ComboboxItem {
3
+ value: string;
4
+ label: string;
5
+ icon?: React.ReactNode;
6
+ }
2
7
  export interface ComboboxProps {
3
- options: {
4
- value: string;
5
- label: string;
6
- }[];
8
+ options: ComboboxItem[];
7
9
  defaultValueLabel: string;
8
10
  placeholder: string;
9
11
  noResultsLabel: string;
10
12
  className?: string;
13
+ dropdownWidth?: number;
14
+ value?: string;
11
15
  onOpenChange?: (open: boolean) => void;
12
16
  onChange?: (value: string) => void;
13
17
  }
14
- export declare function Combobox({ options, defaultValueLabel, placeholder, noResultsLabel, className, onOpenChange, onChange, }: ComboboxProps): React.JSX.Element;
18
+ export declare function Combobox({ options, defaultValueLabel, placeholder, noResultsLabel, className, onOpenChange, onChange, dropdownWidth, value: controlledValue, }: ComboboxProps): React.JSX.Element;
@@ -0,0 +1 @@
1
+ export * from './two-level-combobox';
@@ -0,0 +1,15 @@
1
+ import { ComboboxItem } from '../combobox';
2
+ import * as React from 'react';
3
+ export interface TwoLevelComboboxProps {
4
+ firstLevelItems: ComboboxItem[];
5
+ fetchSecondLevelItems: (firstLevelId: string) => Promise<ComboboxItem[]>;
6
+ onSelectionChange?: (firstLevel: ComboboxItem | null, secondLevel: ComboboxItem | null) => void;
7
+ firstLevelLabel?: string;
8
+ secondLevelLabel?: string;
9
+ firstLevelPlaceholder?: string;
10
+ secondLevelPlaceholder?: string;
11
+ className?: string;
12
+ debugMode?: boolean;
13
+ displayLabel?: boolean;
14
+ }
15
+ export declare function TwoLevelCombobox({ firstLevelItems, fetchSecondLevelItems, onSelectionChange, firstLevelLabel, secondLevelLabel, firstLevelPlaceholder, className, debugMode, displayLabel, }: TwoLevelComboboxProps): React.JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ import * as React from "react";
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "link" | "dark" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
5
+ size?: "default" | "icon" | "sm" | "lg" | null | undefined;
6
+ } & import('class-variance-authority/dist/types').ClassProp) | undefined) => string;
7
+ export interface DivButtonProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof buttonVariants> {
8
+ asChild?: boolean;
9
+ }
10
+ declare const DivButton: React.ForwardRefExoticComponent<DivButtonProps & React.RefAttributes<HTMLDivElement>>;
11
+ export { DivButton, buttonVariants };
@@ -2,7 +2,7 @@ import React__default, { useState, useCallback, useMemo, createContext, useConte
2
2
  import { motion, AnimatePresence } from 'framer-motion';
3
3
  import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '../components/ui/tooltip.js';
4
4
  import { Button } from '../components/ui/button.js';
5
- import { XCircle, Check, Copy, CaretDown, ArrowSquareOut, CaretRight, ArrowsVertical, ArrowDown, MagnifyingGlass, X, CheckCircle, Circle, Image, ArrowRight, ArrowLeft, ArrowsInSimple, ArrowsOutSimple } from '@phosphor-icons/react';
5
+ import { XCircle, Check, Copy, CaretDown, ArrowSquareOut, CaretRight, ArrowsVertical, ArrowDown, Globe, LockSimple, MagnifyingGlass, X, Image, ArrowRight, ArrowLeft, ArrowsInSimple, ArrowsOutSimple } from '@phosphor-icons/react';
6
6
  import { g as getDefaultExportFromCjs, F as FormattedMessage, c as addPopupWidgetUtm } from './FormattedMessage.C7CKFL5X.js';
7
7
  import { appendErrors, useForm, Controller } from 'react-hook-form';
8
8
  import { validateFieldsNatively, toNestErrors } from '@hookform/resolvers';
@@ -20,7 +20,9 @@ import { MemoizedIcon } from '../components/ui/icon.js';
20
20
  import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '../components/ui/collapsible.js';
21
21
  import { F as Feedback } from './feedback.NWn6_mYe.js';
22
22
  import { G as GeneratingStar } from './generating-star.B0RUXRff.js';
23
- import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '../components/ui/dropdown-menu.js';
23
+ import { getCountry } from 'countries-and-timezones';
24
+ import { C as Combobox } from './combobox.BRm6ZDEB.js';
25
+ import { T as TwoLevelCombobox } from './two-level-combobox.DFonmrmc.js';
24
26
  import { ScrollArea } from '../components/ui/scroll-area.js';
25
27
 
26
28
  import '../ChatSearch.css';function Suggestions({ suggestions, onQuestionClick, title = "Suggested questions" }) {
@@ -4252,6 +4254,7 @@ async function searchApi({
4252
4254
  secretAttributes,
4253
4255
  allowedRegions
4254
4256
  }) {
4257
+ const isAgentAssist = !!headers?.["x-brainfish-agent-assist"] && headers?.["x-brainfish-agent-assist"] !== "false";
4255
4258
  const payload = await makeRequest(endpoint, {
4256
4259
  method: "POST",
4257
4260
  headers,
@@ -4263,7 +4266,8 @@ async function searchApi({
4263
4266
  ...conversationId && { conversationId },
4264
4267
  ...attributes && { attributes },
4265
4268
  ...secretAttributes && { secretAttributes },
4266
- ...allowedRegions && { allowedRegions }
4269
+ ...allowedRegions && { allowedRegions },
4270
+ ...isAgentAssist && { source: "agent_assist" }
4267
4271
  }
4268
4272
  });
4269
4273
  return {
@@ -4747,6 +4751,10 @@ const PrimarySearch = React__default.forwardRef(
4747
4751
  collections = [],
4748
4752
  currentCollectionId,
4749
4753
  onCollectionChange,
4754
+ allowedRegions = [],
4755
+ onRegionChange,
4756
+ apiKey,
4757
+ fetchRegionConfig,
4750
4758
  disableImageAttachment = false,
4751
4759
  attachedImages = [],
4752
4760
  onImageUpload,
@@ -4757,6 +4765,65 @@ const PrimarySearch = React__default.forwardRef(
4757
4765
  }, ref) => {
4758
4766
  const fileInputRef = useRef(null);
4759
4767
  const [showSuggestions, setShowSuggestions] = useState(false);
4768
+ const regionItems = [
4769
+ {
4770
+ value: "all",
4771
+ label: "All regions",
4772
+ icon: /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" })
4773
+ },
4774
+ ...allowedRegions.map((region) => {
4775
+ const country = getCountry(region);
4776
+ return {
4777
+ value: region,
4778
+ label: country?.name || region,
4779
+ icon: /* @__PURE__ */ React__default.createElement(
4780
+ "img",
4781
+ {
4782
+ alt: `${country?.name || region}`,
4783
+ src: `https://purecatamphetamine.github.io/country-flag-icons/3x2/${region}.svg`,
4784
+ className: "w-5"
4785
+ }
4786
+ )
4787
+ };
4788
+ })
4789
+ ];
4790
+ const fetchCollectionsForRegion = React__default.useCallback(
4791
+ async (regionId) => {
4792
+ if (!apiKey || !fetchRegionConfig) {
4793
+ console.warn("No apiKey or fetchRegionConfig provided, falling back to current collections");
4794
+ return collections.map((collection) => ({
4795
+ value: collection.id,
4796
+ label: collection.name,
4797
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4798
+ }));
4799
+ }
4800
+ try {
4801
+ const regionConfig = await fetchRegionConfig(apiKey, regionId);
4802
+ const regionCollections = regionConfig?.settings?.collections || [];
4803
+ return regionCollections.map((collection) => ({
4804
+ value: collection.id,
4805
+ label: collection.name,
4806
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4807
+ }));
4808
+ } catch (error) {
4809
+ console.error("Error fetching collections for region:", error);
4810
+ return collections.map((collection) => ({
4811
+ value: collection.id,
4812
+ label: collection.name,
4813
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4814
+ }));
4815
+ }
4816
+ },
4817
+ [apiKey, fetchRegionConfig, collections]
4818
+ );
4819
+ const handleSelectionChange = (region, collection) => {
4820
+ if (region && onRegionChange) {
4821
+ onRegionChange(region.value);
4822
+ }
4823
+ if (collection && onCollectionChange) {
4824
+ onCollectionChange(collection.value);
4825
+ }
4826
+ };
4760
4827
  const adjustTextareaHeight = (textarea) => {
4761
4828
  textarea.style.height = "auto";
4762
4829
  textarea.style.height = `${textarea.scrollHeight}px`;
@@ -4868,19 +4935,40 @@ const PrimarySearch = React__default.forwardRef(
4868
4935
  },
4869
4936
  /* @__PURE__ */ React__default.createElement(X, { className: "size-3 text-white", "aria-label": "Remove image" })
4870
4937
  )))),
4871
- !shouldShowSuggestions && /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center justify-between px-3 py-2 border-t border-border" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex gap-1", "data-name": "collections-dropdown" }, collections.length > 0 && /* @__PURE__ */ React__default.createElement(DropdownMenu, null, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger, { asChild: true }, /* @__PURE__ */ React__default.createElement(
4872
- Button,
4873
- {
4874
- variant: "ghost",
4875
- size: "sm",
4876
- className: cn(
4877
- "transition-all duration-200 rounded-md h-8",
4878
- "flex items-center gap-1 hover:bg-opacity-80 text-foreground"
4879
- )
4880
- },
4881
- collections.find((c) => c.id === currentCollectionId)?.name || textConfig.allDocumentsText || "All documents",
4882
- /* @__PURE__ */ React__default.createElement(CaretDown, { className: "size-4 text-secondary-foreground" })
4883
- )), /* @__PURE__ */ React__default.createElement(DropdownMenuContent, { className: "max-w-48" }, collections.map((collection) => /* @__PURE__ */ React__default.createElement(DropdownMenuItem, { key: collection.id, onClick: () => onCollectionChange?.(collection.id) }, collection.id === currentCollectionId ? /* @__PURE__ */ React__default.createElement(CheckCircle, { className: "rounded-full text-primary-500 !size-5", weight: "fill" }) : /* @__PURE__ */ React__default.createElement(Circle, { className: "rounded-full !size-5 text-gray-300" }), /* @__PURE__ */ React__default.createElement("span", { className: "text-sm truncate" }, collection.name))))), !disableImageAttachment && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
4938
+ !shouldShowSuggestions && /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center justify-between px-3 py-2 border-t border-border" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex gap-1", "data-name": "collections-dropdown" }, allowedRegions.length > 0 && collections.length > 0 ? (
4939
+ // Two-level selection: Region -> Collection
4940
+ /* @__PURE__ */ React__default.createElement(
4941
+ TwoLevelCombobox,
4942
+ {
4943
+ firstLevelItems: regionItems,
4944
+ fetchSecondLevelItems: fetchCollectionsForRegion,
4945
+ onSelectionChange: handleSelectionChange,
4946
+ firstLevelLabel: "Region",
4947
+ secondLevelLabel: "Collection",
4948
+ firstLevelPlaceholder: "All documents",
4949
+ className: "min-w-[200px]",
4950
+ displayLabel: false
4951
+ }
4952
+ )
4953
+ ) : collections.length > 0 ? (
4954
+ // Single-level selection: Collection only (fallback when no regions)
4955
+ /* @__PURE__ */ React__default.createElement(
4956
+ Combobox,
4957
+ {
4958
+ options: collections.map((collection) => ({
4959
+ value: collection.id,
4960
+ label: collection.name,
4961
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4962
+ })),
4963
+ value: currentCollectionId === "all" ? void 0 : currentCollectionId,
4964
+ defaultValueLabel: "All documents",
4965
+ placeholder: "Select collection",
4966
+ noResultsLabel: "No collections found",
4967
+ dropdownWidth: 200,
4968
+ onChange: (value) => onCollectionChange?.(value)
4969
+ }
4970
+ )
4971
+ ) : null, !disableImageAttachment && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
4884
4972
  "input",
4885
4973
  {
4886
4974
  type: "file",
@@ -5304,6 +5392,10 @@ const ChatSearchComponent = forwardRef(
5304
5392
  collections = [],
5305
5393
  selectedCollectionId,
5306
5394
  onCollectionChange,
5395
+ selectedRegion,
5396
+ onRegionChange,
5397
+ apiKey,
5398
+ fetchRegionConfig,
5307
5399
  searchEndpoint,
5308
5400
  answerStreamEndpoint,
5309
5401
  feedbackEndpoint,
@@ -5355,6 +5447,7 @@ const ChatSearchComponent = forwardRef(
5355
5447
  const [showScrollArrow, setShowScrollArrow] = useState(false);
5356
5448
  const [attachedImages, setAttachedImages] = useState([]);
5357
5449
  const [currentCollectionId, setCurrentCollectionId] = useState(selectedCollectionId);
5450
+ const [currentRegion, setCurrentRegion] = useState(selectedRegion);
5358
5451
  const [showFollowUp, setShowFollowUp] = useState(true);
5359
5452
  const primaryTextareaRef = useRef(null);
5360
5453
  const answerRefs = useRef([]);
@@ -5720,6 +5813,9 @@ const ChatSearchComponent = forwardRef(
5720
5813
  useEffect(() => {
5721
5814
  setCurrentCollectionId(selectedCollectionId);
5722
5815
  }, [selectedCollectionId]);
5816
+ useEffect(() => {
5817
+ setCurrentRegion(selectedRegion);
5818
+ }, [selectedRegion]);
5723
5819
  const adjustTextareaHeight = (textarea) => {
5724
5820
  textarea.style.height = "auto";
5725
5821
  textarea.style.height = `${textarea.scrollHeight}px`;
@@ -5827,6 +5923,11 @@ const ChatSearchComponent = forwardRef(
5827
5923
  setCurrentCollectionId(collectionId);
5828
5924
  onCollectionChange?.(collectionId);
5829
5925
  };
5926
+ const handleRegionChange = (regionId) => {
5927
+ setCurrentRegion(regionId);
5928
+ onRegionChange?.(regionId);
5929
+ trackEvent?.("Region Changed", { region: regionId, conversationId: currentConversationId });
5930
+ };
5830
5931
  useEffect(() => {
5831
5932
  const handleUrlChange = () => {
5832
5933
  const urlParams = new URLSearchParams(window.location.search);
@@ -5914,6 +6015,11 @@ const ChatSearchComponent = forwardRef(
5914
6015
  collections,
5915
6016
  currentCollectionId,
5916
6017
  onCollectionChange: handleCollectionChange,
6018
+ allowedRegions,
6019
+ currentRegion,
6020
+ onRegionChange: handleRegionChange,
6021
+ apiKey,
6022
+ fetchRegionConfig,
5917
6023
  disableImageAttachment,
5918
6024
  attachedImages,
5919
6025
  onImageUpload: handleImageUpload,
@@ -6025,4 +6131,4 @@ const ChatSearch = forwardRef(({ featureFlags, ...props }, ref) => /* @__PURE__
6025
6131
  ChatSearch.displayName = "ChatSearch";
6026
6132
 
6027
6133
  export { ChatSearch as C, ChatSearchProvider as a, useIsChatSearchDirty as b, useChatSearch as u };
6028
- //# sourceMappingURL=ChatSearch.BdkUMxIG.js.map
6134
+ //# sourceMappingURL=ChatSearch.BVivOuWt.js.map