@lotics/ui 2.6.1 → 3.0.0

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 (45) hide show
  1. package/package.json +1 -15
  2. package/src/react_native.d.ts +2 -2
  3. package/src/cell_date.tsx +0 -30
  4. package/src/cell_date_format.test.ts +0 -32
  5. package/src/cell_date_format.ts +0 -73
  6. package/src/cell_number.test.ts +0 -42
  7. package/src/cell_number.tsx +0 -25
  8. package/src/cell_number_format.ts +0 -42
  9. package/src/cell_select.tsx +0 -68
  10. package/src/cell_text.tsx +0 -45
  11. package/src/grid/data_grid.tsx +0 -2003
  12. package/src/grid/data_grid_columns.test.ts +0 -72
  13. package/src/grid/data_grid_columns.ts +0 -30
  14. package/src/grid/data_grid_context.ts +0 -119
  15. package/src/grid/dispatch_safely.ts +0 -39
  16. package/src/grid/engine.module.css +0 -114
  17. package/src/grid/engine.tsx +0 -1042
  18. package/src/grid/helpers.ts +0 -205
  19. package/src/grid/layout.test.ts +0 -515
  20. package/src/grid/layout.ts +0 -425
  21. package/src/grid/recycling.test.ts +0 -236
  22. package/src/grid/recycling.ts +0 -172
  23. package/src/grid/row_cell.module.css +0 -105
  24. package/src/grid/row_cell.tsx +0 -313
  25. package/src/grid/search_highlight.ts +0 -71
  26. package/src/grid/select_cell.tsx +0 -58
  27. package/src/grid/select_group_summary_cell.tsx +0 -76
  28. package/src/grid/select_header_cell.tsx +0 -32
  29. package/src/grid/skeleton_row.module.css +0 -34
  30. package/src/grid/skeleton_row.tsx +0 -20
  31. package/src/grid/use_grid_groups.ts +0 -311
  32. package/src/grid/use_scroll_to_cell.ts +0 -135
  33. package/src/grid/use_virtual_grid.ts +0 -383
  34. package/src/grid/visibility.test.ts +0 -208
  35. package/src/grid/visibility.ts +0 -77
  36. package/src/kanban/constants.ts +0 -18
  37. package/src/kanban/default_renderers.tsx +0 -160
  38. package/src/kanban/drag_preview.tsx +0 -157
  39. package/src/kanban/index.ts +0 -13
  40. package/src/kanban/insert_card_zone.tsx +0 -135
  41. package/src/kanban/kanban_board.tsx +0 -635
  42. package/src/kanban/kanban_card.tsx +0 -321
  43. package/src/kanban/kanban_column.tsx +0 -499
  44. package/src/kanban/placeholders.tsx +0 -54
  45. package/src/kanban/types.ts +0 -116
