@brainfish-ai/components 0.37.0 → 0.37.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.
@@ -1169,7 +1169,7 @@ const ChatSearchComponent = forwardRef(
1169
1169
  offset
1170
1170
  }
1171
1171
  )),
1172
- disclaimer?.trim() !== "" && isWidgetMode && !(showResults && showFollowUp) && /* @__PURE__ */ React__default.createElement(
1172
+ disclaimer && isWidgetMode && !(showResults && showFollowUp) && /* @__PURE__ */ React__default.createElement(
1173
1173
  "div",
1174
1174
  {
1175
1175
  "data-name": "disclaimer",
@@ -3641,6 +3641,48 @@ strong {
3641
3641
  color: var(--bfc-warning-text);
3642
3642
  }
3643
3643
 
3644
+ .before\:pointer-events-none::before{
3645
+ content: var(--tw-content);
3646
+ pointer-events: none;
3647
+ }
3648
+
3649
+ .before\:absolute::before{
3650
+ content: var(--tw-content);
3651
+ position: absolute;
3652
+ }
3653
+
3654
+ .before\:inset-0::before{
3655
+ content: var(--tw-content);
3656
+ inset: 0px;
3657
+ }
3658
+
3659
+ @keyframes article-drop-pulse{0%{
3660
+ content: var(--tw-content);
3661
+ opacity: 0.1;
3662
+ }20%{
3663
+ content: var(--tw-content);
3664
+ opacity: 0.2;
3665
+ }50%{
3666
+ content: var(--tw-content);
3667
+ opacity: 0.6;
3668
+ }
3669
+ }
3670
+
3671
+ .before\:animate-article-drop-pulse::before{
3672
+ content: var(--tw-content);
3673
+ animation: article-drop-pulse 600ms ease-out;
3674
+ }
3675
+
3676
+ .before\:bg-primary::before{
3677
+ content: var(--tw-content);
3678
+ background-color: var(--bfc-primary);
3679
+ }
3680
+
3681
+ .before\:opacity-0::before{
3682
+ content: var(--tw-content);
3683
+ opacity: 0;
3684
+ }
3685
+
3644
3686
  .after\:absolute::after{
3645
3687
  content: var(--tw-content);
3646
3688
  position: absolute;
@@ -7,6 +7,7 @@ import { Button as Button$1 } from '../../../components/ui/button.js';
7
7
  import { ButtonGroup } from '../../../components/ui/button-group.js';
8
8
  import { ArticleStatusIcon } from './status-icons/article-status-icon.js';
9
9
 
10
+ const JustDroppedIdContext = React.createContext(null);
10
11
  function ArticleItem({
11
12
  item,
12
13
  hasChildItems,
@@ -20,6 +21,8 @@ function ArticleItem({
20
21
  level
21
22
  }) {
22
23
  const { isSearching } = useSidebar();
24
+ const justDroppedId = React.useContext(JustDroppedIdContext);
25
+ const justDropped = justDroppedId === item.value.id;
23
26
  const treeState = React.useContext(TreeStateContext);
24
27
  const shouldPreventNavigation = Boolean(isSelected);
25
28
  const handleAddClick = (e) => {
@@ -60,7 +63,8 @@ function ArticleItem({
60
63
  className: cn(
61
64
  "group relative flex items-center gap-1 rounded-md py-1 pl-1 ml-[calc((var(--tree-item-level)-1)*var(--line-offset))] pr-4 h-9",
62
65
  isDraft && "text-subtlest italic",
63
- isSelected ? "bg-lime-100 text-default font-bold after:absolute after:-right-0.5 after:top-1/2 after:h-1/2 after:w-1 after:-translate-y-1/2 after:bg-lime-400" : "hover:bg-dark-200 hover:text-accent-foreground"
66
+ isSelected ? "bg-lime-100 text-default font-bold after:absolute after:-right-0.5 after:top-1/2 after:h-1/2 after:w-1 after:-translate-y-1/2 after:bg-lime-400" : "hover:bg-dark-200 hover:text-accent-foreground",
67
+ justDropped && "before:animate-article-drop-pulse before:bg-primary before:opacity-0 before:inset-0 before:absolute before:pointer-events-none"
64
68
  )
65
69
  },
66
70
  Array.from({ length: level - 1 }, (_, i) => /* @__PURE__ */ React.createElement(
@@ -135,4 +139,4 @@ function ArticleItem({
135
139
  );
136
140
  }
137
141
 
138
- export { ArticleItem };
142
+ export { ArticleItem, JustDroppedIdContext };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useTreeData, useDragAndDrop, DropIndicator, Tree, TreeItem, TreeItemContent, Collection } from 'react-aria-components';
3
- import { ArticleItem } from './article-item.js';
3
+ import { JustDroppedIdContext, ArticleItem } from './article-item.js';
4
4
  import { ArticleSearchResults } from './article-search-results.js';
5
5
  import { useSidebar } from '../context.js';
6
6
  import { getNewlyExpandedKeys } from './expansion.js';
@@ -68,6 +68,14 @@ function ArticleTree({ articles, isSearching, renderEmptyState }) {
68
68
  }
69
69
  });
70
70
  }, [articles, articlesTree]);
71
+ const [expandedKeysState, setExpandedKeysState] = React.useState(/* @__PURE__ */ new Set());
72
+ const [justDroppedId, setJustDroppedId] = React.useState(null);
73
+ React.useEffect(() => {
74
+ if (!justDroppedId) return;
75
+ const ANIMATION_DURATION = 600;
76
+ const timeoutId = window.setTimeout(() => setJustDroppedId(null), ANIMATION_DURATION);
77
+ return () => window.clearTimeout(timeoutId);
78
+ }, [justDroppedId]);
71
79
  const { dragAndDropHooks } = useDragAndDrop({
72
80
  getItems: (_keys, items) => items.map((item) => ({
73
81
  "text/plain": item.value.label
@@ -103,14 +111,20 @@ function ArticleTree({ articles, isSearching, renderEmptyState }) {
103
111
  const originalIndex = originalSiblings.findIndex((i) => i.key === movedArticleId);
104
112
  if (e.target.dropPosition === "on") {
105
113
  articlesTree.move(movedArticleId, movedToParentId, movedToIndex);
114
+ if (movedToParentId) {
115
+ setExpandedKeysState((prev) => /* @__PURE__ */ new Set([...prev, movedToParentId]));
116
+ onExpandArticle?.(movedToParentId);
117
+ }
106
118
  } else if (e.target.dropPosition === "before") {
107
119
  articlesTree.moveBefore(e.target.key, e.keys);
108
120
  } else {
109
121
  articlesTree.moveAfter(e.target.key, e.keys);
110
122
  }
123
+ setJustDroppedId(movedArticleId.toString());
111
124
  const result = onMoveArticle?.(moveDetails);
112
125
  if (result && typeof result.then === "function") {
113
126
  result.catch(() => {
127
+ setJustDroppedId(null);
114
128
  articlesTree.move(movedArticleId, originalParentId, originalIndex);
115
129
  });
116
130
  }
@@ -133,7 +147,6 @@ function ArticleTree({ articles, isSearching, renderEmptyState }) {
133
147
  const path = getParentKeys(articles, effectiveActiveId);
134
148
  return path ?? [];
135
149
  }, [articles, effectiveActiveId, isSearching]);
136
- const [expandedKeysState, setExpandedKeysState] = React.useState(/* @__PURE__ */ new Set());
137
150
  const expandedKeys = React.useMemo(
138
151
  () => /* @__PURE__ */ new Set([...pathToActive, ...expandedKeysState]),
139
152
  [pathToActive, expandedKeysState]
@@ -183,7 +196,7 @@ function ArticleTree({ articles, isSearching, renderEmptyState }) {
183
196
  if (isSearching) {
184
197
  return /* @__PURE__ */ React.createElement(ArticleSearchResults, { articles });
185
198
  }
186
- return /* @__PURE__ */ React.createElement(
199
+ return /* @__PURE__ */ React.createElement(JustDroppedIdContext.Provider, { value: justDroppedId }, /* @__PURE__ */ React.createElement(
187
200
  Tree,
188
201
  {
189
202
  "aria-label": isSearching ? "Search results" : "Articles tree",
@@ -237,7 +250,7 @@ function ArticleTree({ articles, isSearching, renderEmptyState }) {
237
250
  !isSearching && item.children && /* @__PURE__ */ React.createElement(Collection, { items: item.children }, renderItem)
238
251
  );
239
252
  }
240
- );
253
+ ));
241
254
  }
242
255
 
243
256
  export { ArticleTree, getParentKeys };
@@ -131,12 +131,18 @@ const preset = {
131
131
  sweep: {
132
132
  "0%": { backgroundPosition: "100% center" },
133
133
  "100%": { backgroundPosition: "-100% center" }
134
+ },
135
+ "article-drop-pulse": {
136
+ "0%": { opacity: "0.1" },
137
+ "20%": { opacity: "0.2" },
138
+ "50%": { opacity: "0.6" }
134
139
  }
135
140
  },
136
141
  animation: {
137
142
  "accordion-down": "accordion-down 0.2s ease-out",
138
143
  "accordion-up": "accordion-up 0.2s ease-out",
139
- sweep: "sweep 1.8s linear infinite"
144
+ sweep: "sweep 1.8s linear infinite",
145
+ "article-drop-pulse": "article-drop-pulse 600ms ease-out"
140
146
  },
141
147
  maxWidth: {
142
148
  threadWidth: "1400px"
@@ -1,6 +1,7 @@
1
1
  import { Key, TreeItemContentRenderProps } from 'react-aria-components';
2
2
  import { ArticleNavItem, ItemLinkComponent } from '../types';
3
3
  import * as React from 'react';
4
+ export declare const JustDroppedIdContext: React.Context<string | null>;
4
5
  type ArticleItemTreeNode = {
5
6
  key: Key;
6
7
  value: ArticleNavItem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainfish-ai/components",
3
- "version": "0.37.0",
3
+ "version": "0.37.2",
4
4
  "description": "Brainfish Components",
5
5
  "license": "MIT",
6
6
  "main": "./dist/esm/index.js",
@@ -137,11 +137,17 @@ const preset: Partial<Config> = {
137
137
  '0%': { backgroundPosition: '100% center' },
138
138
  '100%': { backgroundPosition: '-100% center' },
139
139
  },
140
+ 'article-drop-pulse': {
141
+ '0%': { opacity: '0.1' },
142
+ '20%': { opacity: '0.2' },
143
+ '50%': { opacity: '0.6' },
144
+ },
140
145
  },
141
146
  animation: {
142
147
  'accordion-down': 'accordion-down 0.2s ease-out',
143
148
  'accordion-up': 'accordion-up 0.2s ease-out',
144
149
  sweep: 'sweep 1.8s linear infinite',
150
+ 'article-drop-pulse': 'article-drop-pulse 600ms ease-out',
145
151
  },
146
152
  maxWidth: {
147
153
  threadWidth: '1400px',