@octanejs/aria 0.0.46 → 0.0.47
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 +7 -6
- package/UPSTREAM.md +58 -69
- package/package.json +11 -11
- package/src/calendar/useCalendarGrid.tsx +64 -62
- package/src/collections/Document.ts +3 -0
- package/src/color/useColorArea.tsx +95 -69
- package/src/color/useColorWheel.tsx +38 -37
- package/src/combobox/{useComboBox.ts → useComboBox.tsx} +239 -259
- package/src/components/ComboBox.ts +35 -2
- package/src/components/Dialog.ts +12 -1
- package/src/components/DropZone.tsx +3 -2
- package/src/components/FileTrigger.tsx +1 -0
- package/src/components/GridList.ts +11 -2
- package/src/components/ListBox.ts +1 -1
- package/src/components/Menu.ts +1 -0
- package/src/components/Meter.ts +3 -1
- package/src/components/Popover.ts +20 -8
- package/src/components/PreviewTrigger.tsx +101 -0
- package/src/components/ProgressBar.ts +10 -2
- package/src/components/Select.ts +1 -1
- package/src/components/Table.ts +26 -15
- package/src/components/TokenField.tsx +395 -0
- package/src/components/Tooltip.ts +4 -6
- package/src/components/Tree.ts +14 -7
- package/src/components/Virtualizer.tsx +30 -14
- package/src/components/index.ts +22 -0
- package/src/components/utils.ts +1 -1
- package/src/datepicker/useDateField.tsx +2 -11
- package/src/datepicker/useDatePickerGroup.tsx +44 -33
- package/src/datepicker/useDateSegment.tsx +31 -30
- package/src/dialog/useDialog.ts +8 -1
- package/src/dnd/DragManager.tsx +5 -1
- package/src/dnd/useDrag.tsx +2 -1
- package/src/focus/FocusScope.ts +2 -2
- package/src/grid/useGrid.ts +3 -0
- package/src/grid/{useGridCell.ts → useGridCell.tsx} +121 -64
- package/src/grid/utils.ts +1 -0
- package/src/gridlist/{useGridListItem.ts → useGridListItem.tsx} +152 -111
- package/src/index.ts +22 -0
- package/src/interactions/createEventHandler.ts +11 -8
- package/src/interactions/createKeyboardShortcutHandler.tsx +218 -0
- package/src/interactions/textSelection.ts +3 -3
- package/src/interactions/useContextMenu.tsx +125 -0
- package/src/interactions/useFocusVisible.ts +4 -4
- package/src/interactions/useKeyboard.ts +50 -2
- package/src/interactions/useLongPress.ts +33 -22
- package/src/interactions/useMove.ts +6 -6
- package/src/interactions/usePress.ts +8 -0
- package/src/interactions/utils.ts +10 -10
- package/src/intl/combobox/fi-FI.json +2 -2
- package/src/intl/previewtrigger/ar-AE.json +3 -0
- package/src/intl/previewtrigger/bg-BG.json +3 -0
- package/src/intl/previewtrigger/cs-CZ.json +3 -0
- package/src/intl/previewtrigger/da-DK.json +3 -0
- package/src/intl/previewtrigger/de-DE.json +3 -0
- package/src/intl/previewtrigger/el-GR.json +3 -0
- package/src/intl/previewtrigger/en-US.json +3 -0
- package/src/intl/previewtrigger/es-ES.json +3 -0
- package/src/intl/previewtrigger/et-EE.json +3 -0
- package/src/intl/previewtrigger/fi-FI.json +3 -0
- package/src/intl/previewtrigger/fr-FR.json +3 -0
- package/src/intl/previewtrigger/he-IL.json +3 -0
- package/src/intl/previewtrigger/hr-HR.json +3 -0
- package/src/intl/previewtrigger/hu-HU.json +3 -0
- package/src/intl/previewtrigger/index.ts +73 -0
- package/src/intl/previewtrigger/it-IT.json +3 -0
- package/src/intl/previewtrigger/ja-JP.json +3 -0
- package/src/intl/previewtrigger/ko-KR.json +3 -0
- package/src/intl/previewtrigger/lt-LT.json +3 -0
- package/src/intl/previewtrigger/lv-LV.json +3 -0
- package/src/intl/previewtrigger/nb-NO.json +3 -0
- package/src/intl/previewtrigger/nl-NL.json +3 -0
- package/src/intl/previewtrigger/pl-PL.json +3 -0
- package/src/intl/previewtrigger/pt-BR.json +3 -0
- package/src/intl/previewtrigger/pt-PT.json +3 -0
- package/src/intl/previewtrigger/ro-RO.json +3 -0
- package/src/intl/previewtrigger/ru-RU.json +3 -0
- package/src/intl/previewtrigger/sk-SK.json +3 -0
- package/src/intl/previewtrigger/sl-SI.json +3 -0
- package/src/intl/previewtrigger/sr-SP.json +3 -0
- package/src/intl/previewtrigger/sv-SE.json +3 -0
- package/src/intl/previewtrigger/tr-TR.json +3 -0
- package/src/intl/previewtrigger/uk-UA.json +3 -0
- package/src/intl/previewtrigger/zh-CN.json +3 -0
- package/src/intl/previewtrigger/zh-TW.json +3 -0
- package/src/intl/table/ar-AE.json +3 -3
- package/src/intl/table/bg-BG.json +3 -3
- package/src/intl/table/cs-CZ.json +3 -3
- package/src/intl/table/da-DK.json +3 -3
- package/src/intl/table/de-DE.json +3 -3
- package/src/intl/table/el-GR.json +3 -3
- package/src/intl/table/es-ES.json +3 -3
- package/src/intl/table/et-EE.json +3 -3
- package/src/intl/table/fi-FI.json +3 -3
- package/src/intl/table/fr-FR.json +3 -3
- package/src/intl/table/he-IL.json +3 -3
- package/src/intl/table/hr-HR.json +3 -3
- package/src/intl/table/hu-HU.json +3 -3
- package/src/intl/table/it-IT.json +3 -3
- package/src/intl/table/ja-JP.json +3 -3
- package/src/intl/table/ko-KR.json +3 -3
- package/src/intl/table/lt-LT.json +3 -3
- package/src/intl/table/lv-LV.json +3 -3
- package/src/intl/table/nb-NO.json +3 -3
- package/src/intl/table/nl-NL.json +3 -3
- package/src/intl/table/pl-PL.json +3 -3
- package/src/intl/table/pt-BR.json +3 -3
- package/src/intl/table/pt-PT.json +3 -3
- package/src/intl/table/ro-RO.json +3 -3
- package/src/intl/table/ru-RU.json +3 -3
- package/src/intl/table/sk-SK.json +3 -3
- package/src/intl/table/sl-SI.json +3 -3
- package/src/intl/table/sr-SP.json +3 -3
- package/src/intl/table/sv-SE.json +3 -3
- package/src/intl/table/tr-TR.json +3 -3
- package/src/intl/table/uk-UA.json +3 -3
- package/src/intl/table/zh-CN.json +4 -4
- package/src/intl/table/zh-TW.json +3 -3
- package/src/intl/tree/es-ES.json +1 -1
- package/src/link/useLink.ts +2 -0
- package/src/menu/useMenuItem.ts +33 -36
- package/src/menu/useMenuTrigger.tsx +217 -0
- package/src/menu/{useSubmenuTrigger.ts → useSubmenuTrigger.tsx} +112 -152
- package/src/numberfield/{useNumberField.ts → useNumberField.tsx} +185 -239
- package/src/overlays/Overlay.ts +5 -1
- package/src/overlays/ariaHideOutside.ts +6 -8
- package/src/overlays/useCloseOnScroll.ts +7 -5
- package/src/overlays/{useOverlay.ts → useOverlay.tsx} +72 -84
- package/src/overlays/usePopover.ts +10 -5
- package/src/overlays/usePreventScroll.ts +4 -4
- package/src/progress/useProgressBar.ts +2 -1
- package/src/radio/{useRadioGroup.ts → useRadioGroup.tsx} +83 -80
- package/src/searchfield/useSearchField.tsx +147 -0
- package/src/select/useSelect.ts +20 -20
- package/src/selection/useSelectableCollection.tsx +751 -0
- package/src/selection/useSelectableItem.ts +48 -11
- package/src/slider/{useSliderThumb.ts → useSliderThumb.tsx} +116 -159
- package/src/spinbutton/useSpinButton.tsx +330 -0
- package/src/stately/combobox/useComboBoxState.ts +1 -1
- package/src/stately/grid/useGridState.ts +9 -10
- package/src/stately/index.ts +11 -0
- package/src/stately/menu/useMenuTriggerState.ts +1 -1
- package/src/stately/menu/useSubmenuTriggerState.ts +2 -0
- package/src/stately/overlays/useOverlayTriggerState.ts +12 -1
- package/src/stately/radio/useRadioGroupState.ts +5 -1
- package/src/stately/table/TableUtils.ts +15 -1
- package/src/stately/table/useTableState.ts +7 -0
- package/src/stately/tokenfield/TokenFieldValue.tsx +440 -0
- package/src/stately/tokenfield/useTokenFieldState.tsx +57 -0
- package/src/stately/tooltip/useTooltipTriggerState.ts +16 -7
- package/src/stately/virtualizer/Layout.tsx +2 -0
- package/src/stately/virtualizer/ScrollAnchor.tsx +338 -0
- package/src/stately/virtualizer/Virtualizer.tsx +52 -1
- package/src/stately/virtualizer/types.tsx +2 -0
- package/src/table/useTableCell.ts +12 -0
- package/src/table/useTableColumnHeader.ts +8 -1
- package/src/table/useTableColumnResize.tsx +354 -0
- package/src/tag/useTag.ts +22 -15
- package/src/textfield/useTextField.ts +2 -0
- package/src/tokenfield/useToken.tsx +64 -0
- package/src/tokenfield/useTokenField.tsx +849 -0
- package/src/tooltip/usePreviewTrigger.tsx +266 -0
- package/src/tooltip/useSafeArea.tsx +171 -0
- package/src/upstream-exports/react-aria/mergeRefs.tsx +3 -0
- package/src/upstream-exports/react-aria/usePreviewTrigger.tsx +18 -0
- package/src/upstream-exports/react-aria/useTokenField.tsx +22 -0
- package/src/upstream-exports/react-stately/private/collections/getChildNodes.tsx +8 -0
- package/src/upstream-exports/react-stately/private/collections/getItemCount.tsx +2 -0
- package/src/upstream-exports/react-stately/private/grid/GridCollection.tsx +7 -0
- package/src/upstream-exports/react-stately/private/grid/useGridState.tsx +6 -0
- package/src/upstream-exports/react-stately/private/utils/number.tsx +2 -0
- package/src/upstream-exports/react-stately/useComboBoxState.tsx +23 -0
- package/src/upstream-exports/react-stately/useListState.tsx +15 -0
- package/src/upstream-exports/react-stately/useMenuTriggerState.tsx +26 -0
- package/src/upstream-exports/react-stately/useMultipleSelectionState.tsx +21 -0
- package/src/upstream-exports/react-stately/useNumberFieldState.tsx +20 -0
- package/src/upstream-exports/react-stately/useOverlayTriggerState.tsx +20 -0
- package/src/upstream-exports/react-stately/useRadioGroupState.tsx +16 -0
- package/src/upstream-exports/react-stately/useSearchFieldState.tsx +19 -0
- package/src/upstream-exports/react-stately/useSliderState.tsx +20 -0
- package/src/upstream-exports/react-stately/useTableState.tsx +45 -0
- package/src/upstream-exports/react-stately/useTokenFieldState.tsx +25 -0
- package/src/upstream-exports/react-stately/useTooltipTriggerState.tsx +20 -0
- package/src/upstream-exports/react-stately/useTreeState.tsx +14 -0
- package/src/utils/domHelpers.ts +74 -17
- package/src/utils/isVirtualEvent.ts +2 -1
- package/src/utils/openLink.ts +8 -3
- package/src/utils/platform.ts +7 -3
- package/src/utils/scrollIntoView.ts +4 -4
- package/src/utils/shadowdom/DOMFunctions.ts +42 -2
- package/src/utils/useId.ts +11 -2
- package/src/utils/useLoadMoreSentinel.ts +8 -3
- package/src/utils/useViewportSize.ts +3 -3
- package/src/virtualizer/ScrollView.tsx +13 -4
- package/src/virtualizer/VirtualizerItem.tsx +3 -1
- package/src/virtualizer/useVirtualizerItem.tsx +43 -3
- package/src/menu/useMenuTrigger.ts +0 -189
- package/src/searchfield/useSearchField.ts +0 -156
- package/src/selection/useSelectableCollection.ts +0 -750
- package/src/spinbutton/useSpinButton.ts +0 -380
- package/src/table/useTableColumnResize.ts +0 -374
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @jsxImportSource octane */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
4
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
6
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
*
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
9
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
10
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
11
|
+
* governing permissions and limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export { useSearchFieldState } from '../../stately/searchfield/useSearchFieldState';
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
SearchFieldProps,
|
|
18
|
+
SearchFieldState,
|
|
19
|
+
} from '../../stately/searchfield/useSearchFieldState';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @jsxImportSource octane */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
4
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
6
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
*
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
9
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
10
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
11
|
+
* governing permissions and limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export { useSliderState } from '../../stately/slider/useSliderState';
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
SliderProps,
|
|
18
|
+
SliderStateOptions,
|
|
19
|
+
SliderState,
|
|
20
|
+
} from '../../stately/slider/useSliderState';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** @jsxImportSource octane */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
4
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
6
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
*
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
9
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
10
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
11
|
+
* governing permissions and limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type {
|
|
15
|
+
TableColumnResizeState,
|
|
16
|
+
TableColumnResizeStateProps,
|
|
17
|
+
} from '../../stately/table/useTableColumnResizeState';
|
|
18
|
+
export type { TableProps, TableState, TableStateProps } from '../../stately/table/useTableState';
|
|
19
|
+
|
|
20
|
+
export { useTableColumnResizeState } from '../../stately/table/useTableColumnResizeState';
|
|
21
|
+
export { useTableState, UNSTABLE_useFilteredTableState } from '../../stately/table/useTableState';
|
|
22
|
+
|
|
23
|
+
export type { CellProps, CellElement, CellRenderer } from '../../stately/table/Cell';
|
|
24
|
+
export { Cell } from '../../stately/table/Cell';
|
|
25
|
+
|
|
26
|
+
export type {
|
|
27
|
+
ColumnProps,
|
|
28
|
+
ColumnSize,
|
|
29
|
+
ColumnDynamicSize,
|
|
30
|
+
ColumnStaticSize,
|
|
31
|
+
ColumnElement,
|
|
32
|
+
ColumnRenderer,
|
|
33
|
+
} from '../../stately/table/Column';
|
|
34
|
+
export { Column } from '../../stately/table/Column';
|
|
35
|
+
|
|
36
|
+
export type { RowProps, RowElement } from '../../stately/table/Row';
|
|
37
|
+
export { Row } from '../../stately/table/Row';
|
|
38
|
+
|
|
39
|
+
export type { TableBodyProps } from '../../stately/table/TableBody';
|
|
40
|
+
export { TableBody } from '../../stately/table/TableBody';
|
|
41
|
+
|
|
42
|
+
export type { TableHeaderProps } from '../../stately/table/TableHeader';
|
|
43
|
+
export { TableHeader } from '../../stately/table/TableHeader';
|
|
44
|
+
|
|
45
|
+
export type { SortDescriptor, SortDirection } from '@react-types/shared';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** @jsxImportSource octane */
|
|
2
|
+
// Ported from adobe/react-spectrum@5ecb3333001313e83898cd07644227897e3bae1f (packages/react-stately/exports/useTokenFieldState.ts).
|
|
3
|
+
/*
|
|
4
|
+
* Copyright 2026 Adobe. All rights reserved.
|
|
5
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
7
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
10
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
11
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
12
|
+
* governing permissions and limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export { useTokenFieldState } from '../../stately/tokenfield/useTokenFieldState';
|
|
16
|
+
export { TokenFieldValue } from '../../stately/tokenfield/TokenFieldValue';
|
|
17
|
+
|
|
18
|
+
export type { TokenFieldProps, TokenFieldState } from '../../stately/tokenfield/useTokenFieldState';
|
|
19
|
+
export type {
|
|
20
|
+
TokenFieldSegment,
|
|
21
|
+
TokenSegment,
|
|
22
|
+
TextSegment,
|
|
23
|
+
Position,
|
|
24
|
+
TokenFieldValueOptions,
|
|
25
|
+
} from '../../stately/tokenfield/TokenFieldValue';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @jsxImportSource octane */
|
|
2
|
+
// Ported from adobe/react-spectrum@5ecb3333001313e83898cd07644227897e3bae1f (packages/react-stately/exports/useTooltipTriggerState.ts).
|
|
3
|
+
/*
|
|
4
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
5
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
7
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
10
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
11
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
12
|
+
* governing permissions and limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export { useTooltipTriggerState } from '../../stately/tooltip/useTooltipTriggerState';
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
TooltipTriggerProps,
|
|
19
|
+
TooltipTriggerState,
|
|
20
|
+
} from '../../stately/tooltip/useTooltipTriggerState';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @jsxImportSource octane */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
4
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
6
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
*
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
9
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
10
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
11
|
+
* governing permissions and limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
export type { TreeProps, TreeState } from '../../stately/tree/useTreeState';
|
|
14
|
+
export { useTreeState } from '../../stately/tree/useTreeState';
|
package/src/utils/domHelpers.ts
CHANGED
|
@@ -1,36 +1,93 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { EventMapType } from '@react-types/shared';
|
|
14
|
+
|
|
15
|
+
export const getOwnerDocument = (target?: EventTarget | null): Document => {
|
|
16
|
+
if (isWindow(target)) return target.document;
|
|
2
17
|
|
|
3
|
-
|
|
4
|
-
|
|
18
|
+
if (isDocument(target)) return target;
|
|
19
|
+
|
|
20
|
+
// @ts-expect-error Ensure safe access in SSR environments.
|
|
21
|
+
return target?.ownerDocument ?? (typeof document !== 'undefined' ? document : undefined);
|
|
5
22
|
};
|
|
6
23
|
|
|
7
|
-
export const getOwnerWindow = (
|
|
8
|
-
|
|
9
|
-
): Window & typeof globalThis => {
|
|
10
|
-
if (el && 'window' in el && el.window === el) {
|
|
11
|
-
return el;
|
|
12
|
-
}
|
|
24
|
+
export const getOwnerWindow = (target?: EventTarget | null): Window & typeof globalThis => {
|
|
25
|
+
let ownerDocument = getOwnerDocument(target);
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
return
|
|
27
|
+
// @ts-expect-error Ensure safe access in SSR environments.
|
|
28
|
+
return ownerDocument?.defaultView ?? (typeof window !== 'undefined' ? window : undefined);
|
|
16
29
|
};
|
|
17
30
|
|
|
18
31
|
/**
|
|
19
32
|
* Type guard that checks if a value is a Node. Verifies the presence and type of the nodeType
|
|
20
33
|
* property.
|
|
21
34
|
*/
|
|
22
|
-
function isNode(value: unknown): value is Node {
|
|
35
|
+
export function isNode(value: unknown): value is Node {
|
|
23
36
|
return (
|
|
24
37
|
value !== null &&
|
|
25
38
|
typeof value === 'object' &&
|
|
26
39
|
'nodeType' in value &&
|
|
27
|
-
typeof
|
|
40
|
+
typeof value.nodeType === 'number'
|
|
28
41
|
);
|
|
29
42
|
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Type guard that checks if a value is a Window. Uses window self reference checks to
|
|
46
|
+
* distinguish Window from other values.
|
|
47
|
+
*/
|
|
48
|
+
function isWindow(value: unknown): value is Window & typeof globalThis {
|
|
49
|
+
return typeof value === 'object' && value != null && 'window' in value && value.window === value;
|
|
50
|
+
}
|
|
51
|
+
|
|
30
52
|
/**
|
|
31
|
-
* Type guard that checks if a
|
|
32
|
-
* distinguish
|
|
53
|
+
* Type guard that checks if a value is a Document. Uses nodeType and host property checks to
|
|
54
|
+
* distinguish Document from other values.
|
|
33
55
|
*/
|
|
34
|
-
export function
|
|
35
|
-
return isNode(
|
|
56
|
+
export function isDocument(value: unknown): value is Document {
|
|
57
|
+
return isNode(value) && value.nodeType === 9;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Type guard that checks if a value is a ShadowRoot. Uses nodeType and host property checks to
|
|
62
|
+
* distinguish ShadowRoot from other values.
|
|
63
|
+
*/
|
|
64
|
+
export function isShadowRoot(value: unknown): value is ShadowRoot {
|
|
65
|
+
// 11 = DOCUMENT_FRAGMENT_NODE
|
|
66
|
+
return isNode(value) && value.nodeType === 11 && 'host' in value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Attaches an event listener on target(s) and returns a cleanup function.
|
|
71
|
+
*/
|
|
72
|
+
export function addEvent<T extends EventTarget, K extends keyof EventMapType<Exclude<T, null>>>(
|
|
73
|
+
target: T | EventTarget[] | null,
|
|
74
|
+
event: Extract<K, string> | (string & {}),
|
|
75
|
+
listener?: (this: T, ev: EventMapType<Exclude<T, null>>[K]) => any,
|
|
76
|
+
options?: boolean | AddEventListenerOptions,
|
|
77
|
+
): () => void {
|
|
78
|
+
if (listener == null || target == null) {
|
|
79
|
+
return () => {};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let eventTargets = Array.isArray(target) ? target : [target];
|
|
83
|
+
|
|
84
|
+
for (let eventTarget of eventTargets) {
|
|
85
|
+
eventTarget.addEventListener(event, listener as EventListener, options);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return () => {
|
|
89
|
+
for (let eventTarget of eventTargets) {
|
|
90
|
+
eventTarget.removeEventListener(event, listener as EventListener, options);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
36
93
|
}
|
|
@@ -38,7 +38,8 @@ export function isVirtualPointerEvent(event: PointerEvent): boolean {
|
|
|
38
38
|
// Talkback double tap from Windows Firefox touch screen press
|
|
39
39
|
return (
|
|
40
40
|
(!isAndroid() && event.width === 0 && event.height === 0) ||
|
|
41
|
-
(
|
|
41
|
+
(isAndroid() &&
|
|
42
|
+
event.width === 1 &&
|
|
42
43
|
event.height === 1 &&
|
|
43
44
|
event.pressure === 0 &&
|
|
44
45
|
event.detail === 0 &&
|
package/src/utils/openLink.ts
CHANGED
|
@@ -100,7 +100,12 @@ export function openLink(target: HTMLAnchorElement, modifiers: Modifiers, setOpe
|
|
|
100
100
|
// will prevent links with target="_blank" from opening. However, it does allow the event if the
|
|
101
101
|
// Command/Control key is held, which opens the link in a background tab. This seems like the best we can do.
|
|
102
102
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=257870 and https://bugzilla.mozilla.org/show_bug.cgi?id=746640.
|
|
103
|
-
if (
|
|
103
|
+
if (
|
|
104
|
+
!isWebKit() &&
|
|
105
|
+
isFirefox() &&
|
|
106
|
+
window.event?.type?.startsWith('key') &&
|
|
107
|
+
target.target === '_blank'
|
|
108
|
+
) {
|
|
104
109
|
if (isMac()) {
|
|
105
110
|
metaKey = true;
|
|
106
111
|
} else {
|
|
@@ -200,8 +205,8 @@ export function useLinkProps(...args: any[]): LinkDOMProps {
|
|
|
200
205
|
const href = router.useHref(props?.href ?? '');
|
|
201
206
|
let linkProps: LinkDOMProps = {};
|
|
202
207
|
if (props) {
|
|
203
|
-
for (let key of ['href', 'target', 'rel', 'download', 'ping', 'referrerPolicy']) {
|
|
204
|
-
if (key in props) {
|
|
208
|
+
for (let key of ['href', 'target', 'rel', 'download', 'ping', 'referrerPolicy'] as const) {
|
|
209
|
+
if (key in props && props[key] !== undefined) {
|
|
205
210
|
(linkProps as any)[key] = key === 'href' ? href : (props as any)[key];
|
|
206
211
|
}
|
|
207
212
|
}
|
package/src/utils/platform.ts
CHANGED
|
@@ -58,11 +58,15 @@ export const isAppleDevice: () => boolean = cached(function () {
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
export const isWebKit: () => boolean = cached(function () {
|
|
61
|
-
return testUserAgent(/AppleWebKit/i) && !isChrome();
|
|
61
|
+
return testUserAgent(/AppleWebKit/i) && (isIOS() || !isChrome());
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const isSafari: () => boolean = cached(function () {
|
|
65
|
+
return isWebKit() && !isChrome() && !isFirefox();
|
|
62
66
|
});
|
|
63
67
|
|
|
64
68
|
export const isChrome: () => boolean = cached(function () {
|
|
65
|
-
return testUserAgent(/Chrome/i);
|
|
69
|
+
return testUserAgent(/Chrome|CriOS|CrMo/i);
|
|
66
70
|
});
|
|
67
71
|
|
|
68
72
|
export const isAndroid: () => boolean = cached(function () {
|
|
@@ -70,5 +74,5 @@ export const isAndroid: () => boolean = cached(function () {
|
|
|
70
74
|
});
|
|
71
75
|
|
|
72
76
|
export const isFirefox: () => boolean = cached(function () {
|
|
73
|
-
return testUserAgent(/Firefox/i);
|
|
77
|
+
return testUserAgent(/(Firefox|FxiOS)/i);
|
|
74
78
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Verbatim (no React surface), including the NODE_ENV === 'test' direct-assignment branch
|
|
3
3
|
// (jsdom has no scrollTo implementation).
|
|
4
4
|
import { getScrollParents } from './getScrollParents';
|
|
5
|
-
import { isIOS } from '
|
|
5
|
+
import { isIOS, isWebKit } from '../utils/platform';
|
|
6
6
|
|
|
7
7
|
interface ScrollIntoViewOpts {
|
|
8
8
|
/** The position to align items along the block axis in. */
|
|
@@ -81,10 +81,10 @@ export function scrollIntoView(
|
|
|
81
81
|
let scrollPortRight = viewRight - (isRoot ? 0 : borderRightWidth) - scrollPaddingRight;
|
|
82
82
|
|
|
83
83
|
// IOS always positions the scrollbar on the right ¯\_(ツ)_/¯
|
|
84
|
-
if (viewStyle.direction === '
|
|
85
|
-
scrollPortLeft += scrollBarWidth;
|
|
86
|
-
} else {
|
|
84
|
+
if ((isIOS() && isWebKit()) || viewStyle.direction === 'ltr') {
|
|
87
85
|
scrollPortRight -= scrollBarWidth;
|
|
86
|
+
} else if (viewStyle.direction === 'rtl') {
|
|
87
|
+
scrollPortLeft += scrollBarWidth;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
let shouldScrollBlock = scrollAreaTop < scrollPortTop || scrollAreaBottom > scrollPortBottom;
|
|
@@ -29,8 +29,8 @@ export function nodeContains(
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
if (
|
|
32
|
-
(currentNode as HTMLSlotElement).
|
|
33
|
-
(currentNode as HTMLSlotElement).assignedSlot
|
|
32
|
+
typeof (currentNode as HTMLSlotElement).assignedElements !== 'function' &&
|
|
33
|
+
(currentNode as HTMLSlotElement).assignedSlot?.parentNode
|
|
34
34
|
) {
|
|
35
35
|
// Element is slotted
|
|
36
36
|
currentNode = (currentNode as HTMLSlotElement).assignedSlot!.parentNode;
|
|
@@ -77,6 +77,46 @@ export function getEventTarget<T extends Event>(event: T): EventTarget {
|
|
|
77
77
|
return event.target as EventTarget;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* ShadowDOM safe fast version of node.contains(document.activeElement).
|
|
82
|
+
*
|
|
83
|
+
* @param node
|
|
84
|
+
* @returns
|
|
85
|
+
*/
|
|
86
|
+
export function getPropagationTargets(
|
|
87
|
+
from: Element | null | undefined,
|
|
88
|
+
to?: Document | Window | Element | null,
|
|
89
|
+
): EventTarget[] {
|
|
90
|
+
// If `to` is coming from a ref, its type technically allows `null`.
|
|
91
|
+
// In practice, this function will generally be called from within a useEffect.
|
|
92
|
+
// If the ref has not resolved by that point, then a coding error has been made.
|
|
93
|
+
// Better to return an empty array than `[window]`, which may appear to work
|
|
94
|
+
// in the light DOM, but fail in the shadow DOM.
|
|
95
|
+
if (to === null) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
to = to ?? getOwnerWindow(from);
|
|
99
|
+
let targets: EventTarget[] = [to];
|
|
100
|
+
if (!shadowDOM() || !from || from === to) {
|
|
101
|
+
return targets;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// The root `to` itself lives in. The event already reaches `to` once
|
|
105
|
+
// it is inside this root, so we must NOT collect this root or anything above
|
|
106
|
+
// it — only the shadow roots strictly between `refNode` and `to`.
|
|
107
|
+
// `window` has no getRootNode; its boundary is the document, which the walk
|
|
108
|
+
// reaches naturally (the document is not a ShadowRoot, so the loop exits).
|
|
109
|
+
let toRoot = 'getRootNode' in to ? to.getRootNode() : null;
|
|
110
|
+
let current: Node | null = from.getRootNode() ?? null;
|
|
111
|
+
while (isShadowRoot(current) && current !== toRoot) {
|
|
112
|
+
// order shouldn't matter
|
|
113
|
+
targets.push(current);
|
|
114
|
+
current = current.host.getRootNode();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return targets;
|
|
118
|
+
}
|
|
119
|
+
|
|
80
120
|
/**
|
|
81
121
|
* ShadowDOM safe fast version of node.contains(document.activeElement).
|
|
82
122
|
*
|
package/src/utils/useId.ts
CHANGED
|
@@ -29,6 +29,7 @@ if (typeof FinalizationRegistry !== 'undefined') {
|
|
|
29
29
|
*
|
|
30
30
|
* @param defaultId - Default component id.
|
|
31
31
|
*/
|
|
32
|
+
let registeredIds = new WeakMap<object, string>();
|
|
32
33
|
export function useId(defaultId?: string): string;
|
|
33
34
|
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
34
35
|
export function useId(slot: symbol | undefined): string;
|
|
@@ -44,8 +45,15 @@ export function useId(...args: any[]): string {
|
|
|
44
45
|
let res = useSSRSafeId(value, subSlot(slot, 'ssrId'));
|
|
45
46
|
let cleanupRef = useRef(null, subSlot(slot, 'cleanupToken'));
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
let registeredId = registeredIds.get(cleanupRef);
|
|
49
|
+
if (registry && registeredId !== res) {
|
|
50
|
+
if (registeredId != null) {
|
|
51
|
+
registry.unregister(cleanupRef);
|
|
52
|
+
}
|
|
53
|
+
// oxlint-disable-next-line react/react-compiler
|
|
54
|
+
registry.register(cleanupRef, res, cleanupRef);
|
|
55
|
+
// oxlint-disable-next-line react/react-compiler
|
|
56
|
+
registeredIds.set(cleanupRef, res);
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
if (canUseDOM) {
|
|
@@ -65,6 +73,7 @@ export function useId(...args: any[]): string {
|
|
|
65
73
|
// when it is though, also remove it from the finalization registry.
|
|
66
74
|
if (registry) {
|
|
67
75
|
registry.unregister(cleanupRef);
|
|
76
|
+
registeredIds.delete(cleanupRef);
|
|
68
77
|
}
|
|
69
78
|
idsUpdaterMap.delete(r);
|
|
70
79
|
};
|
|
@@ -28,6 +28,7 @@ export interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'>
|
|
|
28
28
|
* @default 1
|
|
29
29
|
*/
|
|
30
30
|
scrollOffset?: number;
|
|
31
|
+
direction?: 'start' | 'end';
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export function useLoadMoreSentinel(
|
|
@@ -35,7 +36,7 @@ export function useLoadMoreSentinel(
|
|
|
35
36
|
ref: RefObject<HTMLElement | null>,
|
|
36
37
|
slot: symbol | undefined,
|
|
37
38
|
): void {
|
|
38
|
-
let { collection, onLoadMore, scrollOffset = 1 } = props;
|
|
39
|
+
let { collection, onLoadMore, scrollOffset = 1, direction = 'end' } = props;
|
|
39
40
|
|
|
40
41
|
let sentinelObserver = useRef<IntersectionObserver | null>(null, subSlot(slot, 'observer'));
|
|
41
42
|
|
|
@@ -59,9 +60,13 @@ export function useLoadMoreSentinel(
|
|
|
59
60
|
if (ref.current) {
|
|
60
61
|
// Tear down and set up a new IntersectionObserver when the collection changes so that we can properly trigger additional loadMores if there is room for more items
|
|
61
62
|
// Need to do this tear down and set up since using a large rootMargin will mean the observer's callback isn't called even when scrolling the item into view beause its visibility hasn't actually changed
|
|
63
|
+
const margin = 100 * scrollOffset;
|
|
64
|
+
// For direction='start', right/left margins have no affect for vertical scroll containers. We are not supporting reverse horizontal scroll containers for now.
|
|
65
|
+
const rootMargin =
|
|
66
|
+
direction === 'start' ? `${margin}% 0px 0px 0px` : `0px ${margin}% ${margin}% ${margin}%`;
|
|
62
67
|
sentinelObserver.current = new IntersectionObserver(triggerLoadMore, {
|
|
63
68
|
root: getScrollParent(ref?.current) as HTMLElement,
|
|
64
|
-
rootMargin
|
|
69
|
+
rootMargin,
|
|
65
70
|
});
|
|
66
71
|
sentinelObserver.current.observe(ref.current);
|
|
67
72
|
}
|
|
@@ -72,7 +77,7 @@ export function useLoadMoreSentinel(
|
|
|
72
77
|
}
|
|
73
78
|
};
|
|
74
79
|
},
|
|
75
|
-
[collection, ref, scrollOffset],
|
|
80
|
+
[collection, ref, scrollOffset, direction],
|
|
76
81
|
subSlot(slot, 'observe'),
|
|
77
82
|
);
|
|
78
83
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { useEffect, useState } from 'octane';
|
|
6
6
|
|
|
7
7
|
import { getActiveElement, getEventTarget } from './shadowdom/DOMFunctions';
|
|
8
|
-
import { isIOS } from './platform';
|
|
8
|
+
import { isIOS, isWebKit } from './platform';
|
|
9
9
|
import { S, splitSlot, subSlot } from '../internal';
|
|
10
10
|
import { useIsSSR } from '../ssr/SSRProvider';
|
|
11
11
|
import { willOpenKeyboard } from './keyboard';
|
|
@@ -75,7 +75,7 @@ export function useViewportSize(...args: any[]): ViewportSize {
|
|
|
75
75
|
|
|
76
76
|
updateSize(getViewportSize());
|
|
77
77
|
|
|
78
|
-
if (isIOS()) {
|
|
78
|
+
if (isIOS() && isWebKit()) {
|
|
79
79
|
window.addEventListener('blur', onBlur, true);
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -87,7 +87,7 @@ export function useViewportSize(...args: any[]): ViewportSize {
|
|
|
87
87
|
|
|
88
88
|
return () => {
|
|
89
89
|
cancelAnimationFrame(frame);
|
|
90
|
-
if (isIOS()) {
|
|
90
|
+
if (isIOS() && isWebKit()) {
|
|
91
91
|
window.removeEventListener('blur', onBlur, true);
|
|
92
92
|
}
|
|
93
93
|
if (!visualViewport) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** @jsxImportSource octane */
|
|
2
|
+
import { addEvent, getOwnerDocument } from '../utils/domHelpers';
|
|
2
3
|
// Ported from adobe/react-spectrum@1c84a49a1faf50b571c84e00bcf9c60b22ddd03e (packages/react-aria/src/virtualizer/ScrollView.tsx).
|
|
3
4
|
/*
|
|
4
5
|
* Copyright 2020 Adobe. All rights reserved.
|
|
@@ -14,7 +15,11 @@
|
|
|
14
15
|
|
|
15
16
|
// @ts-ignore
|
|
16
17
|
import { flushSync } from 'octane';
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
getEventTarget,
|
|
20
|
+
getPropagationTargets,
|
|
21
|
+
nodeContains,
|
|
22
|
+
} from '../utils/shadowdom/DOMFunctions';
|
|
18
23
|
import { getScrollLeft } from './utils';
|
|
19
24
|
import { Point, Rect, Size } from '../upstream-exports/react-stately/useVirtualizerState';
|
|
20
25
|
import React, {
|
|
@@ -221,9 +226,13 @@ export function useScrollView(
|
|
|
221
226
|
|
|
222
227
|
// Attach a document-level capturing scroll listener so we can account for scrollable ancestors.
|
|
223
228
|
useEffect(() => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
229
|
+
return addEvent(
|
|
230
|
+
getPropagationTargets(ref.current, getOwnerDocument(ref.current)),
|
|
231
|
+
'scroll',
|
|
232
|
+
onScroll,
|
|
233
|
+
true,
|
|
234
|
+
);
|
|
235
|
+
}, [onScroll, ref]);
|
|
227
236
|
|
|
228
237
|
useEffect(() => {
|
|
229
238
|
return () => {
|
|
@@ -24,10 +24,12 @@ interface VirtualizerItemProps extends Omit<VirtualizerItemOptions, 'ref'> {
|
|
|
24
24
|
style?: CSSProperties;
|
|
25
25
|
className?: string;
|
|
26
26
|
children: ReactNode;
|
|
27
|
+
shouldObserveItemSize?: boolean;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export function VirtualizerItem(props: VirtualizerItemProps): JSX.Element {
|
|
30
|
-
let { style, className, layoutInfo, virtualizer, parent, children } =
|
|
31
|
+
let { style, className, layoutInfo, virtualizer, parent, shouldObserveItemSize, children } =
|
|
32
|
+
props;
|
|
31
33
|
let { direction } = useLocale();
|
|
32
34
|
let ref = useRef<HTMLDivElement | null>(null);
|
|
33
35
|
useVirtualizerItem({
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource octane */
|
|
2
|
+
import { isElementVisible } from '../utils/isElementVisible';
|
|
3
|
+
import { useEffectEvent } from '../utils/useEffectEvent';
|
|
2
4
|
// Ported from adobe/react-spectrum@1c84a49a1faf50b571c84e00bcf9c60b22ddd03e (packages/react-aria/src/virtualizer/useVirtualizerItem.ts).
|
|
3
5
|
/*
|
|
4
6
|
* Copyright 2020 Adobe. All rights reserved.
|
|
@@ -14,7 +16,7 @@
|
|
|
14
16
|
|
|
15
17
|
import { Key, RefObject } from '@react-types/shared';
|
|
16
18
|
import { LayoutInfo, Size } from '../upstream-exports/react-stately/useVirtualizerState';
|
|
17
|
-
import { useCallback } from '../compat/react';
|
|
19
|
+
import { useCallback, useEffect } from '../compat/react';
|
|
18
20
|
import { useLayoutEffect } from '../utils/useLayoutEffect';
|
|
19
21
|
|
|
20
22
|
interface IVirtualizer {
|
|
@@ -25,25 +27,63 @@ export interface VirtualizerItemOptions {
|
|
|
25
27
|
layoutInfo: LayoutInfo | null;
|
|
26
28
|
virtualizer: IVirtualizer;
|
|
27
29
|
ref: RefObject<HTMLElement | null>;
|
|
30
|
+
shouldObserveItemSize?: boolean;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export function useVirtualizerItem(options: VirtualizerItemOptions): { updateSize: () => void } {
|
|
31
|
-
let { layoutInfo, virtualizer, ref } = options;
|
|
34
|
+
let { layoutInfo, virtualizer, ref, shouldObserveItemSize } = options;
|
|
32
35
|
let key = layoutInfo?.key;
|
|
33
36
|
|
|
34
37
|
let updateSize = useCallback(() => {
|
|
35
38
|
if (key != null && ref.current) {
|
|
39
|
+
if (!isElementVisible(ref.current)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
36
42
|
let size = getSize(ref.current);
|
|
37
43
|
virtualizer.updateItemSize(key, size);
|
|
38
44
|
}
|
|
39
45
|
}, [virtualizer, key, ref]);
|
|
40
46
|
|
|
47
|
+
let updateSizeEvent = useEffectEvent(updateSize);
|
|
41
48
|
useLayoutEffect(() => {
|
|
42
49
|
if (layoutInfo?.estimatedSize) {
|
|
43
|
-
|
|
50
|
+
updateSizeEvent();
|
|
44
51
|
}
|
|
45
52
|
});
|
|
46
53
|
|
|
54
|
+
// TODO: Consider using a MutationObserver in addition to ResizeObserver to detect
|
|
55
|
+
// when inner DOM structure changes cause an item's height to change.
|
|
56
|
+
// The current ResizeObserver only observes direct children,
|
|
57
|
+
// so mutations deeper in the tree won't trigger a remeasure, leading to stale cached heights and overlapping items.
|
|
58
|
+
// useResizeObserver observes one element via ref, but the wrapper height is fixed by layout
|
|
59
|
+
// and won't change when content grows. Observe direct children instead, then remeasure the
|
|
60
|
+
// wrapper in updateSize.
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!shouldObserveItemSize) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let el = ref.current;
|
|
67
|
+
if (!el || typeof ResizeObserver === 'undefined') {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let resizeObserver = new ResizeObserver((entries) => {
|
|
72
|
+
if (!entries.length) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
updateSizeEvent();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
for (let child of el.children) {
|
|
79
|
+
resizeObserver.observe(child);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
resizeObserver.disconnect();
|
|
84
|
+
};
|
|
85
|
+
}, [shouldObserveItemSize, ref, key]);
|
|
86
|
+
|
|
47
87
|
return { updateSize };
|
|
48
88
|
}
|
|
49
89
|
|