@brainfish-ai/components 0.13.14 → 0.14.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.
Files changed (35) 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/markdown/utils/urls.d.ts +6 -0
  5. package/dist/components/two-level-combobox/index.d.ts +1 -0
  6. package/dist/components/two-level-combobox/two-level-combobox.d.ts +15 -0
  7. package/dist/components/ui/div-button.d.ts +11 -0
  8. package/dist/esm/chunks/{ChatSearch.CicUAtwR.js → ChatSearch.DdKSJqhX.js} +121 -17
  9. package/dist/esm/chunks/ChatSearch.DdKSJqhX.js.map +1 -0
  10. package/dist/esm/chunks/{FormattedMessage.Cmv0Kl8o.js → FormattedMessage.C7CKFL5X.js} +50 -29
  11. package/dist/esm/chunks/FormattedMessage.C7CKFL5X.js.map +1 -0
  12. package/dist/esm/chunks/{combobox.B5aw7PrS.js → combobox.BRm6ZDEB.js} +18 -9
  13. package/dist/esm/chunks/combobox.BRm6ZDEB.js.map +1 -0
  14. package/dist/esm/chunks/index.tOGWkez1.js +123 -0
  15. package/dist/esm/chunks/index.tOGWkez1.js.map +1 -0
  16. package/dist/esm/chunks/two-level-combobox.DFonmrmc.js +132 -0
  17. package/dist/esm/chunks/two-level-combobox.DFonmrmc.js.map +1 -0
  18. package/dist/esm/components/chat-search.js +1 -1
  19. package/dist/esm/components/combobox.js +1 -1
  20. package/dist/esm/components/markdown.js +1 -1
  21. package/dist/esm/components/two-level-combobox.js +2 -0
  22. package/dist/esm/components/two-level-combobox.js.map +1 -0
  23. package/dist/esm/components/ui/button.js +1 -119
  24. package/dist/esm/components/ui/button.js.map +1 -1
  25. package/dist/esm/components/ui/div-button.js +59 -0
  26. package/dist/esm/components/ui/div-button.js.map +1 -0
  27. package/dist/esm/index.css +1 -1
  28. package/dist/esm/index.js +4 -3
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/stats.html +1 -1
  32. package/package.json +3 -1
  33. package/dist/esm/chunks/ChatSearch.CicUAtwR.js.map +0 -1
  34. package/dist/esm/chunks/FormattedMessage.Cmv0Kl8o.js.map +0 -1
  35. 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,6 @@
1
+ interface TimeParams {
2
+ start?: number;
3
+ end?: number;
4
+ }
5
+ export declare const parseTimeParams: (url: string) => TimeParams;
6
+ export {};
@@ -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,8 +2,8 @@ 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';
6
- import { g as getDefaultExportFromCjs, F as FormattedMessage, c as addPopupWidgetUtm } from './FormattedMessage.Cmv0Kl8o.js';
5
+ import { XCircle, Check, Copy, CaretDown, ArrowSquareOut, CaretRight, ArrowsVertical, ArrowDown, Globe, LockSimple, MagnifyingGlass, X, Image, ArrowRight, ArrowLeft, ArrowsInSimple, ArrowsOutSimple } from '@phosphor-icons/react';
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';
9
9
  import require$$0 from 'ajv';
