@brainfish-ai/components 0.17.0 → 0.17.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/dist/esm/index.js CHANGED
@@ -2,12 +2,13 @@ import './index.css';export { BrainfishColors } from './colors.js';
2
2
  export { C as ChatSearch, a as ChatSearchProvider, u as useChatSearch, b as useIsChatSearchDirty } from './chunks/ChatSearch.B4QTqo-0.js';
3
3
  export { C as CodeBlock, F as FormattedMessage, M as MemoizedReactMarkdown, a as MermaidDiagram, Z as ZoomableImage, c as addPopupWidgetUtm, b as addUtmParameters } from './chunks/FormattedMessage.BcAkzCZt.js';
4
4
  export { z as MarkdownEditorViewer } from './chunks/markdownTranslator-D7_8pMsF.BHDxZbm8.js';
5
- export { Button, buttonVariants } from './components/ui/button.js';
5
+ import { Button } from './components/ui/button.js';
6
+ export { buttonVariants } from './components/ui/button.js';
6
7
  export { Collapsible, CollapsibleContent, CollapsibleTrigger } from './components/ui/collapsible.js';
7
8
  export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './components/ui/dropdown-menu.js';
8
9
  export { Switch } from './components/ui/switch.js';
9
10
  export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './components/ui/tooltip.js';
10
- export { Textarea } from './components/ui/textarea.js';
11
+ import { Textarea } from './components/ui/textarea.js';
11
12
  export { ScrollArea, ScrollBar } from './components/ui/scroll-area.js';
12
13
  export { Label } from './components/ui/label.js';
13
14
  export { Input } from './components/ui/input.js';
@@ -26,4 +27,111 @@ export { T as TwoLevelCombobox } from './chunks/two-level-combobox.DsWPDcI6.js';
26
27
  export { F as Filter, a as Filters, O as Operator } from './chunks/filters.BMbm1LUz.js';
27
28
  export { F as FileUpload, a as FileUploadStatus, f as formatFileSize } from './chunks/file-upload-status.Vw0Zxmir.js';
28
29
  export { D as DataTable } from './chunks/data-table.CVyV_UqZ.js';