@@ -1,499 +0,0 @@
1
- import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import {
3
- FlatList,
4
- GestureResponderEvent,
5
- LayoutChangeEvent,
6
- ListRenderItem,
7
- NativeScrollEvent,
8
- NativeSyntheticEvent,
9
- Pressable,
10
- StyleSheet,
11
- View,
12
- } from "react-native";
13
- import { colors } from "../colors";
14
- import {
15
- KanbanItem,
16
- KanbanRenderAddCardPlaceholderProps,
17
- KanbanRenderInsertCardButtonProps,
18
- KanbanRenderCardProps,
19
- KanbanRenderCollapsedColumnProps,
20
- KanbanRenderColumnHeaderProps,
21
- } from "./types";
22
- import { KanbanCard } from "./kanban_card";
23
- import { CardPlaceholder, ColumnPlaceholder } from "./placeholders";
24
- import { COLUMN_CONTENT_PADDING, DRAG_THRESHOLD } from "./constants";
25
- import type { ColumnRegistration } from "./kanban_board";
26
-
27
- // Memoized separator component to prevent re-renders
28
- const ItemSeparator = memo(function ItemSeparator({ height }: { height: number }) {
29
- const style = useMemo(() => ({ height }), [height]);
30
- return <View style={style} />;
31
- });
32
-
33
- // Memoized footer placeholder component
34
- const FooterPlaceholder = memo(function FooterPlaceholder({ height }: { height: number }) {
35
- return <CardPlaceholder height={height} />;
36
- });
37
-
38
- // Stable key extractor (defined outside component to avoid recreation)
39
- const keyExtractor = <T,>(item: KanbanItem<T>) => item.id;
40
-
41
- interface KanbanColumnProps<T> {
42
- columnKey: string;
43
- title: string;
44
- index: number;
45
- items: KanbanItem<T>[];
46
- renderCard: (props: KanbanRenderCardProps<T>) => React.ReactNode;
47
- renderColumnHeader: (props: KanbanRenderColumnHeaderProps) => React.ReactNode;
48
- renderAddCardPlaceholder: (props: KanbanRenderAddCardPlaceholderProps) => React.ReactNode;
49
- renderInsertCardButton?: (props: KanbanRenderInsertCardButtonProps) => React.ReactNode;
50
- renderCollapsedColumn: (props: KanbanRenderCollapsedColumnProps) => React.ReactNode;
51
- isDragging: boolean;
52
- isDropTarget: boolean;
53
- /** True when any card is being dragged (disables insert zones) */
54
- isDragInProgress: boolean;
55
- cardDragId: string | null;
56
- cardDropTargetIndex: number | null;
57
- /** Height of the card being dragged (for placeholder sizing) */
58
- draggedCardHeight: number | null;
59
- /** Show full-column highlight when a card is being dropped (column-only mode) */
60
- showCardDropHighlight: boolean;
61
- columnWidth: number;
62
- /** Width to use for drop target placeholder (matches dragged column's width) */
63
- placeholderWidth: number;
64
- /** Height to use for drop target placeholder (matches dragged column's height) */
65
- placeholderHeight?: number;
66
- itemHeight: number | ((item: T, index: number) => number);
67
- itemGap: number;
68
- onCardPress?: (cardId: string, item: T, columnKey: string) => void;
69
- onAddCard?: (columnKey: string) => void;
70
- onAddCardAtIndex?: (columnKey: string, index: number) => void;
71
- /** Whether cards in this column can be dragged */
72
- cardDraggable: boolean;
73
- /** Whether this column can be reordered by dragging its header */
74
- columnDraggable: boolean;
75
- startCardDrag: (
76
- cardId: string,
77
- columnKey: string,
78
- index: number,
79
- startX: number,
80
- startY: number,
81
- rect: { x: number; y: number; width: number; height: number },
82
- ) => void;
83
- startColumnDrag: (
84
- columnKey: string,
85
- index: number,
86
- startX: number,
87
- startY: number,
88
- rect: { x: number; y: number; width: number; height: number },
89
- ) => void;
90
- registerColumn: (columnKey: string, data: ColumnRegistration | null) => void;
91
- updateColumnScroll: (columnKey: string, scrollY: number) => void;
92
- onPointerEnter: (columnKey: string) => void;
93
- isMinimized: boolean;
94
- onMinimizeToggle: (columnKey: string) => void;
95
- }
96
-
97
- function KanbanColumnInner<T>({
98
- columnKey,
99
- title,
100
- index,
101
- items,
102
- renderCard,
103
- renderColumnHeader,
104
- renderAddCardPlaceholder,
105
- renderInsertCardButton,
106
- renderCollapsedColumn,
107
- isDragging,
108
- isDropTarget,
109
- isDragInProgress,
110
- cardDragId,
111
- cardDropTargetIndex,
112
- draggedCardHeight,
113
- showCardDropHighlight,
114
- columnWidth,
115
- placeholderWidth,
116
- placeholderHeight,
117
- itemHeight,
118
- itemGap,
119
- onCardPress,
120
- onAddCard,
121
- onAddCardAtIndex,
122
- cardDraggable,
123
- columnDraggable,
124
- startCardDrag,
125
- startColumnDrag,
126
- registerColumn,
127
- updateColumnScroll,
128
- onPointerEnter,
129
- isMinimized,
130
- onMinimizeToggle,
131
- }: KanbanColumnProps<T>) {
132
- const containerRef = useRef<View>(null);
133
- const listRef = useRef<FlatList>(null);
134
- const headerHeightRef = useRef(0);
135
-
136
- const cardDragIdRef = useRef(cardDragId);
137
- const cardDropTargetIndexRef = useRef(cardDropTargetIndex);
138
- const itemsLengthRef = useRef(items.length);
139
- const draggedCardHeightRef = useRef(draggedCardHeight);
140
-
141
- cardDragIdRef.current = cardDragId;
142
- cardDropTargetIndexRef.current = cardDropTargetIndex;
143
- itemsLengthRef.current = items.length;
144
- draggedCardHeightRef.current = draggedCardHeight;
145
-
146
- // Column drag threshold state (similar to card dragging)
147
- const [isHeaderPressing, setIsHeaderPressing] = useState(false);
148
- const headerPressStartRef = useRef<{ x: number; y: number } | null>(null);
149
- const hasColumnDraggedRef = useRef(false);
150
- const columnRectRef = useRef<{
151
- x: number;
152
- y: number;
153
- width: number;
154
- height: number;
155
- } | null>(null);
156
-
157
- const getHeight = useCallback(
158
- (item: T, idx: number): number => {
159
- return typeof itemHeight === "function" ? itemHeight(item, idx) : itemHeight;
160
- },
161
- [itemHeight],
162
- );
163
-
164
- useEffect(() => {
165
- const element = containerRef.current as unknown as HTMLElement | null;
166
- if (element && (listRef.current || isMinimized)) {
167
- registerColumn(columnKey, {
168
- element,
169
- headerHeight: isMinimized ? 0 : headerHeightRef.current,
170
- listRef: listRef.current, // null when minimized, FlatList when expanded
171
- });
172
- }
173
- return () => registerColumn(columnKey, null);
174
- }, [columnKey, registerColumn, isMinimized]);
175
-
176
- const handleHeaderLayout = useCallback(
177
- (event: LayoutChangeEvent) => {
178
- headerHeightRef.current = event.nativeEvent.layout.height;
179
- const element = containerRef.current as unknown as HTMLElement | null;
180
- if (element && listRef.current) {
181
- registerColumn(columnKey, {
182
- element,
183
- headerHeight: headerHeightRef.current,
184
- listRef: listRef.current,
185
- });
186
- }
187
- },
188
- [columnKey, registerColumn],
189
- );
190
-
191
- // Handle column drag with threshold (same as cards)
192
- useEffect(() => {
193
- if (!isHeaderPressing) return;
194
-
195
- const handleMouseMove = (e: MouseEvent) => {
196
- if (!headerPressStartRef.current || hasColumnDraggedRef.current) return;
197
-
198
- const dx = Math.abs(e.clientX - headerPressStartRef.current.x);
199
- const dy = Math.abs(e.clientY - headerPressStartRef.current.y);
200
-
201
- if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) {
202
- hasColumnDraggedRef.current = true;
203
- if (columnRectRef.current) {
204
- startColumnDrag(columnKey, index, e.clientX, e.clientY, columnRectRef.current);
205
- }
206
- }
207
- };
208
-
209
- const handleMouseUp = () => {
210
- setIsHeaderPressing(false);
211
- headerPressStartRef.current = null;
212
- columnRectRef.current = null;
213
- };
214
-
215
- window.addEventListener("mousemove", handleMouseMove);
216
- window.addEventListener("mouseup", handleMouseUp);
217
-
218
- return () => {
219
- window.removeEventListener("mousemove", handleMouseMove);
220
- window.removeEventListener("mouseup", handleMouseUp);
221
- };
222
- }, [isHeaderPressing, columnKey, index, startColumnDrag]);
223
-
224
- const handleHeaderPressIn = useCallback(
225
- (event: GestureResponderEvent) => {
226
- if (!columnDraggable) return;
227
- // Use clientX/clientY (viewport-relative) for consistency with mousemove events
228
- const clientX = event.nativeEvent.pageX - window.scrollX;
229
- const clientY = event.nativeEvent.pageY - window.scrollY;
230
- headerPressStartRef.current = { x: clientX, y: clientY };
231
- hasColumnDraggedRef.current = false;
232
-
233
- const element = containerRef.current as unknown as HTMLElement | null;
234
- if (element) {
235
- const rect = element.getBoundingClientRect();
236
- columnRectRef.current = rect;
237
- setIsHeaderPressing(true);
238
- }
239
- },
240
- [columnDraggable],
241
- );
242
-
243
- const handleScroll = useCallback(
244
- (event: NativeSyntheticEvent<NativeScrollEvent>) => {
245
- updateColumnScroll(columnKey, event.nativeEvent.contentOffset.y);
246
- },
247
- [columnKey, updateColumnScroll],
248
- );
249
-
250
- const handlePointerEnter = useCallback(() => {
251
- onPointerEnter(columnKey);
252
- }, [columnKey, onPointerEnter]);
253
-
254
- const handleMinimizeToggle = useCallback(() => {
255
- onMinimizeToggle(columnKey);
256
- }, [columnKey, onMinimizeToggle]);
257
-
258
- const handleMinimizedPress = useCallback(() => {
259
- onMinimizeToggle(columnKey);
260
- }, [columnKey, onMinimizeToggle]);
261
-
262
- const flatListGetItemLayout = useCallback(
263
- (_: ArrayLike<KanbanItem<T>> | null | undefined, itemIndex: number) => {
264
- if (typeof itemHeight === "number") {
265
- return {
266
- length: itemHeight,
267
- offset: itemIndex * (itemHeight + itemGap),
268
- index: itemIndex,
269
- };
270
- }
271
- let offset = 0;
272
- for (let i = 0; i < itemIndex; i++) {
273
- offset += getHeight(items[i].data, i) + itemGap;
274
- }
275
- return {
276
- length: getHeight(items[itemIndex]?.data, itemIndex),
277
- offset,
278
- index: itemIndex,
279
- };
280
- },
281
- [items, itemHeight, itemGap, getHeight],
282
- );
283
-
284
- // O(1) lookup map for item id -> index
285
- const itemIndexMap = useMemo(() => {
286
- const map = new Map<string, number>();
287
- items.forEach((item, idx) => map.set(item.id, idx));
288
- return map;
289
- }, [items]);
290
-
291
- // Separator that hides when after dragged card that renders null
292
- // When onAddCardAtIndex is provided, cards render their own gaps with insert zones
293
- const renderSeparator = useCallback(
294
- (props: { leadingItem: KanbanItem<T> | null }) => {
295
- // When insert zones are enabled, cards render their own gaps
296
- if (onAddCardAtIndex) {
297
- return null;
298
- }
299
-
300
- if (!props.leadingItem) {
301
- return <ItemSeparator height={itemGap} />;
302
- }
303
-
304
- const isLeadingDragging = cardDragIdRef.current === props.leadingItem.id;
305
- const leadingIndex = itemIndexMap.get(props.leadingItem.id) ?? -1;
306
-
307
- if (isLeadingDragging) {
308
- // Dragged card renders null unless it's also the drop target
309
- const isLeadingDropTarget = cardDropTargetIndexRef.current === leadingIndex;
310
-
311
- // Skip separator after dragged card that renders null
312
- if (!isLeadingDropTarget) {
313
- return null;
314
- }
315
- }
316
-
317
- return <ItemSeparator height={itemGap} />;
318
- },
319
- [itemGap, itemIndexMap, onAddCardAtIndex],
320
- );
321
-
322
- const renderItem: ListRenderItem<KanbanItem<T>> = useCallback(
323
- ({ item, index: itemIndex }) => {
324
- const isCardDragging = cardDragIdRef.current === item.id;
325
- const isCardDropTarget = cardDropTargetIndexRef.current === itemIndex;
326
- const height = getHeight(item.data, itemIndex);
327
-
328
- return (
329
- <KanbanCard
330
- id={item.id}
331
- columnKey={columnKey}
332
- index={itemIndex}
333
- item={item.data}
334
- renderCard={renderCard}
335
- isDragging={isCardDragging}
336
- isDropTarget={isCardDropTarget}
337
- isDragInProgress={isDragInProgress}
338
- cardDraggable={cardDraggable}
339
- onCardPress={onCardPress}
340
- onAddCardAtIndex={onAddCardAtIndex}
341
- renderInsertCardButton={renderInsertCardButton}
342
- startCardDrag={startCardDrag}
343
- placeholderHeight={height}
344
- // Only pass draggedCardHeight to drop target - prevents all cards from re-rendering
345
- draggedCardHeight={isCardDropTarget ? draggedCardHeightRef.current : null}
346
- itemGap={itemGap}
347
- />
348
- );
349
- },
350
- [
351
- columnKey,
352
- renderCard,
353
- onCardPress,
354
- onAddCardAtIndex,
355
- renderInsertCardButton,
356
- cardDraggable,
357
- startCardDrag,
358
- getHeight,
359
- itemGap,
360
- isDragInProgress,
361
- ],
362
- );
363
-
364
- const handleAddCard = useCallback(() => {
365
- onAddCard?.(columnKey);
366
- }, [onAddCard, columnKey]);
367
-
368
- // Stable footer renderer using memoized component
369
- const renderFooter = useCallback(() => {
370
- if (cardDropTargetIndexRef.current === null) return null;
371
- if (cardDropTargetIndexRef.current !== itemsLengthRef.current) return null;
372
-
373
- const height = draggedCardHeightRef.current ?? 60;
374
- return <FooterPlaceholder height={height} />;
375
- }, []);
376
-
377
- // Tells FlatList when to re-render items (refs don't trigger re-renders)
378
- const listExtraData = useMemo(
379
- () => [cardDragId, cardDropTargetIndex, draggedCardHeight],
380
- [cardDragId, cardDropTargetIndex, draggedCardHeight],
381
- );
382
-
383
- // Stable container styles
384
- const containerStyle = useMemo(() => [styles.container, { width: columnWidth }], [columnWidth]);
385
-
386
- // List content style - remove top padding when insert zones are enabled
387
- // since first card renders its own gap
388
- const listContentStyle = useMemo(
389
- () => (onAddCardAtIndex ? [styles.listContent, { paddingTop: 0 }] : styles.listContent),
390
- [onAddCardAtIndex],
391
- );
392
- const minimizedContainerStyle = useMemo(
393
- () => ({ width: columnWidth, height: "100%" as const }),
394
- [columnWidth],
395
- );
396
-
397
- if (isDragging) {
398
- return isDropTarget ? (
399
- <ColumnPlaceholder width={placeholderWidth} height={placeholderHeight} />
400
- ) : null;
401
- }
402
-
403
- if (isMinimized) {
404
- const showDropIndicator = showCardDropHighlight || cardDropTargetIndex !== null;
405
-
406
- return (
407
- <>
408
- {isDropTarget && <ColumnPlaceholder width={placeholderWidth} height={placeholderHeight} />}
409
- <View
410
- ref={containerRef}
411
- style={minimizedContainerStyle}
412
- onPointerEnter={handlePointerEnter}
413
- >
414
- {renderCollapsedColumn({
415
- columnKey,
416
- title,
417
- itemCount: items.length,
418
- showDropIndicator,
419
- onExpand: handleMinimizedPress,
420
- })}
421
- </View>
422
- </>
423
- );
424
- }
425
-
426
- return (
427
- <>
428
- {isDropTarget && <ColumnPlaceholder width={placeholderWidth} height={placeholderHeight} />}
429
- <View ref={containerRef} style={containerStyle} onPointerEnter={handlePointerEnter}>
430
- <Pressable onLayout={handleHeaderLayout} onPressIn={handleHeaderPressIn}>
431
- {renderColumnHeader({
432
- columnKey,
433
- title,
434
- itemCount: items.length,
435
- isMinimized,
436
- onMinimizeToggle: handleMinimizeToggle,
437
- })}
438
- </Pressable>
439
- <FlatList
440
- ref={listRef}
441
- data={items}
442
- extraData={listExtraData}
443
- keyExtractor={keyExtractor}
444
- renderItem={renderItem}
445
- contentContainerStyle={listContentStyle}
446
- ItemSeparatorComponent={renderSeparator}
447
- ListFooterComponent={renderFooter}
448
- showsVerticalScrollIndicator={true}
449
- onScroll={handleScroll}
450
- scrollEventThrottle={16}
451
- getItemLayout={flatListGetItemLayout}
452
- // Performance optimizations
453
- removeClippedSubviews={false} // Keep false for smooth drag animations
454
- maxToRenderPerBatch={10}
455
- updateCellsBatchingPeriod={50}
456
- windowSize={5} // Render 5 screens worth (enough for most columns)
457
- initialNumToRender={15}
458
- />
459
- {onAddCard && (
460
- <View style={styles.addCardFooter}>
461
- {renderAddCardPlaceholder({
462
- columnKey,
463
- onPress: handleAddCard,
464
- })}
465
- </View>
466
- )}
467
- {showCardDropHighlight && <View style={styles.cardDropHighlight} />}
468
- </View>
469
- </>
470
- );
471
- }
472
-
473
- export const KanbanColumn = memo(KanbanColumnInner) as typeof KanbanColumnInner;
474
-
475
- const styles = StyleSheet.create({
476
- container: {
477
- backgroundColor: colors.zinc[50],
478
- borderRadius: 16,
479
- maxHeight: "100%",
480
- },
481
- listContent: {
482
- padding: COLUMN_CONTENT_PADDING,
483
- },
484
- addCardFooter: {
485
- padding: COLUMN_CONTENT_PADDING,
486
- paddingTop: 0,
487
- },
488
- cardDropHighlight: {
489
- position: "absolute",
490
- top: 0,
491
- left: 0,
492
- right: 0,
493
- bottom: 0,
494
- backgroundColor: colors.blue[100],
495
- opacity: 0.5,
496
- borderRadius: 8,
497
- pointerEvents: "none",
498
- },
499
- });
@@ -1,54 +0,0 @@
1
- import React, { memo } from "react";
2
- import { StyleSheet, View } from "react-native";
3
- import { colors } from "../colors";
4
-
5
- interface CardPlaceholderProps {
6
- height: number;
7
- }
8
-
9
- /**
10
- * Placeholder shown when dragging a card to a new position
11
- */
12
- export const CardPlaceholder = memo(function CardPlaceholder({ height }: CardPlaceholderProps) {
13
- return <View style={[styles.cardPlaceholder, { height }]} />;
14
- });
15
-
16
- interface ColumnPlaceholderProps {
17
- width: number;
18
- height?: number;
19
- }
20
-
21
- /**
22
- * Placeholder shown when dragging a column to a new position
23
- */
24
- export const ColumnPlaceholder = memo(function ColumnPlaceholder({
25
- width,
26
- height,
27
- }: ColumnPlaceholderProps) {
28
- return (
29
- <View style={[styles.columnPlaceholder, { width, height }]}>
30
- <View style={styles.columnPlaceholderContent} />
31
- </View>
32
- );
33
- });
34
-
35
- const styles = StyleSheet.create({
36
- cardPlaceholder: {
37
- backgroundColor: colors.blue[50],
38
- borderRadius: 8,
39
- borderWidth: 2,
40
- borderColor: colors.blue[300],
41
- boxSizing: "border-box",
42
- },
43
- columnPlaceholder: {
44
- minHeight: 200,
45
- backgroundColor: colors.blue[50],
46
- borderRadius: 8,
47
- borderWidth: 2,
48
- borderColor: colors.blue[300],
49
- },
50
- columnPlaceholderContent: {
51
- flex: 1,
52
- minHeight: 100,
53
- },
54
- });
@@ -1,116 +0,0 @@
1
- /**
2
- * Represents a single item/card in the Kanban board
3
- */
4
- export interface KanbanItem<T = unknown> {
5
- id: string;
6
- data: T;
7
- }
8
-
9
- /**
10
- * Represents a column in the Kanban board
11
- */
12
- export interface KanbanColumn<T = unknown> {
13
- key: string;
14
- title: string;
15
- items: KanbanItem<T>[];
16
- }
17
-
18
- /**
19
- * Props passed to the renderCard function
20
- */
21
- export interface KanbanRenderCardProps<T = unknown> {
22
- item: T;
23
- columnKey: string;
24
- id: string;
25
- hovered: boolean;
26
- isDragging: boolean;
27
- }
28
-
29
- /**
30
- * Props passed to the renderColumnHeader function
31
- */
32
- export interface KanbanRenderColumnHeaderProps {
33
- columnKey: string;
34
- title: string;
35
- itemCount: number;
36
- isMinimized: boolean;
37
- onMinimizeToggle: () => void;
38
- }
39
-
40
- /**
41
- * Information about the current drag operation
42
- */
43
- export interface DragInfo {
44
- type: "card" | "column";
45
- id: string;
46
- sourceColumnKey: string;
47
- sourceIndex: number;
48
- }
49
-
50
- /**
51
- * Information about the current drop target
52
- */
53
- export interface DropTarget {
54
- type: "card" | "column";
55
- columnKey: string;
56
- index: number;
57
- }
58
-
59
- /**
60
- * Drag preview dimensions and offset
61
- */
62
- export interface DragPreviewInfo {
63
- width: number;
64
- height: number;
65
- offsetX: number;
66
- offsetY: number;
67
- }
68
-
69
- /**
70
- * Result of a card move operation
71
- */
72
- export interface CardMoveResult<T = unknown> {
73
- cardId: string;
74
- cardData: T;
75
- sourceColumnKey: string;
76
- sourceIndex: number;
77
- targetColumnKey: string;
78
- targetIndex: number;
79
- }
80
-
81
- /**
82
- * Result of a column move operation
83
- */
84
- export interface ColumnMoveResult {
85
- columnKey: string;
86
- sourceIndex: number;
87
- targetIndex: number;
88
- }
89
-
90
- /**
91
- * Props passed to the renderAddCardPlaceholder function
92
- */
93
- export interface KanbanRenderAddCardPlaceholderProps {
94
- columnKey: string;
95
- onPress: () => void;
96
- }
97
-
98
- /**
99
- * Props passed to the renderInsertCardButton function
100
- */
101
- export interface KanbanRenderInsertCardButtonProps {
102
- columnKey: string;
103
- index: number;
104
- onPress: () => void;
105
- }
106
-
107
- /**
108
- * Props passed to the renderCollapsedColumn function
109
- */
110
- export interface KanbanRenderCollapsedColumnProps {
111
- columnKey: string;
112
- title: string;
113
- itemCount: number;
114
- showDropIndicator: boolean;
115
- onExpand: () => void;
116
- }