@noya-app/noya-designsystem 0.1.48 → 0.1.50

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 (55) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +347 -173
  5. package/dist/index.d.ts +347 -173
  6. package/dist/index.js +3602 -2811
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +4761 -3993
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -5
  11. package/src/__tests__/validateDropIndicator.test.ts +4 -4
  12. package/src/components/ActionMenu.tsx +15 -4
  13. package/src/components/Avatar.tsx +2 -2
  14. package/src/components/Banner.tsx +29 -0
  15. package/src/components/BaseToolbar.tsx +2 -2
  16. package/src/components/Button.tsx +2 -2
  17. package/src/components/Checkbox.tsx +2 -2
  18. package/src/components/Chip.tsx +15 -14
  19. package/src/components/Collection.tsx +25 -2
  20. package/src/components/Combobox.tsx +22 -23
  21. package/src/components/ComboboxMenu.tsx +1 -1
  22. package/src/components/Dialog.tsx +2 -2
  23. package/src/components/DimensionInput.tsx +14 -12
  24. package/src/components/EditableText.tsx +3 -1
  25. package/src/components/FillInputField.tsx +2 -2
  26. package/src/components/Grid.tsx +131 -113
  27. package/src/components/GridView.tsx +36 -18
  28. package/src/components/InputField.tsx +116 -171
  29. package/src/components/Label.tsx +14 -73
  30. package/src/components/LabeledField.tsx +13 -2
  31. package/src/components/List.tsx +106 -47
  32. package/src/components/ListView.tsx +52 -31
  33. package/src/components/MediaThumbnail.tsx +14 -6
  34. package/src/components/Message.tsx +8 -8
  35. package/src/components/NoyaLogo.tsx +41 -0
  36. package/src/components/Popover.tsx +9 -6
  37. package/src/components/Section.tsx +172 -0
  38. package/src/components/SegmentedControl.tsx +1 -1
  39. package/src/components/SelectMenu.tsx +9 -4
  40. package/src/components/Slider.tsx +16 -7
  41. package/src/components/Sortable.tsx +186 -47
  42. package/src/components/UserPointer.tsx +1 -1
  43. package/src/components/ai-assistant/AIAssistantLayout.tsx +102 -0
  44. package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +71 -0
  45. package/src/components/file-explorer/FileExplorerLayout.tsx +71 -0
  46. package/src/components/internal/Menu.tsx +20 -10
  47. package/src/components/internal/SelectItem.tsx +3 -2
  48. package/src/components/pipeline/PipelineResultLayout.tsx +32 -0
  49. package/src/index.css +118 -112
  50. package/src/index.tsx +9 -0
  51. package/src/theme/index.ts +2 -0
  52. package/src/utils/classNames.ts +76 -3
  53. package/src/utils/inputs.ts +21 -0
  54. package/src/utils/moveTreeItem.ts +99 -0
  55. package/tailwind.config.ts +82 -75
@@ -3,16 +3,18 @@ import {
3
3
  memoGeneric,
4
4
  useFileDropTarget,
5
5
  } from "@noya-app/react-utils";
6
- import React, { useImperativeHandle, useRef, useState } from "react";
6
+ import React, { memo, useImperativeHandle, useRef, useState } from "react";
7
7
  import { cssVars } from "../theme";
8
8
  import { cx } from "../utils/classNames";
9
9
  import { updateSelection } from "../utils/selection";
10
10
  import { ActionMenu } from "./ActionMenu";
11
11
  import { CollectionProps, CollectionRef } from "./Collection";
12
- import { ListView } from "./ListView";
12
+ import { GridViewSize } from "./Grid";
13
+ import { ListView, ListViewItemInfo } from "./ListView";
13
14
  import { TreeView } from "./TreeView";
15
+
14
16
  const cssVarOverrides = {
15
- "--icon-selected": cssVars.colors.primary,
17
+ "--n-icon-selected": cssVars.colors.primary,
16
18
  };