30
+ import * as React from 'react';
31
+ import { Plus } from '@phosphor-icons/react';
32
+ import { c as cn } from './chunks/utils.Cwtlq8dh.js';
33
+
34
+ function InputWithTags({
35
+ title,
36
+ placeholder,
37
+ tags,
38
+ value: controlledValue,
39
+ defaultValue,
40
+ onChange,
41
+ onTagClick,
42
+ singleValue = false,
43
+ className,
44
+ inputClassName,
45
+ tagsClassName,
46
+ disabled,
47
+ name,
48
+ id,
49
+ required,
50
+ maxLength,
51
+ minLength,
52
+ rows
53
+ }) {
54
+ const findTagsInValue = React.useCallback(
55
+ (val) => {
56
+ if (!val) return /* @__PURE__ */ new Set();
57
+ const trimmedVal = val.trim();
58
+ const foundTags = /* @__PURE__ */ new Set();
59
+ for (const tag of tags) {
60
+ const tagValue = tag.value.trim();
61
+ if (singleValue) {
62
+ if (trimmedVal === tagValue) {
63
+ foundTags.add(tag.value);
64
+ }
65
+ } else {
66
+ if (trimmedVal === tagValue || trimmedVal.startsWith(tagValue + " ") || trimmedVal.includes(" " + tagValue + " ") || trimmedVal.endsWith(" " + tagValue)) {
67
+ foundTags.add(tag.value);
68
+ }
69
+ }
70
+ }
71
+ return foundTags;
72
+ },
73
+ [tags, singleValue]
74
+ );
75
+ const initialValue = controlledValue !== void 0 ? controlledValue : defaultValue || "";
76
+ const [internalValue, setInternalValue] = React.useState(defaultValue || "");
77
+ const [clickedTags, setClickedTags] = React.useState(() => findTagsInValue(initialValue));
78
+ const value = controlledValue !== void 0 ? controlledValue : internalValue;
79
+ React.useEffect(() => {
80
+ const currentValue = controlledValue !== void 0 ? controlledValue : internalValue;
81
+ setClickedTags(findTagsInValue(currentValue));
82
+ }, [controlledValue, internalValue, tags, singleValue, findTagsInValue]);
83
+ const availableTags = tags.filter((tag) => !clickedTags.has(tag.value));
84
+ const handleInputChange = (e) => {
85
+ const newValue = e.target.value;
86
+ if (controlledValue === void 0) {
87
+ setInternalValue(newValue);
88
+ setClickedTags(findTagsInValue(newValue));
89
+ }
90
+ onChange?.(newValue);
91
+ };
92
+ const handleTagClick = (tag) => {
93
+ const newValue = singleValue ? tag.value : value ? `${value} ${tag.value}` : tag.value;
94
+ if (controlledValue === void 0) {
95
+ setInternalValue(newValue);
96
+ if (singleValue) {
97
+ setClickedTags(/* @__PURE__ */ new Set([tag.value]));
98
+ } else {
99
+ setClickedTags(findTagsInValue(newValue));
100
+ }
101
+ }
102
+ onChange?.(newValue);
103
+ onTagClick?.(tag);
104
+ };
105
+ return /* @__PURE__ */ React.createElement("div", { className: cn("w-full flex flex-col gap-3", className) }, title && /* @__PURE__ */ React.createElement("label", { htmlFor: id, className: "text-sm font-semibold" }, title), /* @__PURE__ */ React.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React.createElement(
106
+ Textarea,
107
+ {
108
+ id,
109
+ name,
110
+ placeholder,
111
+ value,
112
+ onChange: handleInputChange,
113
+ disabled,
114
+ required,
115
+ maxLength,
116
+ minLength,
117
+ rows,
118
+ className: inputClassName
119
+ }
120
+ )), availableTags.length > 0 && /* @__PURE__ */ React.createElement("div", { className: cn("flex flex-wrap gap-2", tagsClassName) }, availableTags.map((tag, index) => /* @__PURE__ */ React.createElement(
121
+ Button,
122
+ {
123
+ key: `${tag.value}-${index}`,
124
+ type: "button",
125
+ variant: "outline",
126
+ size: "sm",
127
+ onClick: () => handleTagClick(tag),
128
+ disabled,
129
+ className: "rounded-full"
130
+ },
131
+ /* @__PURE__ */ React.createElement(Plus, { size: 16, className: "text-muted-foreground" }),
132
+ /* @__PURE__ */ React.createElement("span", null, tag.label)
133
+ ))));
134
+ }
135
+
136
+ export { Button, InputWithTags, Textarea };
29
137
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/components/input-with-tags/input-with-tags.tsx"],"sourcesContent":["import * as React from 'react';\nimport { Plus } from '@phosphor-icons/react';\n\nimport { cn } from '@/lib/utils';\nimport { Textarea } from '@/components/ui/textarea';\nimport { Button } from '@/components/ui/button';\n\nexport interface Tag {\n label: string;\n value: string;\n}\n\nexport interface InputWithTagsProps {\n title: string;\n placeholder?: string;\n tags: Tag[];\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n onTagClick?: (tag: Tag) => void;\n singleValue?: boolean; // If true, clicking a tag replaces the value instead of appending\n className?: string;\n inputClassName?: string;\n tagsClassName?: string;\n disabled?: boolean;\n // Standard textarea props\n name?: string;\n id?: string;\n required?: boolean;\n maxLength?: number;\n minLength?: number;\n rows?: number;\n}\n\nexport function InputWithTags({\n title,\n placeholder,\n tags,\n value: controlledValue,\n defaultValue,\n onChange,\n onTagClick,\n singleValue = false,\n className,\n inputClassName,\n tagsClassName,\n disabled,\n name,\n id,\n required,\n maxLength,\n minLength,\n rows,\n}: InputWithTagsProps) {\n // Helper to find tags present in value (tags are appended as: `${value} ${tag.value}`)\n const findTagsInValue = React.useCallback(\n (val: string): Set<string> => {\n if (!val) return new Set();\n const trimmedVal = val.trim();\n const foundTags = new Set<string>();\n\n for (const tag of tags) {\n const tagValue = tag.value.trim();\n if (singleValue) {\n if (trimmedVal === tagValue) {\n foundTags.add(tag.value);\n }\n } else {\n // Check if tag appears as complete segment (tags are appended as: `${value} ${tag.value}`)\n // Need to check: exact match, at start, in middle, or at end\n if (\n trimmedVal === tagValue ||\n trimmedVal.startsWith(tagValue + ' ') ||\n trimmedVal.includes(' ' + tagValue + ' ') ||\n trimmedVal.endsWith(' ' + tagValue)\n ) {\n foundTags.add(tag.value);\n }\n }\n }\n\n return foundTags;\n },\n [tags, singleValue],\n );\n\n // Initialize clickedTags based on initial value\n const initialValue = controlledValue !== undefined ? controlledValue : defaultValue || '';\n const [internalValue, setInternalValue] = React.useState(defaultValue || '');\n const [clickedTags, setClickedTags] = React.useState<Set<string>>(() => findTagsInValue(initialValue));\n\n // Use controlled value if provided, otherwise use internal state\n const value = controlledValue !== undefined ? controlledValue : internalValue;\n\n // Update clickedTags when value or tags change\n React.useEffect(() => {\n const currentValue = controlledValue !== undefined ? controlledValue : internalValue;\n setClickedTags(findTagsInValue(currentValue));\n }, [controlledValue, internalValue, tags, singleValue, findTagsInValue]);\n\n // Filter out clicked tags\n const availableTags = tags.filter((tag) => !clickedTags.has(tag.value));\n\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n // Sync clickedTags with the new value in uncontrolled mode\n setClickedTags(findTagsInValue(newValue));\n }\n onChange?.(newValue);\n };\n\n const handleTagClick = (tag: Tag) => {\n const newValue = singleValue ? tag.value : value ? `${value} ${tag.value}` : tag.value;\n if (controlledValue === undefined) {\n // In uncontrolled mode, update state and sync clickedTags immediately\n setInternalValue(newValue);\n // Sync clickedTags with the new value\n if (singleValue) {\n setClickedTags(new Set([tag.value]));\n } else {\n setClickedTags(findTagsInValue(newValue));\n }\n }\n // In controlled mode, only call onChange - let useEffect sync clickedTags when controlledValue updates\n onChange?.(newValue);\n onTagClick?.(tag);\n };\n\n return (\n <div className={cn('w-full flex flex-col gap-3', className)}>\n {title && (\n <label htmlFor={id} className=\"text-sm font-semibold\">\n {title}\n </label>\n )}\n <div className=\"relative w-full\">\n <Textarea\n id={id}\n name={name}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n maxLength={maxLength}\n minLength={minLength}\n rows={rows}\n className={inputClassName}\n />\n </div>\n {availableTags.length > 0 && (\n <div className={cn('flex flex-wrap gap-2', tagsClassName)}>\n {availableTags.map((tag, index) => (\n <Button\n key={`${tag.value}-${index}`}\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => handleTagClick(tag)}\n disabled={disabled}\n className=\"rounded-full\"\n >\n <Plus size={16} className=\"text-muted-foreground\" />\n <span>{tag.label}</span>\n </Button>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -883,6 +883,29 @@ export declare interface InputProps extends default_2.InputHTMLAttributes<HTMLIn
883
883
  endIcon?: Icon;
884
884
  }
