@proyecto-viviana/solidaria-components 0.2.9 → 0.3.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.
- package/README.md +39 -272
- package/dist/ActionBar.d.ts +21 -13
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionGroup.d.ts +8 -8
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/Alert.d.ts +5 -5
- package/dist/Alert.d.ts.map +1 -1
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +18 -7
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +24 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +38 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +32 -7
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +19 -14
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Color.d.ts +103 -14
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +6 -6
- package/dist/ColorEditor.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +85 -19
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +2 -2
- package/dist/ContextualHelpTrigger.d.ts.map +1 -1
- package/dist/DateField.d.ts +8 -6
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +53 -22
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +23 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +6 -6
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragPreview.d.ts +2 -2
- package/dist/DragPreview.d.ts.map +1 -1
- package/dist/DropZone.d.ts +4 -4
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/FieldError.d.ts +9 -5
- package/dist/FieldError.d.ts.map +1 -1
- package/dist/FileTrigger.d.ts +3 -3
- package/dist/FileTrigger.d.ts.map +1 -1
- package/dist/Focusable.d.ts +2 -2
- package/dist/Focusable.d.ts.map +1 -1
- package/dist/Form.d.ts +18 -4
- package/dist/Form.d.ts.map +1 -1
- package/dist/GridList.d.ts +32 -12
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +5 -5
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Keyboard.d.ts +1 -1
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +32 -12
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +6 -6
- package/dist/ListDropTargetDelegate.d.ts.map +1 -1
- package/dist/Menu.d.ts +65 -14
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +3 -3
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +5 -5
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +8 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +28 -5
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +2 -2
- package/dist/Pressable.d.ts.map +1 -1
- package/dist/ProgressBar.d.ts +5 -3
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +34 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +2 -2
- package/dist/RouterProvider.d.ts.map +1 -1
- package/dist/SearchField.d.ts +23 -20
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +41 -11
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +3 -3
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +6 -4
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/Slider.d.ts +12 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +187 -23
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +45 -9
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +2 -2
- package/dist/TextField.d.ts +15 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +6 -6
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +11 -5
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.d.ts +7 -7
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +50 -8
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +66 -17
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +12 -12
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/VirtualizerLayouts.d.ts +2 -2
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.d.ts +1 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +5 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23247 -18564
- package/dist/index.js.map +1 -1
- package/dist/index.jsx +18110 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +13 -13
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +1 -1
- package/dist/virtualizer/Layout.d.ts.map +1 -1
- package/package.json +31 -32
- package/src/ActionBar.tsx +75 -72
- package/src/ActionGroup.tsx +53 -61
- package/src/Alert.tsx +17 -42
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +149 -80
- package/src/Button.tsx +267 -70
- package/src/Calendar.tsx +218 -138
- package/src/Checkbox.tsx +413 -121
- package/src/Collection.tsx +67 -58
- package/src/Color.tsx +803 -380
- package/src/ColorEditor.tsx +131 -149
- package/src/ComboBox.tsx +414 -249
- package/src/ContextualHelpTrigger.tsx +86 -74
- package/src/DateField.tsx +185 -91
- package/src/DatePicker.tsx +524 -213
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +156 -118
- package/src/Disclosure.tsx +127 -80
- package/src/DragAndDrop.tsx +60 -54
- package/src/DragPreview.tsx +13 -11
- package/src/DropZone.tsx +42 -22
- package/src/FieldError.tsx +45 -23
- package/src/FileTrigger.tsx +19 -19
- package/src/Focusable.tsx +21 -24
- package/src/Form.tsx +71 -16
- package/src/GridList.tsx +273 -197
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +22 -43
- package/src/Keyboard.tsx +3 -3
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +125 -75
- package/src/ListBox.tsx +332 -233
- package/src/ListDropTargetDelegate.ts +81 -80
- package/src/Menu.tsx +1023 -274
- package/src/Meter.tsx +38 -56
- package/src/Modal.tsx +243 -175
- package/src/NumberField.tsx +139 -143
- package/src/Popover.tsx +386 -233
- package/src/Pressable.tsx +21 -21
- package/src/ProgressBar.tsx +48 -57
- package/src/RadioGroup.tsx +524 -122
- package/src/RangeCalendar.tsx +157 -90
- package/src/RouterProvider.tsx +30 -47
- package/src/SearchField.tsx +362 -143
- package/src/Select.tsx +656 -233
- package/src/SelectionIndicator.tsx +18 -15
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +103 -97
- package/src/Slider.tsx +138 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1308 -342
- package/src/Tabs.tsx +324 -103
- package/src/TagGroup.tsx +139 -126
- package/src/Text.tsx +3 -3
- package/src/TextField.tsx +389 -79
- package/src/TimeField.tsx +136 -76
- package/src/Toast.tsx +209 -157
- package/src/ToggleButton.tsx +47 -37
- package/src/ToggleButtonGroup.tsx +39 -34
- package/src/Toolbar.tsx +54 -69
- package/src/Tooltip.tsx +387 -119
- package/src/Tree.tsx +651 -368
- package/src/Virtualizer.tsx +208 -180
- package/src/VirtualizerLayouts.ts +45 -30
- package/src/VisuallyHidden.tsx +19 -19
- package/src/contexts.ts +29 -37
- package/src/index.ts +110 -195
- package/src/useDragAndDrop.ts +87 -71
- package/src/utils.tsx +40 -55
- package/src/virtualizer/Layout.ts +14 -22
- package/dist/index.ssr.js +0 -16996
- package/dist/index.ssr.js.map +0 -1
package/src/Virtualizer.tsx
CHANGED
|
@@ -14,10 +14,15 @@ import {
|
|
|
14
14
|
onMount,
|
|
15
15
|
splitProps,
|
|
16
16
|
useContext,
|
|
17
|
-
} from
|
|
18
|
-
import type {
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
} from "solid-js";
|
|
18
|
+
import type {
|
|
19
|
+
DragTypes,
|
|
20
|
+
DropOperation,
|
|
21
|
+
DropTarget,
|
|
22
|
+
ItemDropTarget,
|
|
23
|
+
} from "@proyecto-viviana/solid-stately";
|
|
24
|
+
import { CollectionRendererContext, type CollectionRendererContextValue } from "./Collection";
|
|
25
|
+
import { filterDOMProps } from "./utils";
|
|
21
26
|
import {
|
|
22
27
|
GridLayout,
|
|
23
28
|
ListLayout,
|
|
@@ -35,26 +40,19 @@ import {
|
|
|
35
40
|
type VirtualizerDropTarget,
|
|
36
41
|
type VirtualizerVisibleRange,
|
|
37
42
|
type WaterfallLayoutOptions,
|
|
38
|
-
} from
|
|
43
|
+
} from "./VirtualizerLayouts";
|
|
39
44
|
|
|
40
45
|
export interface LayoutOptionsDelegate<O> {
|
|
41
46
|
useLayoutOptions?(): O;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
export interface VirtualizerLayout<O = unknown> extends LayoutOptionsDelegate<O> {
|
|
45
|
-
getVisibleRange?(
|
|
46
|
-
|
|
47
|
-
options?: O
|
|
48
|
-
): VirtualizerVisibleRange;
|
|
49
|
-
getLayoutInfo?(
|
|
50
|
-
index: number,
|
|
51
|
-
context: VirtualizerLayoutInfoContext,
|
|
52
|
-
options?: O
|
|
53
|
-
): LayoutInfo;
|
|
50
|
+
getVisibleRange?(context: VirtualizerRangeContext, options?: O): VirtualizerVisibleRange;
|
|
51
|
+
getLayoutInfo?(index: number, context: VirtualizerLayoutInfoContext, options?: O): LayoutInfo;
|
|
54
52
|
getDropTargetFromPoint?(
|
|
55
53
|
point: Point,
|
|
56
54
|
itemCount: number,
|
|
57
|
-
options?: O
|
|
55
|
+
options?: O,
|
|
58
56
|
): VirtualizerDropTarget | null;
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -64,8 +62,8 @@ export interface VirtualizerLayoutClass<O> {
|
|
|
64
62
|
|
|
65
63
|
export type VirtualizerKeyboardNavigationOverride = (
|
|
66
64
|
target: DropTarget | null,
|
|
67
|
-
direction:
|
|
68
|
-
isValidDropTarget: (target: DropTarget) => boolean
|
|
65
|
+
direction: "next" | "previous",
|
|
66
|
+
isValidDropTarget: (target: DropTarget) => boolean,
|
|
69
67
|
) => DropTarget | null;
|
|
70
68
|
|
|
71
69
|
export interface VirtualizerContextValue<O = unknown> {
|
|
@@ -75,19 +73,25 @@ export interface VirtualizerContextValue<O = unknown> {
|
|
|
75
73
|
getVisibleRange: (itemCount: number) => VirtualizerVisibleRange;
|
|
76
74
|
getLayoutInfo: (index: number) => LayoutInfo;
|
|
77
75
|
getDropTargetFromPoint: (point: Point, itemCount: number) => VirtualizerDropTarget | null;
|
|
78
|
-
setDropTargetResolver: (
|
|
79
|
-
setDropTargetItemCountResolver: (
|
|
80
|
-
setDropTargetIndexResolver: (
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
setDropTargetResolver: (resolver: VirtualizerDropTargetResolver | undefined) => void;
|
|
77
|
+
setDropTargetItemCountResolver: (resolver: (() => number) | undefined) => void;
|
|
78
|
+
setDropTargetIndexResolver: (
|
|
79
|
+
resolver: ((key: string | number) => number | null) | undefined,
|
|
80
|
+
) => void;
|
|
81
|
+
setDropOperationResolver: (resolver: VirtualizerDropOperationResolver | undefined) => void;
|
|
82
|
+
setKeyboardNavigationOverride: (
|
|
83
|
+
override: VirtualizerKeyboardNavigationOverride | undefined,
|
|
84
|
+
) => void;
|
|
83
85
|
getBaseKeyboardNavigationTarget: VirtualizerKeyboardNavigationOverride;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
export type VirtualizerDropTargetResolver = (
|
|
88
|
+
export type VirtualizerDropTargetResolver = (
|
|
89
|
+
target: VirtualizerDropTarget,
|
|
90
|
+
) => VirtualizerDropTarget;
|
|
87
91
|
export type VirtualizerDropOperationResolver = (
|
|
88
92
|
target: DropTarget,
|
|
89
93
|
types: DragTypes,
|
|
90
|
-
allowedOperations: DropOperation[]
|
|
94
|
+
allowedOperations: DropOperation[],
|
|
91
95
|
) => DropOperation;
|
|
92
96
|
|
|
93
97
|
export const VirtualizerContext = createContext<VirtualizerContextValue<unknown> | null>(null);
|
|
@@ -96,8 +100,10 @@ export function useVirtualizerContext<O>(): VirtualizerContextValue<O> | null {
|
|
|
96
100
|
return useContext(VirtualizerContext) as VirtualizerContextValue<O> | null;
|
|
97
101
|
}
|
|
98
102
|
|
|
99
|
-
export interface VirtualizerProps<O>
|
|
100
|
-
|
|
103
|
+
export interface VirtualizerProps<O> extends Omit<
|
|
104
|
+
JSX.HTMLAttributes<HTMLDivElement>,
|
|
105
|
+
"children" | "class" | "style"
|
|
106
|
+
> {
|
|
101
107
|
/** The child collection to virtualize (e.g. ListBox, GridList, or Table). */
|
|
102
108
|
children: JSX.Element;
|
|
103
109
|
/** Layout object or constructor for layout behavior and options delegation. */
|
|
@@ -105,7 +111,10 @@ export interface VirtualizerProps<O>
|
|
|
105
111
|
/** Layout options consumed by the layout implementation. */
|
|
106
112
|
layoutOptions?: O;
|
|
107
113
|
/** Optional renderer for collection drop indicators in virtualized flows. */
|
|
108
|
-
renderDropIndicator?: (
|
|
114
|
+
renderDropIndicator?: (
|
|
115
|
+
index: number,
|
|
116
|
+
position: "before" | "after" | "on",
|
|
117
|
+
) => JSX.Element | undefined;
|
|
109
118
|
/** Optional operation resolver for collection drop target operations. */
|
|
110
119
|
getDropOperation?: VirtualizerDropOperationResolver;
|
|
111
120
|
class?: string;
|
|
@@ -114,7 +123,7 @@ export interface VirtualizerProps<O>
|
|
|
114
123
|
|
|
115
124
|
function getObjectValue<T extends object, K extends keyof T>(
|
|
116
125
|
value: T | undefined,
|
|
117
|
-
key: K
|
|
126
|
+
key: K,
|
|
118
127
|
): T[K] | undefined {
|
|
119
128
|
return value?.[key];
|
|
120
129
|
}
|
|
@@ -145,39 +154,39 @@ function isSameLayoutInfo(a: LayoutInfo, b: LayoutInfo): boolean {
|
|
|
145
154
|
*/
|
|
146
155
|
export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
147
156
|
const [local, domProps] = splitProps(props, [
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
"children",
|
|
158
|
+
"layout",
|
|
159
|
+
"layoutOptions",
|
|
160
|
+
"renderDropIndicator",
|
|
161
|
+
"getDropOperation",
|
|
162
|
+
"class",
|
|
163
|
+
"style",
|
|
155
164
|
]);
|
|
156
165
|
const [scrollOffset, setScrollOffset] = createSignal(0);
|
|
157
166
|
const [measuredViewportSize, setMeasuredViewportSize] = createSignal(0);
|
|
158
167
|
const [measuredViewportWidth, setMeasuredViewportWidth] = createSignal(0);
|
|
159
|
-
const [dropTargetResolver, setDropTargetResolver] = createSignal<
|
|
160
|
-
undefined
|
|
161
|
-
);
|
|
162
|
-
const [dropTargetItemCountResolver, setDropTargetItemCountResolver] = createSignal<
|
|
163
|
-
undefined
|
|
164
|
-
);
|
|
168
|
+
const [dropTargetResolver, setDropTargetResolver] = createSignal<
|
|
169
|
+
VirtualizerDropTargetResolver | undefined
|
|
170
|
+
>(undefined);
|
|
171
|
+
const [dropTargetItemCountResolver, setDropTargetItemCountResolver] = createSignal<
|
|
172
|
+
(() => number) | undefined
|
|
173
|
+
>(undefined);
|
|
165
174
|
const [dropTargetIndexResolver, setDropTargetIndexResolver] = createSignal<
|
|
166
175
|
((key: string | number) => number | null) | undefined
|
|
167
176
|
>(undefined);
|
|
168
|
-
const [dropOperationResolver, setDropOperationResolver] = createSignal<
|
|
169
|
-
undefined
|
|
170
|
-
);
|
|
171
|
-
const [keyboardNavigationOverride, setKeyboardNavigationOverride] = createSignal<
|
|
172
|
-
undefined
|
|
173
|
-
);
|
|
177
|
+
const [dropOperationResolver, setDropOperationResolver] = createSignal<
|
|
178
|
+
VirtualizerDropOperationResolver | undefined
|
|
179
|
+
>(undefined);
|
|
180
|
+
const [keyboardNavigationOverride, setKeyboardNavigationOverride] = createSignal<
|
|
181
|
+
VirtualizerKeyboardNavigationOverride | undefined
|
|
182
|
+
>(undefined);
|
|
174
183
|
let containerRef: HTMLDivElement | undefined;
|
|
175
184
|
const fallbackLayout = new ListLayout();
|
|
176
185
|
const visibleRangeCache = new Map<number, VirtualizerVisibleRange>();
|
|
177
186
|
const layoutInfoCache = new Map<number, LayoutInfo>();
|
|
178
187
|
|
|
179
188
|
const layout = createMemo<VirtualizerLayout<O>>(() => {
|
|
180
|
-
if (typeof local.layout ===
|
|
189
|
+
if (typeof local.layout === "function") {
|
|
181
190
|
return new local.layout();
|
|
182
191
|
}
|
|
183
192
|
return local.layout;
|
|
@@ -194,10 +203,12 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
194
203
|
return local.layoutOptions ?? fromLayout;
|
|
195
204
|
});
|
|
196
205
|
|
|
197
|
-
const virtualOptions = createMemo(
|
|
206
|
+
const virtualOptions = createMemo(
|
|
207
|
+
() => resolvedLayoutOptions() as DefaultVirtualizerLayoutOptions | undefined,
|
|
208
|
+
);
|
|
198
209
|
const layoutOptionsWithViewport = createMemo(() => {
|
|
199
210
|
const options = resolvedLayoutOptions();
|
|
200
|
-
if (options && typeof options ===
|
|
211
|
+
if (options && typeof options === "object") {
|
|
201
212
|
return {
|
|
202
213
|
...(options as Record<string, unknown>),
|
|
203
214
|
viewportWidth: measuredViewportWidth(),
|
|
@@ -205,10 +216,10 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
205
216
|
}
|
|
206
217
|
return { viewportWidth: measuredViewportWidth() } as O;
|
|
207
218
|
});
|
|
208
|
-
const itemSize = createMemo(() => getObjectValue(virtualOptions(),
|
|
209
|
-
const overscan = createMemo(() => getObjectValue(virtualOptions(),
|
|
219
|
+
const itemSize = createMemo(() => getObjectValue(virtualOptions(), "itemSize") ?? 40);
|
|
220
|
+
const overscan = createMemo(() => getObjectValue(virtualOptions(), "overscan") ?? 2);
|
|
210
221
|
const viewportSize = createMemo(
|
|
211
|
-
() => getObjectValue(virtualOptions(),
|
|
222
|
+
() => getObjectValue(virtualOptions(), "viewportSize") ?? measuredViewportSize() ?? 0,
|
|
212
223
|
);
|
|
213
224
|
|
|
214
225
|
const getVisibleRange = (itemCount: number): VirtualizerVisibleRange => {
|
|
@@ -222,7 +233,13 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
222
233
|
const layoutResult = resolvedLayout().getVisibleRange?.(ctx, layoutOptionsWithViewport());
|
|
223
234
|
const nextRange =
|
|
224
235
|
layoutResult ??
|
|
225
|
-
calculateLinearVisibleRange(
|
|
236
|
+
calculateLinearVisibleRange(
|
|
237
|
+
itemCount,
|
|
238
|
+
ctx.scrollOffset,
|
|
239
|
+
ctx.viewportSize,
|
|
240
|
+
itemSize(),
|
|
241
|
+
ctx.overscan,
|
|
242
|
+
);
|
|
226
243
|
const cachedRange = visibleRangeCache.get(itemCount);
|
|
227
244
|
if (cachedRange && isSameRange(cachedRange, nextRange)) {
|
|
228
245
|
return cachedRange;
|
|
@@ -252,8 +269,12 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
252
269
|
layoutInfoCache.set(index, nextInfo);
|
|
253
270
|
return nextInfo;
|
|
254
271
|
};
|
|
255
|
-
const getDropTargetFromPoint = (
|
|
256
|
-
|
|
272
|
+
const getDropTargetFromPoint = (
|
|
273
|
+
point: Point,
|
|
274
|
+
itemCount: number,
|
|
275
|
+
): VirtualizerDropTarget | null => {
|
|
276
|
+
const target =
|
|
277
|
+
resolvedLayout().getDropTargetFromPoint?.(point, itemCount, layoutOptionsWithViewport()) ??
|
|
257
278
|
fallbackLayout.getDropTargetFromPoint(point, itemCount, virtualOptions());
|
|
258
279
|
if (!target) return null;
|
|
259
280
|
const resolver = dropTargetResolver();
|
|
@@ -265,20 +286,26 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
265
286
|
const assignDropTargetItemCountResolver = (resolver: (() => number) | undefined): void => {
|
|
266
287
|
setDropTargetItemCountResolver(() => resolver);
|
|
267
288
|
};
|
|
268
|
-
const assignDropTargetIndexResolver = (
|
|
289
|
+
const assignDropTargetIndexResolver = (
|
|
290
|
+
resolver: ((key: string | number) => number | null) | undefined,
|
|
291
|
+
): void => {
|
|
269
292
|
setDropTargetIndexResolver(() => resolver);
|
|
270
293
|
};
|
|
271
|
-
const assignDropOperationResolver = (
|
|
294
|
+
const assignDropOperationResolver = (
|
|
295
|
+
resolver: VirtualizerDropOperationResolver | undefined,
|
|
296
|
+
): void => {
|
|
272
297
|
setDropOperationResolver(() => resolver);
|
|
273
298
|
};
|
|
274
|
-
const assignKeyboardNavigationOverride = (
|
|
299
|
+
const assignKeyboardNavigationOverride = (
|
|
300
|
+
override: VirtualizerKeyboardNavigationOverride | undefined,
|
|
301
|
+
): void => {
|
|
275
302
|
setKeyboardNavigationOverride(() => override);
|
|
276
303
|
};
|
|
277
304
|
const toCollectionDropTarget = (target: VirtualizerDropTarget): DropTarget => {
|
|
278
|
-
if (target.type ===
|
|
305
|
+
if (target.type === "root") return { type: "root" };
|
|
279
306
|
const key = target.key ?? target.index;
|
|
280
307
|
return {
|
|
281
|
-
type:
|
|
308
|
+
type: "item",
|
|
282
309
|
key,
|
|
283
310
|
dropPosition: target.position,
|
|
284
311
|
} as ItemDropTarget;
|
|
@@ -286,19 +313,20 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
286
313
|
const getCollectionDropTargetFromPoint = (
|
|
287
314
|
x: number,
|
|
288
315
|
y: number,
|
|
289
|
-
isValidDropTarget: (target: DropTarget) => boolean
|
|
316
|
+
isValidDropTarget: (target: DropTarget) => boolean,
|
|
290
317
|
): DropTarget | null => {
|
|
291
318
|
const itemCount = dropTargetItemCountResolver()?.() ?? 0;
|
|
292
319
|
const virtualTarget = getDropTargetFromPoint({ x, y }, itemCount);
|
|
293
320
|
if (!virtualTarget) return null;
|
|
294
321
|
const mappedTarget = toCollectionDropTarget(virtualTarget);
|
|
295
322
|
if (isValidDropTarget(mappedTarget)) return mappedTarget;
|
|
296
|
-
if (mappedTarget.type ===
|
|
297
|
-
const alternatePositions: Array<
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
323
|
+
if (mappedTarget.type === "item") {
|
|
324
|
+
const alternatePositions: Array<"before" | "after" | "on"> =
|
|
325
|
+
mappedTarget.dropPosition === "on"
|
|
326
|
+
? ["before", "after"]
|
|
327
|
+
: mappedTarget.dropPosition === "before"
|
|
328
|
+
? ["on", "after"]
|
|
329
|
+
: ["on", "before"];
|
|
302
330
|
for (const position of alternatePositions) {
|
|
303
331
|
const alternateTarget: DropTarget = {
|
|
304
332
|
...mappedTarget,
|
|
@@ -306,7 +334,7 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
306
334
|
};
|
|
307
335
|
if (isValidDropTarget(alternateTarget)) return alternateTarget;
|
|
308
336
|
}
|
|
309
|
-
const rootTarget: DropTarget = { type:
|
|
337
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
310
338
|
if (isValidDropTarget(rootTarget)) return rootTarget;
|
|
311
339
|
}
|
|
312
340
|
return null;
|
|
@@ -314,81 +342,86 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
314
342
|
const getCollectionDropOperation = (
|
|
315
343
|
target: DropTarget,
|
|
316
344
|
types: DragTypes,
|
|
317
|
-
allowedOperations: DropOperation[]
|
|
345
|
+
allowedOperations: DropOperation[],
|
|
318
346
|
): DropOperation => {
|
|
319
347
|
const resolver = dropOperationResolver() ?? local.getDropOperation;
|
|
320
348
|
if (resolver) return resolver(target, types, allowedOperations);
|
|
321
|
-
if (allowedOperations.length === 0) return
|
|
322
|
-
if (target.type ===
|
|
323
|
-
if (allowedOperations.includes(
|
|
324
|
-
if (allowedOperations.includes(
|
|
325
|
-
} else if (target.dropPosition ===
|
|
326
|
-
if (allowedOperations.includes(
|
|
327
|
-
if (allowedOperations.includes(
|
|
349
|
+
if (allowedOperations.length === 0) return "cancel";
|
|
350
|
+
if (target.type === "root") {
|
|
351
|
+
if (allowedOperations.includes("copy")) return "copy";
|
|
352
|
+
if (allowedOperations.includes("move")) return "move";
|
|
353
|
+
} else if (target.dropPosition === "on") {
|
|
354
|
+
if (allowedOperations.includes("copy")) return "copy";
|
|
355
|
+
if (allowedOperations.includes("move")) return "move";
|
|
328
356
|
} else {
|
|
329
|
-
if (allowedOperations.includes(
|
|
330
|
-
if (allowedOperations.includes(
|
|
357
|
+
if (allowedOperations.includes("move")) return "move";
|
|
358
|
+
if (allowedOperations.includes("copy")) return "copy";
|
|
331
359
|
}
|
|
332
|
-
if (allowedOperations.includes(
|
|
333
|
-
return allowedOperations.find((operation) => operation !==
|
|
360
|
+
if (allowedOperations.includes("link")) return "link";
|
|
361
|
+
return allowedOperations.find((operation) => operation !== "cancel") ?? "cancel";
|
|
334
362
|
};
|
|
335
363
|
const getBaseKeyboardNavigationTarget = (
|
|
336
364
|
target: DropTarget | null,
|
|
337
|
-
direction:
|
|
338
|
-
isValidDropTarget: (target: DropTarget) => boolean
|
|
365
|
+
direction: "next" | "previous",
|
|
366
|
+
isValidDropTarget: (target: DropTarget) => boolean,
|
|
339
367
|
): DropTarget | null => {
|
|
340
368
|
const itemCount = dropTargetItemCountResolver()?.() ?? 0;
|
|
341
369
|
if (itemCount <= 0) {
|
|
342
|
-
const rootTarget: DropTarget = { type:
|
|
370
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
343
371
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
344
372
|
}
|
|
345
373
|
|
|
346
374
|
const resolveCurrentIndex = (currentTarget: DropTarget | null): number | null => {
|
|
347
|
-
if (!currentTarget || currentTarget.type ===
|
|
375
|
+
if (!currentTarget || currentTarget.type === "root") return null;
|
|
348
376
|
const resolver = dropTargetIndexResolver();
|
|
349
377
|
if (resolver) {
|
|
350
378
|
const fromResolver = resolver(currentTarget.key);
|
|
351
|
-
if (fromResolver != null && fromResolver >= 0 && fromResolver < itemCount)
|
|
379
|
+
if (fromResolver != null && fromResolver >= 0 && fromResolver < itemCount)
|
|
380
|
+
return fromResolver;
|
|
352
381
|
return null;
|
|
353
382
|
}
|
|
354
|
-
if (
|
|
383
|
+
if (
|
|
384
|
+
typeof currentTarget.key === "number" &&
|
|
385
|
+
currentTarget.key >= 0 &&
|
|
386
|
+
currentTarget.key < itemCount
|
|
387
|
+
) {
|
|
355
388
|
return currentTarget.key;
|
|
356
389
|
}
|
|
357
390
|
return null;
|
|
358
391
|
};
|
|
359
392
|
const getCurrentIndex = (currentTarget: DropTarget | null): number => {
|
|
360
|
-
if (!currentTarget || currentTarget.type ===
|
|
361
|
-
return direction ===
|
|
393
|
+
if (!currentTarget || currentTarget.type === "root") {
|
|
394
|
+
return direction === "next" ? -1 : itemCount;
|
|
362
395
|
}
|
|
363
396
|
const resolvedIndex = resolveCurrentIndex(currentTarget);
|
|
364
397
|
if (resolvedIndex != null) return resolvedIndex;
|
|
365
|
-
return direction ===
|
|
398
|
+
return direction === "next" ? -1 : itemCount;
|
|
366
399
|
};
|
|
367
400
|
const tryCurrentItemTransition = (currentTarget: DropTarget | null): DropTarget | null => {
|
|
368
|
-
if (!currentTarget || currentTarget.type !==
|
|
369
|
-
const tryPosition = (position:
|
|
401
|
+
if (!currentTarget || currentTarget.type !== "item") return null;
|
|
402
|
+
const tryPosition = (position: "before" | "on" | "after"): DropTarget | null => {
|
|
370
403
|
if (currentTarget.dropPosition === position) return null;
|
|
371
404
|
const nextTarget: DropTarget = {
|
|
372
|
-
type:
|
|
405
|
+
type: "item",
|
|
373
406
|
key: currentTarget.key,
|
|
374
407
|
dropPosition: position,
|
|
375
408
|
};
|
|
376
409
|
return isValidDropTarget(nextTarget) ? nextTarget : null;
|
|
377
410
|
};
|
|
378
411
|
|
|
379
|
-
if (direction ===
|
|
380
|
-
if (currentTarget.dropPosition ===
|
|
381
|
-
return tryPosition(
|
|
412
|
+
if (direction === "next") {
|
|
413
|
+
if (currentTarget.dropPosition === "before") {
|
|
414
|
+
return tryPosition("on") ?? tryPosition("after");
|
|
382
415
|
}
|
|
383
|
-
if (currentTarget.dropPosition ===
|
|
384
|
-
return tryPosition(
|
|
416
|
+
if (currentTarget.dropPosition === "on") {
|
|
417
|
+
return tryPosition("after");
|
|
385
418
|
}
|
|
386
419
|
} else {
|
|
387
|
-
if (currentTarget.dropPosition ===
|
|
388
|
-
return tryPosition(
|
|
420
|
+
if (currentTarget.dropPosition === "after") {
|
|
421
|
+
return tryPosition("on") ?? tryPosition("before");
|
|
389
422
|
}
|
|
390
|
-
if (currentTarget.dropPosition ===
|
|
391
|
-
return tryPosition(
|
|
423
|
+
if (currentTarget.dropPosition === "on") {
|
|
424
|
+
return tryPosition("before");
|
|
392
425
|
}
|
|
393
426
|
}
|
|
394
427
|
|
|
@@ -397,19 +430,14 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
397
430
|
const scanFromIndex = (
|
|
398
431
|
startIndex: number,
|
|
399
432
|
step: number,
|
|
400
|
-
directionForInsertion:
|
|
433
|
+
directionForInsertion: "next" | "previous",
|
|
401
434
|
): DropTarget | null => {
|
|
402
|
-
for (
|
|
403
|
-
|
|
404
|
-
index >= 0 && index < itemCount;
|
|
405
|
-
index += step
|
|
406
|
-
) {
|
|
407
|
-
const onTarget = tryTarget(index, 'on');
|
|
435
|
+
for (let index = startIndex; index >= 0 && index < itemCount; index += step) {
|
|
436
|
+
const onTarget = tryTarget(index, "on");
|
|
408
437
|
if (onTarget) return onTarget;
|
|
409
438
|
|
|
410
|
-
const insertionOrder: Array<
|
|
411
|
-
? [
|
|
412
|
-
: ['after', 'before'];
|
|
439
|
+
const insertionOrder: Array<"before" | "after"> =
|
|
440
|
+
directionForInsertion === "next" ? ["before", "after"] : ["after", "before"];
|
|
413
441
|
for (const position of insertionOrder) {
|
|
414
442
|
const insertionTarget = tryTarget(index, position);
|
|
415
443
|
if (insertionTarget) return insertionTarget;
|
|
@@ -418,62 +446,59 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
418
446
|
return null;
|
|
419
447
|
};
|
|
420
448
|
const findNavigationTarget = (currentIndex: number, step = 1): DropTarget | null => {
|
|
421
|
-
const delta = direction ===
|
|
449
|
+
const delta = direction === "next" ? 1 : -1;
|
|
422
450
|
const stepSize = Math.max(1, step);
|
|
423
451
|
const nextStart = currentIndex + delta * stepSize;
|
|
424
452
|
const clampedStart = Math.max(0, Math.min(itemCount - 1, nextStart));
|
|
425
453
|
if (nextStart < 0 || nextStart >= itemCount) {
|
|
426
|
-
const rootTarget: DropTarget = { type:
|
|
454
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
427
455
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
428
456
|
}
|
|
429
457
|
const primaryTarget = scanFromIndex(clampedStart, delta, direction);
|
|
430
458
|
if (primaryTarget) return primaryTarget;
|
|
431
|
-
const oppositeDirection:
|
|
459
|
+
const oppositeDirection: "next" | "previous" = direction === "next" ? "previous" : "next";
|
|
432
460
|
const oppositeTarget = scanFromIndex(clampedStart - delta, -delta, oppositeDirection);
|
|
433
461
|
if (oppositeTarget) return oppositeTarget;
|
|
434
462
|
|
|
435
|
-
const rootTarget: DropTarget = { type:
|
|
463
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
436
464
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
437
465
|
};
|
|
438
|
-
const tryTarget = (
|
|
439
|
-
index: number,
|
|
440
|
-
position: 'on' | 'before' | 'after'
|
|
441
|
-
): DropTarget | null => {
|
|
466
|
+
const tryTarget = (index: number, position: "on" | "before" | "after"): DropTarget | null => {
|
|
442
467
|
const layoutInfo = getLayoutInfo(index);
|
|
443
468
|
const virtualTarget = getDropTargetFromPoint(
|
|
444
469
|
{
|
|
445
470
|
x: layoutInfo.rect.x + 1,
|
|
446
471
|
y: layoutInfo.rect.y + layoutInfo.rect.height / 2,
|
|
447
472
|
},
|
|
448
|
-
itemCount
|
|
473
|
+
itemCount,
|
|
449
474
|
);
|
|
450
|
-
if (!virtualTarget || virtualTarget.type ===
|
|
475
|
+
if (!virtualTarget || virtualTarget.type === "root") return null;
|
|
451
476
|
const nextTarget = toCollectionDropTarget({ ...virtualTarget, position });
|
|
452
477
|
return isValidDropTarget(nextTarget) ? nextTarget : null;
|
|
453
478
|
};
|
|
454
|
-
const tryBoundaryTarget = (boundaryDirection:
|
|
455
|
-
const boundaryIndex = boundaryDirection ===
|
|
456
|
-
const boundaryOrder: Array<
|
|
457
|
-
? [
|
|
458
|
-
: ['after', 'on', 'before'];
|
|
479
|
+
const tryBoundaryTarget = (boundaryDirection: "next" | "previous"): DropTarget | null => {
|
|
480
|
+
const boundaryIndex = boundaryDirection === "next" ? 0 : itemCount - 1;
|
|
481
|
+
const boundaryOrder: Array<"before" | "on" | "after"> =
|
|
482
|
+
boundaryDirection === "next" ? ["before", "on", "after"] : ["after", "on", "before"];
|
|
459
483
|
for (const position of boundaryOrder) {
|
|
460
484
|
const candidate = tryTarget(boundaryIndex, position);
|
|
461
485
|
if (candidate) return candidate;
|
|
462
486
|
}
|
|
463
487
|
return null;
|
|
464
488
|
};
|
|
465
|
-
const directTransition =
|
|
489
|
+
const directTransition =
|
|
490
|
+
resolveCurrentIndex(target) != null ? tryCurrentItemTransition(target) : null;
|
|
466
491
|
if (directTransition) return directTransition;
|
|
467
|
-
if (!target || target.type ===
|
|
492
|
+
if (!target || target.type === "root") {
|
|
468
493
|
const boundaryTarget = tryBoundaryTarget(direction);
|
|
469
494
|
if (boundaryTarget) return boundaryTarget;
|
|
470
|
-
const rootTarget: DropTarget = { type:
|
|
495
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
471
496
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
472
497
|
}
|
|
473
498
|
const currentIndex = getCurrentIndex(target);
|
|
474
|
-
const nextStart = currentIndex + (direction ===
|
|
499
|
+
const nextStart = currentIndex + (direction === "next" ? 1 : -1);
|
|
475
500
|
if (nextStart < 0 || nextStart >= itemCount) {
|
|
476
|
-
const rootTarget: DropTarget = { type:
|
|
501
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
477
502
|
if (isValidDropTarget(rootTarget)) return rootTarget;
|
|
478
503
|
const wrappedBoundary = tryBoundaryTarget(direction);
|
|
479
504
|
if (wrappedBoundary) return wrappedBoundary;
|
|
@@ -483,8 +508,8 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
483
508
|
};
|
|
484
509
|
const getKeyboardNavigationTarget = (
|
|
485
510
|
target: DropTarget | null,
|
|
486
|
-
direction:
|
|
487
|
-
isValidDropTarget: (target: DropTarget) => boolean
|
|
511
|
+
direction: "next" | "previous",
|
|
512
|
+
isValidDropTarget: (target: DropTarget) => boolean,
|
|
488
513
|
): DropTarget | null => {
|
|
489
514
|
// If a collection component (e.g. Tree) has installed a keyboard navigation override,
|
|
490
515
|
// delegate to it. This enables collection-aware navigation (tree branch traversal, etc.).
|
|
@@ -496,20 +521,19 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
496
521
|
};
|
|
497
522
|
const getKeyboardPageNavigationTarget = (
|
|
498
523
|
target: DropTarget | null,
|
|
499
|
-
direction:
|
|
500
|
-
isValidDropTarget: (target: DropTarget) => boolean
|
|
524
|
+
direction: "next" | "previous",
|
|
525
|
+
isValidDropTarget: (target: DropTarget) => boolean,
|
|
501
526
|
): DropTarget | null => {
|
|
502
527
|
const itemCount = dropTargetItemCountResolver()?.() ?? 0;
|
|
503
528
|
if (itemCount <= 0) {
|
|
504
|
-
const rootTarget: DropTarget = { type:
|
|
529
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
505
530
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
506
531
|
}
|
|
507
|
-
if (!target || target.type ===
|
|
508
|
-
const startIndex = direction ===
|
|
509
|
-
const delta = direction ===
|
|
510
|
-
const boundaryOrder: Array<
|
|
511
|
-
? [
|
|
512
|
-
: ['after', 'on', 'before'];
|
|
532
|
+
if (!target || target.type === "root") {
|
|
533
|
+
const startIndex = direction === "next" ? 0 : itemCount - 1;
|
|
534
|
+
const delta = direction === "next" ? 1 : -1;
|
|
535
|
+
const boundaryOrder: Array<"before" | "on" | "after"> =
|
|
536
|
+
direction === "next" ? ["before", "on", "after"] : ["after", "on", "before"];
|
|
513
537
|
for (let index = startIndex; index >= 0 && index < itemCount; index += delta) {
|
|
514
538
|
const layoutInfo = getLayoutInfo(index);
|
|
515
539
|
const virtualTarget = getDropTargetFromPoint(
|
|
@@ -517,50 +541,53 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
517
541
|
x: layoutInfo.rect.x + 1,
|
|
518
542
|
y: layoutInfo.rect.y + layoutInfo.rect.height / 2,
|
|
519
543
|
},
|
|
520
|
-
itemCount
|
|
544
|
+
itemCount,
|
|
521
545
|
);
|
|
522
|
-
if (!virtualTarget || virtualTarget.type ===
|
|
546
|
+
if (!virtualTarget || virtualTarget.type === "root") continue;
|
|
523
547
|
for (const position of boundaryOrder) {
|
|
524
548
|
const candidate = toCollectionDropTarget({ ...virtualTarget, position });
|
|
525
549
|
if (isValidDropTarget(candidate)) return candidate;
|
|
526
550
|
}
|
|
527
551
|
}
|
|
528
|
-
const rootTarget: DropTarget = { type:
|
|
552
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
529
553
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
530
554
|
}
|
|
531
555
|
const resolver = dropTargetIndexResolver();
|
|
532
556
|
const resolvedIndex = resolver?.(target.key);
|
|
533
|
-
const currentIndex =
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
557
|
+
const currentIndex =
|
|
558
|
+
resolvedIndex != null
|
|
559
|
+
? resolvedIndex
|
|
560
|
+
: resolver
|
|
561
|
+
? direction === "next"
|
|
562
|
+
? -1
|
|
563
|
+
: itemCount
|
|
564
|
+
: typeof target.key === "number"
|
|
565
|
+
? target.key
|
|
566
|
+
: direction === "next"
|
|
567
|
+
? -1
|
|
568
|
+
: itemCount;
|
|
538
569
|
const pageSize = Math.max(1, Math.floor(viewportSize() / Math.max(1, itemSize())));
|
|
539
|
-
const delta = direction ===
|
|
570
|
+
const delta = direction === "next" ? 1 : -1;
|
|
540
571
|
const nextStart = currentIndex + delta * pageSize;
|
|
541
572
|
const clampedStart = Math.max(0, Math.min(itemCount - 1, nextStart));
|
|
542
|
-
const tryTarget = (
|
|
543
|
-
index: number,
|
|
544
|
-
position: 'on' | 'before' | 'after'
|
|
545
|
-
): DropTarget | null => {
|
|
573
|
+
const tryTarget = (index: number, position: "on" | "before" | "after"): DropTarget | null => {
|
|
546
574
|
const layoutInfo = getLayoutInfo(index);
|
|
547
575
|
const virtualTarget = getDropTargetFromPoint(
|
|
548
576
|
{
|
|
549
577
|
x: layoutInfo.rect.x + 1,
|
|
550
578
|
y: layoutInfo.rect.y + layoutInfo.rect.height / 2,
|
|
551
579
|
},
|
|
552
|
-
itemCount
|
|
580
|
+
itemCount,
|
|
553
581
|
);
|
|
554
|
-
if (!virtualTarget || virtualTarget.type ===
|
|
582
|
+
if (!virtualTarget || virtualTarget.type === "root") return null;
|
|
555
583
|
const nextTarget = toCollectionDropTarget({ ...virtualTarget, position });
|
|
556
584
|
return isValidDropTarget(nextTarget) ? nextTarget : null;
|
|
557
585
|
};
|
|
558
586
|
const scanFromIndex = (startIndex: number, step: number): DropTarget | null => {
|
|
559
|
-
const insertionOrder: Array<
|
|
560
|
-
? [
|
|
561
|
-
: ['after', 'before'];
|
|
587
|
+
const insertionOrder: Array<"before" | "after"> =
|
|
588
|
+
step > 0 ? ["before", "after"] : ["after", "before"];
|
|
562
589
|
for (let index = startIndex; index >= 0 && index < itemCount; index += step) {
|
|
563
|
-
const onTarget = tryTarget(index,
|
|
590
|
+
const onTarget = tryTarget(index, "on");
|
|
564
591
|
if (onTarget) return onTarget;
|
|
565
592
|
for (const position of insertionOrder) {
|
|
566
593
|
const insertionTarget = tryTarget(index, position);
|
|
@@ -570,27 +597,27 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
570
597
|
return null;
|
|
571
598
|
};
|
|
572
599
|
if (nextStart < 0 || nextStart >= itemCount) {
|
|
573
|
-
if (direction ===
|
|
574
|
-
const endBoundaryTarget =
|
|
575
|
-
|
|
576
|
-
|
|
600
|
+
if (direction === "next") {
|
|
601
|
+
const endBoundaryTarget =
|
|
602
|
+
tryTarget(itemCount - 1, "after") ??
|
|
603
|
+
tryTarget(itemCount - 1, "on") ??
|
|
604
|
+
tryTarget(itemCount - 1, "before");
|
|
577
605
|
if (endBoundaryTarget) return endBoundaryTarget;
|
|
578
606
|
const backwardFallback = scanFromIndex(itemCount - 1, -1);
|
|
579
607
|
if (backwardFallback) return backwardFallback;
|
|
580
608
|
} else {
|
|
581
609
|
if (currentIndex <= 0) {
|
|
582
|
-
const rootTarget: DropTarget = { type:
|
|
610
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
583
611
|
if (isValidDropTarget(rootTarget)) return rootTarget;
|
|
584
612
|
}
|
|
585
|
-
const startBoundaryTarget =
|
|
586
|
-
?? tryTarget(0,
|
|
587
|
-
?? tryTarget(0, 'after');
|
|
613
|
+
const startBoundaryTarget =
|
|
614
|
+
tryTarget(0, "before") ?? tryTarget(0, "on") ?? tryTarget(0, "after");
|
|
588
615
|
if (startBoundaryTarget) return startBoundaryTarget;
|
|
589
616
|
const forwardFallback = scanFromIndex(0, 1);
|
|
590
617
|
if (forwardFallback) return forwardFallback;
|
|
591
618
|
}
|
|
592
619
|
|
|
593
|
-
const rootTarget: DropTarget = { type:
|
|
620
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
594
621
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
595
622
|
}
|
|
596
623
|
const primaryTarget = scanFromIndex(clampedStart, delta);
|
|
@@ -598,7 +625,7 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
598
625
|
const oppositeTarget = scanFromIndex(clampedStart - delta, -delta);
|
|
599
626
|
if (oppositeTarget) return oppositeTarget;
|
|
600
627
|
|
|
601
|
-
const rootTarget: DropTarget = { type:
|
|
628
|
+
const rootTarget: DropTarget = { type: "root" };
|
|
602
629
|
return isValidDropTarget(rootTarget) ? rootTarget : null;
|
|
603
630
|
};
|
|
604
631
|
|
|
@@ -642,9 +669,15 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
642
669
|
onMount(() => {
|
|
643
670
|
updateViewportSize();
|
|
644
671
|
const handleResize = () => updateViewportSize();
|
|
645
|
-
window.addEventListener(
|
|
672
|
+
window.addEventListener("resize", handleResize);
|
|
673
|
+
const resizeObserver =
|
|
674
|
+
typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => updateViewportSize()) : null;
|
|
675
|
+
if (containerRef && resizeObserver) {
|
|
676
|
+
resizeObserver.observe(containerRef);
|
|
677
|
+
}
|
|
646
678
|
onCleanup(() => {
|
|
647
|
-
window.removeEventListener(
|
|
679
|
+
window.removeEventListener("resize", handleResize);
|
|
680
|
+
resizeObserver?.disconnect();
|
|
648
681
|
});
|
|
649
682
|
});
|
|
650
683
|
|
|
@@ -681,12 +714,7 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
681
714
|
);
|
|
682
715
|
}
|
|
683
716
|
|
|
684
|
-
export {
|
|
685
|
-
ListLayout,
|
|
686
|
-
GridLayout,
|
|
687
|
-
WaterfallLayout,
|
|
688
|
-
TableLayout,
|
|
689
|
-
};
|
|
717
|
+
export { ListLayout, GridLayout, WaterfallLayout, TableLayout };
|
|
690
718
|
|
|
691
719
|
export type {
|
|
692
720
|
VirtualizerVisibleRange,
|