@noya-app/noya-designsystem 0.1.48 → 0.1.49

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 (43) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +8 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +213 -164
  5. package/dist/index.d.ts +213 -164
  6. package/dist/index.js +3583 -3290
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +3617 -3329
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +3 -2
  11. package/src/__tests__/validateDropIndicator.test.ts +4 -4
  12. package/src/components/ActionMenu.tsx +15 -4
  13. package/src/components/BaseToolbar.tsx +2 -2
  14. package/src/components/Checkbox.tsx +2 -2
  15. package/src/components/Chip.tsx +7 -6
  16. package/src/components/Collection.tsx +19 -1
  17. package/src/components/Combobox.tsx +22 -23
  18. package/src/components/ComboboxMenu.tsx +1 -1
  19. package/src/components/DimensionInput.tsx +14 -12
  20. package/src/components/EditableText.tsx +3 -1
  21. package/src/components/FillInputField.tsx +2 -2
  22. package/src/components/Grid.tsx +133 -113
  23. package/src/components/GridView.tsx +36 -18
  24. package/src/components/InputField.tsx +116 -171
  25. package/src/components/Label.tsx +4 -68
  26. package/src/components/LabeledField.tsx +7 -1
  27. package/src/components/List.tsx +103 -44
  28. package/src/components/ListView.tsx +42 -26
  29. package/src/components/MediaThumbnail.tsx +3 -3
  30. package/src/components/Message.tsx +8 -8
  31. package/src/components/NoyaLogo.tsx +41 -0
  32. package/src/components/SegmentedControl.tsx +1 -1
  33. package/src/components/SelectMenu.tsx +9 -4
  34. package/src/components/Slider.tsx +16 -7
  35. package/src/components/Sortable.tsx +62 -25
  36. package/src/components/internal/Menu.tsx +8 -3
  37. package/src/components/internal/SelectItem.tsx +3 -2
  38. package/src/index.css +7 -1
  39. package/src/index.tsx +2 -0
  40. package/src/theme/index.ts +2 -0
  41. package/src/utils/classNames.ts +51 -3
  42. package/src/utils/inputs.ts +21 -0
  43. package/tailwind.config.ts +7 -0
@@ -1,72 +1,9 @@
1
- import React, {
2
- CSSProperties,
3
- LabelHTMLAttributes,
4
- forwardRef,
5
- memo,
6
- useMemo,
7
- } from "react";
1
+ import React, { LabelHTMLAttributes, forwardRef, memo } from "react";
8
2
  import { cx } from "../utils/classNames";
9
- import { InputFieldSize } from "./InputField";
10
3
 
11
4
  export type LabelPosition = "inset" | "start" | "end" | "above";
12
5
 
13
- export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
14
- /** @default start */
15
- position?: Exclude<LabelPosition, "inset">;
16
- }
17
-
18
- export type InsetLabelProps = {
19
- /** @default medium */
20
- size?: InputFieldSize;
21
- /** when used with an InputField.Root and label position is inset, it will add padding to the right of the label to account for the button */
22
- buttonWidth?: number;
23
- } & LabelHTMLAttributes<HTMLLabelElement>;
24
-
25
- // apply to <label
26
- export const insetLabelTextStyles = `font-sans text-label uppercase text-text-disabled leading-[19px] font-bold text-[60%] truncate pointer-events-none text-right`;
27
-
28
- // InsetLabelContainer
29
- export const insetLabelStyles = `flex items-center absolute top-0 bottom-0 z-label`;
30
- const getInsetLabelPosition = ({
31
- buttonWidth,
32
- }: {
33
- buttonWidth?: number;
34
- }): CSSProperties => ({
35
- right: `${6 + (buttonWidth ?? 0)}px`,
36
- });
37
-
38
- export const InsetLabel = memo(
39
- forwardRef<HTMLLabelElement, InsetLabelProps>(function InsetLabel(
40
- { children, buttonWidth, size = "medium", className, style, ...props },
41
- ref
42
- ) {
43
- const styles = useMemo(
44
- () => ({
45
- ...getInsetLabelPosition({
46
- buttonWidth,
47
- }),
48
- ...style,
49
- }),
50
- [buttonWidth, style]
51
- );
52
-
53
- return (
54
- <label
55
- ref={ref}
56
- style={styles}
57
- className={cx(
58
- insetLabelStyles,
59
- insetLabelTextStyles,
60
- size === "small" ? "min-h-[19px]" : "min-h-[27px]",
61
- className
62
- )}
63
- {...props}
64
- >
65
- {children}
66
- </label>
67
- );
68
- })
69
- );
6
+ export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {}
70
7
 