885
885
 
886
+ export declare function InputWithTags({ title, placeholder, tags, value: controlledValue, defaultValue, onChange, onTagClick, singleValue, className, inputClassName, tagsClassName, disabled, name, id, required, maxLength, minLength, rows, }: InputWithTagsProps): React_2.JSX.Element;
887
+
888
+ export declare interface InputWithTagsProps {
889
+ title: string;
890
+ placeholder?: string;
891
+ tags: Tag[];
892
+ value?: string;
893
+ defaultValue?: string;
894
+ onChange?: (value: string) => void;
895
+ onTagClick?: (tag: Tag) => void;
896
+ singleValue?: boolean;
897
+ className?: string;
898
+ inputClassName?: string;
899
+ tagsClassName?: string;
900
+ disabled?: boolean;
901
+ name?: string;
902
+ id?: string;
903
+ required?: boolean;
904
+ maxLength?: number;
905
+ minLength?: number;
906
+ rows?: number;
907
+ }
908
+
886
909
  declare type InvokeAction = {
887
910
  type: typeof AnswersActions.INVOKE_ACTION;
888
911
  payload: {
@@ -1143,6 +1166,11 @@ export declare const TableHeader: React_2.ForwardRefExoticComponent<React_2.HTML
1143
1166
 
1144
1167
  export declare const TableRow: React_2.ForwardRefExoticComponent<React_2.HTMLAttributes<HTMLTableRowElement> & React_2.RefAttributes<HTMLTableRowElement>>;
1145
1168
 
1169
+ export declare interface Tag {
1170
+ label: string;
1171
+ value: string;
1172
+ }
1173
+
1146
1174
  export declare const Textarea: React_2.ForwardRefExoticComponent<Omit<React_2.DetailedHTMLProps<React_2.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & React_2.RefAttributes<HTMLTextAreaElement>>;
1147
1175
 
1148
1176
  declare interface TextConfig {