17
19
 
18
20
  const emptyArray: string[] = [];
@@ -42,8 +44,10 @@ export const List = memoGeneric(
42
44
  itemRoleDescription = "clickable item",
43
45
  detailPosition = "end",
44
46
  size = "medium",
47
+ thumbnailSize = "auto",
45
48
  testHoveredId,
46
49
  testRenamingId,
50
+ testShowDropIndicatorId,
47
51
  scrollable = false,
48
52
  acceptsDrop,
49
53
  onMoveItem,
@@ -52,6 +56,11 @@ export const List = memoGeneric(
52
56
  renamable,
53
57
  selectedIds = emptyArray,
54
58
  renderEmptyState,
59
+ sortable,
60
+ getDropTargetParentIndex,
61
+ getPlaceholder,
62
+ onClickItem,
63
+ dragIndicatorStyle,
55
64
  } = props;
56
65
 
57
66
  const [internalHoveredId, setHoveredId] = useState<string>();
@@ -116,19 +125,21 @@ export const List = memoGeneric(
116
125
  aria-orientation="vertical"
117
126
  aria-multiselectable={true}
118
127
  expandable={expandable}
119
- sortable={expandable}
128
+ sortable={sortable}
120
129
  acceptsDrop={acceptsDrop}
121
130
  onMoveItem={onMoveItem}
122
131
  renderEmptyState={renderEmptyState}
132
+ getDropTargetParentIndex={getDropTargetParentIndex}
123
133
  {...dropTargetProps}
124
134
  renderItem={(
125
135
  item: T,
126
136
  _: number,
127
- { isDragging }: { isDragging: boolean }
137
+ { isDragOverlay }: ListViewItemInfo
128
138
  ) => {
129
139
  const id = getId(item);
130
140
  const isDropdownOpen = dropdownOpenId === id;
131
- const isHovered = (hoveredId === id || isDropdownOpen) && !isDragging;
141
+ const isHovered =
142
+ (hoveredId === id || isDropdownOpen) && !isDragOverlay;
132
143
  const expanded = getExpanded?.(item);
133
144
  const itemIsRenamable = getRenamable?.(item) ?? renamable;
134
145
  const isSelected = selectedIds.includes(id);
@@ -139,24 +150,25 @@ export const List = memoGeneric(
139
150
  item,
140
151
  selected: isSelected,
141
152
  });
153
+ const onOpenChange = (open: boolean) => {
154
+ setDropdownOpenId(open ? id : undefined);
155
+
156
+ if (open && !isSelected) {
157
+ handleSelect(id);
158
+ }
159
+ };
142
160
  const action =
143
161
  (isHovered || isSelected) &&
144
162
  !isRenaming &&
145
163
  (typeof renderAction === "function"
146
- ? renderAction(item, isSelected)
164
+ ? renderAction({ item, selected: isSelected, onOpenChange })
147
165
  : renderAction === "menu" &&
148
166
  menuItems && (
149
167
  <ActionMenu
150
168
  menuItems={menuItems}
151
169
  onSelect={(action) => handleMenuAction(action, item)}
152
170
  selected={isSelected}
153
- onOpenChange={(open) => {
154
- setDropdownOpenId(open ? id : undefined);
155
-
156
- if (open && !isSelected) {
157
- handleSelect(id);
158
- }
159
- }}
171
+ onOpenChange={onOpenChange}
160
172
  />
161
173
  ));
162
174
 
@@ -171,14 +183,17 @@ export const List = memoGeneric(
171
183
  id={id}
172
184
  key={id}
173
185
  role="option"
174
- sortable={expandable}
186
+ sortable={sortable}
175
187
  aria-roledescription={itemRoleDescription}
176
188
  aria-label={getName(item)}
177
189
  aria-selected={isSelected}
178
- className={cx("cursor-pointer p-1 rounded")}
190
+ className={cx("cursor-pointer rounded px-1", pyMap[size])}
179
191
  backgroundColor={
180
192
  isSelected ? cssVars.colors.primaryPastel : undefined
181
193
  }
194
+ testRelativeDropPosition={
195
+ testShowDropIndicatorId === id ? "inside" : undefined
196
+ }
182
197
  chevronClassName={cx(expandable && "relative left-2")}
183
198
  style={cssVarOverrides as React.CSSProperties}
184
199
  hovered={isHovered}
@@ -190,6 +205,7 @@ export const List = memoGeneric(
190
205
  }
191
206
  onPress={(e: ListView.ClickInfo) => {
192
207
  handleSelect(id, e);
208
+ onClickItem?.(id);
193
209
  }}
194
210
  onDoubleClick={() => {
195
211
  onDoubleClickItem?.(id);
@@ -214,45 +230,44 @@ export const List = memoGeneric(
214
230
  if (!expandable) return;
215
231
  setExpanded?.(item, !expanded);
216
232
  }}
233
+ dragIndicatorStyle={dragIndicatorStyle}
217
234
  >
218
- <div className="flex flex-1 items-center px-2 gap-3">
235
+ <div
236
+ className={cx("flex flex-1 items-center px-2", rowGapMap[size])}
237
+ >
219
238
  {thumbnail && (
220
239
  <div
221
240
  className={cx(
222
241
  "rounded overflow-hidden flex-none flex items-center justify-center",
223
- size === "medium" ? "w-8 h-8" : "w-16 h-16",
242
+ thumbnailSize === "auto" && thumbnailSizeMap[size],
224
243
  isSelected && "text-primary"
225
244
  )}
226
- style={{
227
- backgroundColor: isSelected
228
- ? cssVars.colors.primaryPastel
229
- : cssVars.colors.inputBackground,
230
- }}
231
245
  tabIndex={-1}
232
246
  >
233
247
  {thumbnail}
234
248
  </div>
235
249
  )}
236
250
  <div className="flex flex-col flex-1 w-0">
237
- <div className="flex items-center min-h-[27px] flex-1 gap-2">
251
+ <div className="flex items-center min-h-input-height flex-1 gap-2">
238
252
  <div className="flex-1 w-0 flex items-center" tabIndex={-1}>
239
253
  {isRenaming ? (
240
254
  <ViewComponent.EditableRowTitle
241
255
  value={getName(item)}
242
- placeholder="Enter name"
243
- className="font-medium"
256
+ placeholder={getPlaceholder?.(item) ?? "Enter name"}
257
+ className={fontStyleMap[size]}
244
258
  autoFocus={!isTestingRenaming}
245
259
  onSubmitEditing={(value: string) => {
246
- if (value !== getName(item)) {
247
- onRename?.(item, value);
248
- }
260
+ onRename?.(item, value);
249
261
  setRenamingId(undefined);
250
262
  }}
263
+ onKeyDown={(e: React.KeyboardEvent) => {
264
+ e.stopPropagation();
265
+ }}
251
266
  />
252
267
  ) : (
253
268
  <ViewComponent.RowTitle
254
269
  className={cx(
255
- "font-medium",
270
+ fontStyleMap[size],
256
271
  isSelected && "text-primary"
257
272
  )}
258
273
  >
@@ -260,30 +275,21 @@ export const List = memoGeneric(
260
275
  </ViewComponent.RowTitle>
261
276
  )}
262
277
  </div>
263
- {end && (
264
- <div
265
- className={cx(
266
- "flex items-center gap-2",
267
- isSelected && "text-primary"
268
- )}
269
- tabIndex={-1}
270
- >
278
+ {end && detailPosition === "end" && (
279
+ <DetailContainer selected={isSelected}>
271
280
  {end}
272
- </div>
281
+ </DetailContainer>
273
282
  )}
274
283
  </div>
275
284
  {below && (
276
- <div
277
- className={cx(
278
- "flex items-center",
279
- isSelected && "text-primary"
280
- )}
281
- tabIndex={-1}
282
- >
285
+ <DetailContainer selected={isSelected}>
283
286
  {below}
284
- </div>
287
+ </DetailContainer>
285
288
  )}
286
289
  </div>
290
+ {end && detailPosition === "below" && (
291
+ <DetailContainer selected={isSelected}>{end}</DetailContainer>
292
+ )}
287
293
  </div>
288
294
  </ViewComponent.Row>
289
295
  );
@@ -292,3 +298,56 @@ export const List = memoGeneric(
292
298
  );
293
299
  })
294
300
  );
301
+
302
+ const DetailContainer = memo(function DetailContainer({
303
+ children,
304
+ selected,
305
+ }: {
306
+ children: React.ReactNode;
307
+ selected: boolean;
308
+ }) {
309
+ return (
310
+ <div
311
+ className={cx("flex items-center gap-2", selected && "text-primary")}
312
+ tabIndex={-1}
313
+ >
314
+ {children}
315
+ </div>
316
+ );
317
+ });
318
+
319
+ const pyMap: Record<GridViewSize, string> = {
320
+ xxs: "py-1",
321
+ xs: "py-1",
322
+ small: "py-1",
323
+ medium: "py-1",
324
+ large: "py-2",
325
+ xl: "py-3",
326
+ };
327
+
328
+ const thumbnailSizeMap: Record<GridViewSize, string> = {
329
+ xxs: "w-4 h-4",
330
+ xs: "w-4 h-4",
331
+ small: "w-6 h-6",
332
+ medium: "w-8 h-8",
333
+ large: "w-16 h-16",
334
+ xl: "w-24 h-24",
335
+ };
336
+
337
+ const rowGapMap: Record<GridViewSize, string> = {
338
+ xxs: "gap-3",
339
+ xs: "gap-3",
340
+ small: "gap-3",
341
+ medium: "gap-3",
342
+ large: "gap-3",
343
+ xl: "gap-4",
344
+ };
345
+
346
+ const fontStyleMap: Record<GridViewSize, string> = {
347
+ xxs: "font-medium",
348
+ xs: "font-medium",
349
+ small: "font-medium",
350
+ medium: "font-medium",
351
+ large: "font-medium",
352
+ xl: "font-medium text-heading4 text-text",
353
+ };
@@ -25,17 +25,18 @@ import { WindowScroller, WindowScrollerChildProps } from "react-virtualized";
25
25
  import { ListChildComponentProps, VariableSizeList } from "react-window";
26
26
  import { mergeEventHandlers } from "../hooks/mergeEventHandlers";
27
27
  import { useHover } from "../hooks/useHover";
28
- import { cssVars } from "../theme";
29
- import { cx } from "../utils/classNames";
28
+ import { cssVars, INPUT_HEIGHT } from "../theme";
29
+ import { cx, mergeConflictingClassNames } from "../utils/classNames";
30
30
  import { ContextMenu } from "./ContextMenu";
31
31
  import { InputField } from "./InputField";
32
32
  import { MenuItem } from "./internal/Menu";
33
33
  import { ScrollArea } from "./ScrollArea";
34
34
  import {
35
35
  DropValidator,
36
- normalizeListDestinationIndex,
36
+ normalizeListTargetIndex,
37
37
  RelativeDropPosition,
38
38
  Sortable,
39
+ type SortableItemContextProps,
39
40
  } from "./Sortable";
40
41
  import { Spacer } from "./Spacer";
41
42
 
@@ -43,7 +44,7 @@ export type ListRowMarginType = "none" | "top" | "bottom" | "vertical";
43
44
  export type ListRowPosition = "only" | "first" | "middle" | "last";
44
45
 
45
46
  const ROW_HEIGHT = 31;
46
- const SECTION_HEADER_LABEL_HEIGHT = 27;
47
+ const SECTION_HEADER_LABEL_HEIGHT = INPUT_HEIGHT;
47
48
 
48
49
  type ListColorScheme = "primary" | "secondary";
49
50
 
@@ -71,7 +72,7 @@ type ListRowContextValue = {
71
72
  // and the dragged row doesn't have a ListRowContextValue.
72
73
  type ListViewDraggingContextValue = {
73
74
  indentation: number;
74
- isDragging?: boolean;
75
+ isDragOverlay?: boolean;
75
76
  };
76
77
 
77
78
  const ListViewDraggingContext = createContext<ListViewDraggingContextValue>({
@@ -127,6 +128,7 @@ export interface EditableRowProps {
127
128
  autoFocus: boolean;
128
129
  placeholder?: string;
129
130
  className?: string;
131
+ onKeyDown?: (e: React.KeyboardEvent) => void;
130
132
  }
131
133
 
132
134
  function ListViewEditableRowTitle({
@@ -135,6 +137,7 @@ function ListViewEditableRowTitle({
135
137
  autoFocus,
136
138
  placeholder,
137
139
  className,
140
+ onKeyDown,
138
141
  }: EditableRowProps) {
139
142
  const inputRef = useRef<HTMLInputElement | null>(null);
140
143
 
@@ -161,6 +164,7 @@ function ListViewEditableRowTitle({
161
164
  onSubmit={onSubmitEditing}
162
165
  allowSubmittingWithSameValue
163
166
  className={cx("-mx-1.5 -my-1 bg-listview-editing-background", className)}
167
+ onKeyDown={onKeyDown}
164
168
  />
165
169
  );
166
170
  }
@@ -266,9 +270,10 @@ const RowContainer = forwardRef<
266
270
  borderBottomRightRadius: "0px",
267
271
  borderBottomLeftRadius: "0px",
268
272
  }),
269
- ...($hovered && {
270
- boxShadow: `0 0 0 1px ${cssVars.colors[$colorScheme]} inset`,
271
- }),
273
+ ...($hovered &&
274
+ !$selected && {
275
+ background: cssVars.colors.listViewHoverBackground,
276
+ }),
272
277
  ...($showsActiveState && {
273
278
  "&:active": {
274
279
  backgroundColor: $selected
@@ -301,7 +306,7 @@ const RowContainer = forwardRef<
301
306
  const ListViewDragIndicatorElement = forwardRef<
302
307
  HTMLDivElement,
303
308
  React.HTMLAttributes<HTMLDivElement> & {
304
- $relativeDropPosition: RelativeDropPosition;
309
+ $relativeDropPosition?: RelativeDropPosition;
305
310
  $gap: number;
306
311
  $offsetLeft: number;
307
312
  $colorScheme: ListColorScheme;
@@ -371,7 +376,7 @@ interface ListViewClickInfo {
371
376
  ctrlKey: boolean;
372
377
  }
373
378
 
374
- interface ListViewRowProps<MenuItemType extends string = string> {
379
+ export interface ListViewRowProps<MenuItemType extends string = string> {
375
380
  id?: string;
376
381
  tabIndex?: number;
377
382
  role?: string;
@@ -398,13 +403,16 @@ interface ListViewRowProps<MenuItemType extends string = string> {
398
403
  className?: string;
399
404
  dragIndicatorStyle?:
400
405
  | CSSProperties
401
- | ((props: {
402
- depth: number;
403
- indentation: number;
404
- position: RelativeDropPosition;
405
- }) => CSSProperties);
406
+ | ((props: DragIndicatorStyleProps) => CSSProperties);
407
+ testRelativeDropPosition?: RelativeDropPosition;
406
408
  }
407
409
 
410
+ export type DragIndicatorStyleProps = {
411
+ depth: number;
412
+ indentation: number;
413
+ position: RelativeDropPosition;
414
+ };
415
+
408
416
  const ListViewRow = forwardRefGeneric(function ListViewRow<
409
417
  MenuItemType extends string,
410
418
  >(
@@ -432,6 +440,7 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
432
440
  style,
433
441
  dragIndicatorStyle,
434
442
  className,
443
+ testRelativeDropPosition,
435
444
  }: ListViewRowProps<MenuItemType>,
436
445
  forwardedRef: ForwardedRef<HTMLElement>
437
446
  ) {
@@ -451,7 +460,7 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
451
460
  const { hoverProps } = useHover({
452
461
  onHoverChange,
453
462
  });
454
- const { indentation, isDragging } = useContext(ListViewDraggingContext);
463
+ const { indentation, isDragOverlay } = useContext(ListViewDraggingContext);
455
464
 
456
465
  const handlePress = useCallback(
457
466
  (event: React.MouseEvent) => {
@@ -478,7 +487,7 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
478
487
  );
479
488
 
480
489
  const mergedStyle = useMemo(() => {
481
- return isDragging
490
+ return isDragOverlay
482
491
  ? {
483
492
  // TODO: Where do these offsets actually come from?
484
493
  transform: `translate3d(-36px, -6px, 0)`,
@@ -486,11 +495,11 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
486
495
  ...style,
487
496
  }
488
497
  : style;
489
- }, [isDragging, style]);
498
+ }, [isDragOverlay, style]);
490
499
 
491
500
  const renderContent = (
492
501
  {
493
- relativeDropPosition,
502
+ relativeDropPosition: relativeDropPositionProp,
494
503
  ...renderProps
495
504
  }: React.ComponentProps<typeof RowContainer> & {
496
505
  relativeDropPosition?: RelativeDropPosition;
@@ -498,6 +507,8 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
498
507
  ref: Ref<HTMLElement>
499
508
  ) => {
500
509
  const Component = RowContainer;
510
+ const relativeDropPosition =
511
+ testRelativeDropPosition ?? relativeDropPositionProp;
501
512
 
502
513
  const element = (
503
514
  <Component
@@ -520,7 +531,7 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
520
531
  $selectedPosition={selectedPosition}
521
532
  $showsActiveState={pressEventName === "onClick"}
522
533
  aria-selected={selected}
523
- $divider={!isDragging && divider}
534
+ $divider={!isDragOverlay && divider}
524
535
  onKeyDown={onKeyDown}
525
536
  style={mergedStyle}
526
537
  {...(renderProps as Partial<React.ComponentProps<typeof RowContainer>>)}
@@ -534,9 +545,10 @@ const ListViewRow = forwardRefGeneric(function ListViewRow<
534
545
  >
535
546
  {relativeDropPosition && (
536
547
  <ListViewDragIndicatorElement
548
+ key={relativeDropPosition}
537
549
  $colorScheme={colorScheme}
538
550
  $relativeDropPosition={relativeDropPosition}
539
- $offsetLeft={33 + depth * indentation}
551
+ $offsetLeft={depth * indentation}
540
552
  $gap={listGap + (divider ? 1 : 0)}
541
553
  style={
542
554
  typeof dragIndicatorStyle === "function"
@@ -724,8 +736,9 @@ const VirtualizedList = memo(
724
736
  * Root
725
737
  * ------------------------------------------------------------------------- */
726
738
 
727
- type ListViewItemInfo = {
728
- isDragging: boolean;
739
+ export type ListViewItemInfo = {
740
+ isDragOverlay: boolean;
741
+ activeDragIndex?: number;
729
742
  };
730
743
 
731
744
  type ChildrenProps = {
@@ -762,7 +775,7 @@ export type ListViewRootProps = {
762
775
  expandable?: boolean;
763
776
  onMoveItem?: (
764
777
  sourceIndex: number,
765
- destinationIndex: number,
778
+ targetIndex: number,
766
779
  position: RelativeDropPosition
767
780
  ) => void;
768
781
  indentation?: number;
@@ -779,6 +792,7 @@ export type ListViewRootProps = {
779
792
  onDragLeave?: React.DragEventHandler<HTMLDivElement>;
780
793
  onDrop?: React.DragEventHandler<HTMLDivElement>;
781
794
  renderEmptyState?: () => ReactNode;
795
+ getDropTargetParentIndex?: SortableItemContextProps["getDropTargetParentIndex"];
782
796
  };
783
797
 
784
798
  const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
@@ -813,6 +827,7 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
813
827
  onDragLeave,
814
828
  onDrop,
815
829
  renderEmptyState,
830
+ getDropTargetParentIndex,
816
831
  }: RenderProps<T> & ListViewRootProps,
817
832
  forwardedRef: ForwardedRef<IVirtualizedList>
818
833
  ) {
@@ -834,7 +849,7 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
834
849
  );
835
850
 
836
851
  const renderChild = useCallback(
837
- (index: number) => renderItem(data[index], index, { isDragging: false }),
852
+ (index: number) => renderItem(data[index], index, { isDragOverlay: false }),
838
853
  [data, renderItem]
839
854
  );
840
855
 
@@ -949,7 +964,7 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
949
964
  );
950
965
 
951
966
  const draggingContextOverlayValue = useMemo(
952
- () => ({ indentation, isDragging: true }),
967
+ (): ListViewDraggingContextValue => ({ indentation, isDragOverlay: true }),
953
968
  [indentation]
954
969
  );
955
970
 
@@ -957,7 +972,7 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
957
972
  (index: number) => (
958
973
  <div style={{ opacity: 0.25 }}>
959
974
  <ListViewDraggingContext.Provider value={draggingContextOverlayValue}>
960
- {renderItem(data[index], index, { isDragging: true })}
975
+ {renderItem(data[index], index, { isDragOverlay: true })}
961
976
  </ListViewDraggingContext.Provider>
962
977
  </div>
963
978
  ),
@@ -989,6 +1004,7 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
989
1004
  keys={ids}
990
1005
  renderOverlay={renderOverlay}
991
1006
  acceptsDrop={acceptsDrop}
1007
+ getDropTargetParentIndex={getDropTargetParentIndex}
992
1008
  >
993
1009
  {children}
994
1010
  </Sortable.Root>
@@ -1028,9 +1044,14 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
1028
1044
  aria-labelledby={ariaLabelledby}
1029
1045
  aria-orientation={ariaOrientation}
1030
1046
  aria-multiselectable={ariaMultiselectable}
1031
- className={cx(
1032
- `flex flex-col text-text-muted ${scrollable ? "flex-1" : "flex-none"} `,
1033
- className
1047
+ className={mergeConflictingClassNames(
1048
+ [
1049
+ `flex flex-col text-text-muted ${scrollable ? "flex-1" : "flex-none"} `,
1050
+ className,
1051
+ ],
1052
+ {
1053
+ categories: ["flex"],
1054
+ }
1034
1055
  )}
1035
1056
  style={{ ...gapStyle, ...style }}
1036
1057
  {...{
@@ -1140,5 +1161,5 @@ export namespace ListView {
1140
1161
  menuItemsCount * rowHeight + sectionHeaderCount * sectionHeaderLabelHeight
1141
1162
  );
1142
1163
  };
1143
- export const normalizeDestinationIndex = normalizeListDestinationIndex;
1164
+ export const normalizeTargetIndex = normalizeListTargetIndex;
1144
1165
  }
@@ -4,7 +4,7 @@ import { cssVars } from "../theme";
4
4
  import { cx } from "../utils/classNames";
5
5
  import { IconName, Icons } from "./Icons";
6
6
 
7
- type ColorScheme = "primary" | "icon" | "warning";
7
+ type ColorScheme = "primary" | "secondary" | "icon" | "warning";
8
8
 
9
9
  type AssetType = "image" | "video" | "audio";
10
10
 
@@ -31,7 +31,10 @@ type MediaThumbnailProps = {
31
31
  iconName?: IconName;
32
32
  };
33
33
 
34
- const getColors = (colorScheme: ColorScheme, selected: boolean) => {
34
+ export const getThumbnailColors = (
35
+ colorScheme: ColorScheme,
36
+ selected: boolean
37
+ ) => {
35
38
  if (selected) {
36
39
  return {
37
40
  icon: cssVars.colors.primary,
@@ -43,18 +46,23 @@ const getColors = (colorScheme: ColorScheme, selected: boolean) => {
43
46
  case "primary":
44
47
  return {
45
48
  icon: cssVars.colors.primary,
46
- background: cssVars.colors.inputBackground,
49
+ background: cssVars.colors.listViewThumbnailBackground,
50
+ };
51
+ case "secondary":
52
+ return {
53
+ icon: cssVars.colors.secondary,
54
+ background: cssVars.colors.secondaryPastel,
47
55
  };
48
56
  case "warning":
49
57
  return {
50
58
  icon: cssVars.colors.warning,
51
- background: cssVars.colors.inputBackground,
59
+ background: cssVars.colors.listViewThumbnailBackground,
52
60
  };
53
61
  case "icon":
54
62
  default:
55
63
  return {
56
64
  icon: cssVars.colors.icon,
57
- background: cssVars.colors.inputBackground,
65
+ background: cssVars.colors.listViewThumbnailBackground,
58
66
  };
59
67
  }
60
68
  };
@@ -72,7 +80,7 @@ export const MediaThumbnail = memo(function MediaThumbnail({
72
80
  url,
73
81
  iconName = "FileIcon",
74
82
  }: MediaThumbnailProps) {
75
- const { icon: iconColor, background: backgroundColor } = getColors(
83
+ const { icon: iconColor, background: backgroundColor } = getThumbnailColors(
76
84
  colorScheme,
77
85
  selected
78
86
  );
@@ -1,11 +1,11 @@
1
+ import { MultiplayerUser } from "@noya-app/noya-multiplayer-react";
1
2
  import React, { forwardRef, memo, useMemo } from "react";
2
- import { Icons } from "./Icons";
3
- import { Avatar } from "./Avatar";
3
+ import { cssVars, INPUT_HEIGHT } from "../theme";
4
4
  import { cx } from "../utils/classNames";
5
- import { Text } from "./Text";
6
- import { MultiplayerUser } from "@noya-app/noya-multiplayer-react";
7
5
  import { colorFromString } from "../utils/colorFromString";
8
- import { cssVars } from "../theme";
6
+ import { Avatar } from "./Avatar";
7
+ import { Logo } from "./NoyaLogo";
8
+ import { Text } from "./Text";
9
9
 
10
10
  export type MessageProps = {
11
11
  role: "user" | "assistant" | "system" | "data";
@@ -17,7 +17,7 @@ export type MessageProps = {
17
17
 
18
18
  export const Message = memo(
19
19
  forwardRef(function Message(
20
- { role, children, user, avatarSize = 27 }: MessageProps,
20
+ { role, children, user, avatarSize = INPUT_HEIGHT }: MessageProps,
21
21
  ref: React.ForwardedRef<HTMLDivElement>
22
22
  ) {
23
23
  const randomId = crypto.randomUUID();
@@ -42,9 +42,9 @@ export const Message = memo(
42
42
  <Avatar
43
43
  name="Assistant"
44
44
  size={avatarSize}
45
- backgroundColor={cssVars.colors.inputBackground}
45
+ backgroundColor={cssVars.colors.primaryPastel}
46
46
  >
47
- <Icons.PersonIcon fontSize={22} color={cssVars.colors.text} />
47
+ <Logo style={{ width: 15 }} fill={cssVars.colors.primary} />
48
48
  </Avatar>
49
49
  ) : (
50
50
  <Avatar