@@ -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" }) {
@@ -4747,6 +4749,10 @@ const PrimarySearch = React__default.forwardRef(
4747
4749
  collections = [],
4748
4750
  currentCollectionId,
4749
4751
  onCollectionChange,
4752
+ allowedRegions = [],
4753
+ onRegionChange,
4754
+ apiKey,
4755
+ fetchRegionConfig,
4750
4756
  disableImageAttachment = false,
4751
4757
  attachedImages = [],
4752
4758
  onImageUpload,
@@ -4757,6 +4763,65 @@ const PrimarySearch = React__default.forwardRef(
4757
4763
  }, ref) => {
4758
4764
  const fileInputRef = useRef(null);
4759
4765
  const [showSuggestions, setShowSuggestions] = useState(false);
4766
+ const regionItems = [
4767
+ {
4768
+ value: "all",
4769
+ label: "All regions",
4770
+ icon: /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" })
4771
+ },
4772
+ ...allowedRegions.map((region) => {
4773
+ const country = getCountry(region);
4774
+ return {
4775
+ value: region,
4776
+ label: country?.name || region,
4777
+ icon: /* @__PURE__ */ React__default.createElement(
4778
+ "img",
4779
+ {
4780
+ alt: `${country?.name || region}`,
4781
+ src: `https://purecatamphetamine.github.io/country-flag-icons/3x2/${region}.svg`,
4782
+ className: "w-5"
4783
+ }
4784
+ )
4785
+ };
4786
+ })
4787
+ ];
4788
+ const fetchCollectionsForRegion = React__default.useCallback(
4789
+ async (regionId) => {
4790
+ if (!apiKey || !fetchRegionConfig) {
4791
+ console.warn("No apiKey or fetchRegionConfig provided, falling back to current collections");
4792
+ return collections.map((collection) => ({
4793
+ value: collection.id,
4794
+ label: collection.name,
4795
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4796
+ }));
4797
+ }
4798
+ try {
4799
+ const regionConfig = await fetchRegionConfig(apiKey, regionId);
4800
+ const regionCollections = regionConfig?.settings?.collections || [];
4801
+ return regionCollections.map((collection) => ({
4802
+ value: collection.id,
4803
+ label: collection.name,
4804
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4805
+ }));
4806
+ } catch (error) {
4807
+ console.error("Error fetching collections for region:", error);
4808
+ return collections.map((collection) => ({
4809
+ value: collection.id,
4810
+ label: collection.name,
4811
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4812
+ }));
4813
+ }
4814
+ },
4815
+ [apiKey, fetchRegionConfig, collections]
4816
+ );
4817
+ const handleSelectionChange = (region, collection) => {
4818
+ if (region && onRegionChange) {
4819
+ onRegionChange(region.value);
4820
+ }
4821
+ if (collection && onCollectionChange) {
4822
+ onCollectionChange(collection.value);
4823
+ }
4824
+ };
4760
4825
  const adjustTextareaHeight = (textarea) => {
4761
4826
  textarea.style.height = "auto";
4762
4827
  textarea.style.height = `${textarea.scrollHeight}px`;
@@ -4868,19 +4933,40 @@ const PrimarySearch = React__default.forwardRef(
4868
4933
  },
4869
4934
  /* @__PURE__ */ React__default.createElement(X, { className: "size-3 text-white", "aria-label": "Remove image" })
4870
4935
  )))),
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(
4936
+ !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 ? (
4937
+ // Two-level selection: Region -> Collection
4938
+ /* @__PURE__ */ React__default.createElement(
4939
+ TwoLevelCombobox,
4940
+ {
4941
+ firstLevelItems: regionItems,
4942
+ fetchSecondLevelItems: fetchCollectionsForRegion,
4943
+ onSelectionChange: handleSelectionChange,
4944
+ firstLevelLabel: "Region",
4945
+ secondLevelLabel: "Collection",
4946
+ firstLevelPlaceholder: "All documents",
4947
+ className: "min-w-[200px]",
4948
+ displayLabel: false
4949
+ }
4950
+ )
4951
+ ) : collections.length > 0 ? (
4952
+ // Single-level selection: Collection only (fallback when no regions)
4953
+ /* @__PURE__ */ React__default.createElement(
4954
+ Combobox,
4955
+ {
4956
+ options: collections.map((collection) => ({
4957
+ value: collection.id,
4958
+ label: collection.name,
4959
+ icon: collection.siteEnabled ? /* @__PURE__ */ React__default.createElement(Globe, { className: "size-4" }) : /* @__PURE__ */ React__default.createElement(LockSimple, { className: "size-4" })
4960
+ })),
4961
+ value: currentCollectionId === "all" ? void 0 : currentCollectionId,
4962
+ defaultValueLabel: "All documents",
4963
+ placeholder: "Select collection",
4964
+ noResultsLabel: "No collections found",
4965
+ dropdownWidth: 200,
4966
+ onChange: (value) => onCollectionChange?.(value)
4967
+ }
4968
+ )
4969
+ ) : null, !disableImageAttachment && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
4884
4970
  "input",
4885
4971
  {
4886
4972
  type: "file",
@@ -5304,6 +5390,10 @@ const ChatSearchComponent = forwardRef(
5304
5390
  collections = [],
5305
5391
  selectedCollectionId,
5306
5392
  onCollectionChange,
5393
+ selectedRegion,
5394
+ onRegionChange,
5395
+ apiKey,
5396
+ fetchRegionConfig,
5307
5397
  searchEndpoint,
5308
5398
  answerStreamEndpoint,
5309
5399
  feedbackEndpoint,
@@ -5355,6 +5445,7 @@ const ChatSearchComponent = forwardRef(
5355
5445
  const [showScrollArrow, setShowScrollArrow] = useState(false);
5356
5446
  const [attachedImages, setAttachedImages] = useState([]);
5357
5447
  const [currentCollectionId, setCurrentCollectionId] = useState(selectedCollectionId);
5448
+ const [currentRegion, setCurrentRegion] = useState(selectedRegion);
5358
5449
  const [showFollowUp, setShowFollowUp] = useState(true);
5359
5450
  const primaryTextareaRef = useRef(null);
5360
5451
  const answerRefs = useRef([]);
@@ -5720,6 +5811,9 @@ const ChatSearchComponent = forwardRef(
5720
5811
  useEffect(() => {
5721
5812
  setCurrentCollectionId(selectedCollectionId);
5722
5813
  }, [selectedCollectionId]);
5814
+ useEffect(() => {
5815
+ setCurrentRegion(selectedRegion);
5816
+ }, [selectedRegion]);
5723
5817
  const adjustTextareaHeight = (textarea) => {
5724
5818
  textarea.style.height = "auto";
5725
5819
  textarea.style.height = `${textarea.scrollHeight}px`;
@@ -5827,6 +5921,11 @@ const ChatSearchComponent = forwardRef(
5827
5921
  setCurrentCollectionId(collectionId);
5828
5922
  onCollectionChange?.(collectionId);
5829
5923
  };
5924
+ const handleRegionChange = (regionId) => {
5925
+ setCurrentRegion(regionId);
5926
+ onRegionChange?.(regionId);
5927
+ trackEvent?.("Region Changed", { region: regionId, conversationId: currentConversationId });
5928
+ };
5830
5929
  useEffect(() => {
5831
5930
  const handleUrlChange = () => {
5832
5931
  const urlParams = new URLSearchParams(window.location.search);
@@ -5914,6 +6013,11 @@ const ChatSearchComponent = forwardRef(
5914
6013
  collections,
5915
6014
  currentCollectionId,
5916
6015
  onCollectionChange: handleCollectionChange,
6016
+ allowedRegions,
6017
+ currentRegion,
6018
+ onRegionChange: handleRegionChange,
6019
+ apiKey,
6020
+ fetchRegionConfig,
5917
6021
  disableImageAttachment,
5918
6022
  attachedImages,
5919
6023
  onImageUpload: handleImageUpload,
@@ -6025,4 +6129,4 @@ const ChatSearch = forwardRef(({ featureFlags, ...props }, ref) => /* @__PURE__
6025
6129
  ChatSearch.displayName = "ChatSearch";
6026
6130
 
6027
6131
  export { ChatSearch as C, ChatSearchProvider as a, useIsChatSearchDirty as b, useChatSearch as u };
6028
- //# sourceMappingURL=ChatSearch.CicUAtwR.js.map
6132
+ //# sourceMappingURL=ChatSearch.DdKSJqhX.js.map