71
8
  const labelStyles = "flex items-center select-none z-label relative";
72
9
  const labelTextStyles =
@@ -74,7 +11,7 @@ const labelTextStyles =
74
11
 
75
12
  export const Label = memo(
76
13
  forwardRef<HTMLLabelElement, LabelProps>(function Label(
77
- { className, position = "start", children, ...props },
14
+ { className, children, ...props },
78
15
  ref
79
16
  ) {
80
17
  return (
@@ -83,8 +20,7 @@ export const Label = memo(
83
20
  className={cx(
84
21
  labelStyles,
85
22
  labelTextStyles,
86
- "text-left min-h-[27px]",
87
- (position === "start" || position === "end") && "self-start",
23
+ "text-left min-h-input-height",
88
24
  className
89
25
  )}
90
26
  {...props}
@@ -91,7 +91,13 @@ export const LabeledField = memo(function LabeledField({
91
91
  <div className={labeledFieldClasses}>
92
92
  <Label
93
93
  htmlFor={fieldId}
94
- position={labelPosition}
94
+ // we do this so presence avatars are aligned to the right when position is above
95
+ // and when start/end position with textarea it aligns label to the top of the field
96
+ className={
97
+ labelPosition === "start" || labelPosition === "end"
98
+ ? "self-start"
99
+ : undefined
100
+ }
95
101
  style={labelStyle}
96
102
  {...props}
97
103
  >
@@ -3,14 +3,16 @@ 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
17
  "--icon-selected": cssVars.colors.primary,
16
18
  };
@@ -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,10 @@ export const List = memoGeneric(
52
56
  renamable,
53
57
  selectedIds = emptyArray,
54
58
  renderEmptyState,
59
+ sortable,
60
+ getDropTargetParentIndex,
61
+ getPlaceholder,
62
+ onClickItem,
55
63
  } = props;
56
64
 
57
65
  const [internalHoveredId, setHoveredId] = useState<string>();
@@ -116,19 +124,21 @@ export const List = memoGeneric(
116
124
  aria-orientation="vertical"
117
125
  aria-multiselectable={true}
118
126
  expandable={expandable}
119
- sortable={expandable}
127
+ sortable={sortable}
120
128
  acceptsDrop={acceptsDrop}
121
129
  onMoveItem={onMoveItem}
122
130
  renderEmptyState={renderEmptyState}
131
+ getDropTargetParentIndex={getDropTargetParentIndex}
123
132
  {...dropTargetProps}
124
133
  renderItem={(
125
134
  item: T,
126
135
  _: number,
127
- { isDragging }: { isDragging: boolean }
136
+ { isDragOverlay }: ListViewItemInfo
128
137
  ) => {
129
138
  const id = getId(item);
130
139
  const isDropdownOpen = dropdownOpenId === id;
131
- const isHovered = (hoveredId === id || isDropdownOpen) && !isDragging;
140
+ const isHovered =
141
+ (hoveredId === id || isDropdownOpen) && !isDragOverlay;
132
142
  const expanded = getExpanded?.(item);
133
143
  const itemIsRenamable = getRenamable?.(item) ?? renamable;
134
144
  const isSelected = selectedIds.includes(id);
@@ -139,24 +149,25 @@ export const List = memoGeneric(
139
149
  item,
140
150
  selected: isSelected,
141
151
  });
152
+ const onOpenChange = (open: boolean) => {
153
+ setDropdownOpenId(open ? id : undefined);
154
+
155
+ if (open && !isSelected) {
156
+ handleSelect(id);
157
+ }
158
+ };
142
159
  const action =
143
160
  (isHovered || isSelected) &&
144
161
  !isRenaming &&
145
162
  (typeof renderAction === "function"
146
- ? renderAction(item, isSelected)
163
+ ? renderAction({ item, selected: isSelected, onOpenChange })
147
164
  : renderAction === "menu" &&
148
165
  menuItems && (
149
166
  <ActionMenu
150
167
  menuItems={menuItems}
151
168
  onSelect={(action) => handleMenuAction(action, item)}
152
169
  selected={isSelected}
153
- onOpenChange={(open) => {
154
- setDropdownOpenId(open ? id : undefined);
155
-
156
- if (open && !isSelected) {
157
- handleSelect(id);
158
- }
159
- }}
170
+ onOpenChange={onOpenChange}
160
171
  />
161
172
  ));
162
173
 
@@ -171,14 +182,17 @@ export const List = memoGeneric(
171
182
  id={id}
172
183
  key={id}
173
184
  role="option"
174
- sortable={expandable}
185
+ sortable={sortable}
175
186
  aria-roledescription={itemRoleDescription}
176
187
  aria-label={getName(item)}
177
188
  aria-selected={isSelected}
178
- className={cx("cursor-pointer p-1 rounded")}
189
+ className={cx("cursor-pointer rounded px-1", pyMap[size])}
179
190
  backgroundColor={
180
191
  isSelected ? cssVars.colors.primaryPastel : undefined
181
192
  }
193
+ testRelativeDropPosition={
194
+ testShowDropIndicatorId === id ? "inside" : undefined
195
+ }
182
196
  chevronClassName={cx(expandable && "relative left-2")}
183
197
  style={cssVarOverrides as React.CSSProperties}
184
198
  hovered={isHovered}
@@ -190,6 +204,7 @@ export const List = memoGeneric(
190
204
  }
191
205
  onPress={(e: ListView.ClickInfo) => {
192
206
  handleSelect(id, e);
207
+ onClickItem?.(id);
193
208
  }}
194
209
  onDoubleClick={() => {
195
210
  onDoubleClickItem?.(id);
@@ -215,44 +230,44 @@ export const List = memoGeneric(
215
230
  setExpanded?.(item, !expanded);
216
231
  }}
217
232
  >
218
- <div className="flex flex-1 items-center px-2 gap-3">
233
+ <div
234
+ className={cx("flex flex-1 items-center px-2", rowGapMap[size])}
235
+ >
219
236
  {thumbnail && (
220
237
  <div
221
238
  className={cx(
222
239
  "rounded overflow-hidden flex-none flex items-center justify-center",
223
- size === "medium" ? "w-8 h-8" : "w-16 h-16",
240
+ thumbnailSize === "auto" && thumbnailSizeMap[size],
224
241
  isSelected && "text-primary"
225
242
  )}
226
- style={{
227
- backgroundColor: isSelected
228
- ? cssVars.colors.primaryPastel
229
- : cssVars.colors.inputBackground,
230
- }}
231
243
  tabIndex={-1}
232
244
  >
233
245
  {thumbnail}
234
246
  </div>
235
247
  )}
236
248
  <div className="flex flex-col flex-1 w-0">
237
- <div className="flex items-center min-h-[27px] flex-1 gap-2">
249
+ <div className="flex items-center min-h-input-height flex-1 gap-2">
238
250
  <div className="flex-1 w-0 flex items-center" tabIndex={-1}>
239
251
  {isRenaming ? (
240
252
  <ViewComponent.EditableRowTitle
241
253
  value={getName(item)}
242
- placeholder="Enter name"
243
- className="font-medium"
254
+ placeholder={getPlaceholder?.(item) ?? "Enter name"}
255
+ className={fontStyleMap[size]}
244
256
  autoFocus={!isTestingRenaming}
245
257
  onSubmitEditing={(value: string) => {
246
- if (value !== getName(item)) {
258
+ if (value !== getName(item) && value !== "") {
247
259
  onRename?.(item, value);
248
260
  }
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,7 +25,7 @@ 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";
28
+ import { cssVars, INPUT_HEIGHT } from "../theme";
29
29
  import { cx } from "../utils/classNames";
30
30
  import { ContextMenu } from "./ContextMenu";
31
31
  import { InputField } from "./InputField";
@@ -33,9 +33,10 @@ 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;
@@ -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>
@@ -1140,5 +1156,5 @@ export namespace ListView {
1140
1156
  menuItemsCount * rowHeight + sectionHeaderCount * sectionHeaderLabelHeight
1141
1157
  );
1142
1158
  };
1143
- export const normalizeDestinationIndex = normalizeListDestinationIndex;
1159
+ export const normalizeTargetIndex = normalizeListTargetIndex;
1144
1160
  }
@@ -43,18 +43,18 @@ const getColors = (colorScheme: ColorScheme, selected: boolean) => {
43
43
  case "primary":
44
44
  return {
45
45
  icon: cssVars.colors.primary,
46
- background: cssVars.colors.inputBackground,
46
+ background: cssVars.colors.listViewThumbnailBackground,
47
47
  };
48
48
  case "warning":
49
49
  return {
50
50
  icon: cssVars.colors.warning,
51
- background: cssVars.colors.inputBackground,
51
+ background: cssVars.colors.listViewThumbnailBackground,
52
52
  };
53
53
  case "icon":
54
54
  default:
55
55
  return {
56
56
  icon: cssVars.colors.icon,
57
- background: cssVars.colors.inputBackground,
57
+ background: cssVars.colors.listViewThumbnailBackground,
58
58
  };
59
59
  }
60
60
  };