@cloudscape-design/components 3.0.494 → 3.0.496
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/alert/styles.css.js +25 -25
- package/alert/styles.scoped.css +45 -51
- package/alert/styles.selectors.js +25 -25
- package/anchor-navigation/styles.css.js +8 -8
- package/anchor-navigation/styles.scoped.css +21 -24
- package/anchor-navigation/styles.selectors.js +8 -8
- package/annotation-context/annotation/styles.css.js +24 -24
- package/annotation-context/annotation/styles.scoped.css +32 -35
- package/annotation-context/annotation/styles.selectors.js +24 -24
- package/app-layout/visual-refresh/styles.css.js +80 -80
- package/app-layout/visual-refresh/styles.scoped.css +175 -181
- package/app-layout/visual-refresh/styles.selectors.js +80 -80
- package/attribute-editor/styles.css.js +14 -14
- package/attribute-editor/styles.scoped.css +27 -30
- package/attribute-editor/styles.selectors.js +14 -14
- package/badge/styles.css.js +5 -5
- package/badge/styles.scoped.css +8 -11
- package/badge/styles.selectors.js +5 -5
- package/breadcrumb-group/styles.css.js +7 -7
- package/breadcrumb-group/styles.scoped.css +18 -24
- package/breadcrumb-group/styles.selectors.js +7 -7
- package/button/styles.css.js +20 -20
- package/button/styles.scoped.css +154 -157
- package/button/styles.selectors.js +20 -20
- package/button-dropdown/mobile-expandable-group/styles.css.js +5 -5
- package/button-dropdown/mobile-expandable-group/styles.scoped.css +8 -11
- package/button-dropdown/mobile-expandable-group/styles.selectors.js +5 -5
- package/calendar/styles.css.js +18 -18
- package/calendar/styles.scoped.css +41 -44
- package/calendar/styles.selectors.js +18 -18
- package/cards/styles.css.js +39 -39
- package/cards/styles.scoped.css +52 -55
- package/cards/styles.selectors.js +39 -39
- package/checkbox/styles.css.js +3 -3
- package/checkbox/styles.scoped.css +8 -11
- package/checkbox/styles.selectors.js +3 -3
- package/code-editor/styles.css.js +32 -32
- package/code-editor/styles.scoped.css +132 -135
- package/code-editor/styles.selectors.js +32 -32
- package/collection-preferences/content-display/styles.css.js +11 -11
- package/collection-preferences/content-display/styles.scoped.css +20 -23
- package/collection-preferences/content-display/styles.selectors.js +11 -11
- package/collection-preferences/styles.css.js +37 -37
- package/collection-preferences/styles.scoped.css +47 -50
- package/collection-preferences/styles.selectors.js +37 -37
- package/column-layout/styles.css.js +13 -13
- package/column-layout/styles.scoped.css +46 -49
- package/column-layout/styles.selectors.js +13 -13
- package/container/styles.css.js +29 -29
- package/container/styles.scoped.css +55 -58
- package/container/styles.selectors.js +29 -29
- package/date-picker/styles.css.js +7 -7
- package/date-picker/styles.scoped.css +12 -15
- package/date-picker/styles.selectors.js +7 -7
- package/date-range-picker/styles.css.js +38 -38
- package/date-range-picker/styles.scoped.css +49 -52
- package/date-range-picker/styles.selectors.js +38 -38
- package/drawer/styles.css.js +3 -3
- package/drawer/styles.scoped.css +11 -14
- package/drawer/styles.selectors.js +3 -3
- package/expandable-section/styles.css.js +32 -32
- package/expandable-section/styles.scoped.css +65 -68
- package/expandable-section/styles.selectors.js +32 -32
- package/flashbar/styles.css.js +47 -47
- package/flashbar/styles.scoped.css +149 -152
- package/flashbar/styles.selectors.js +47 -47
- package/form/styles.css.js +9 -9
- package/form/styles.scoped.css +11 -14
- package/form/styles.selectors.js +9 -9
- package/form-field/styles.css.js +19 -19
- package/form-field/styles.scoped.css +32 -35
- package/form-field/styles.selectors.js +19 -19
- package/grid/styles.css.js +53 -53
- package/grid/styles.scoped.css +57 -60
- package/grid/styles.selectors.js +53 -53
- package/header/styles.css.js +34 -34
- package/header/styles.scoped.css +53 -56
- package/header/styles.selectors.js +34 -34
- package/help-panel/styles.css.js +4 -4
- package/help-panel/styles.scoped.css +66 -69
- package/help-panel/styles.selectors.js +4 -4
- package/input/styles.css.js +12 -12
- package/input/styles.scoped.css +33 -36
- package/input/styles.selectors.js +12 -12
- package/internal/components/button-trigger/styles.css.js +10 -10
- package/internal/components/button-trigger/styles.scoped.css +27 -30
- package/internal/components/button-trigger/styles.selectors.js +10 -10
- package/internal/components/chart-filter/styles.css.js +3 -3
- package/internal/components/chart-filter/styles.scoped.css +6 -9
- package/internal/components/chart-filter/styles.selectors.js +3 -3
- package/internal/components/chart-legend/styles.css.js +6 -6
- package/internal/components/chart-legend/styles.scoped.css +18 -21
- package/internal/components/chart-legend/styles.selectors.js +6 -6
- package/internal/components/chart-popover/styles.css.js +3 -3
- package/internal/components/chart-popover/styles.scoped.css +6 -9
- package/internal/components/chart-popover/styles.selectors.js +3 -3
- package/internal/components/chart-series-details/styles.css.js +20 -20
- package/internal/components/chart-series-details/styles.scoped.css +42 -51
- package/internal/components/chart-series-details/styles.selectors.js +20 -20
- package/internal/components/chart-series-marker/styles.css.js +5 -5
- package/internal/components/chart-series-marker/styles.scoped.css +10 -13
- package/internal/components/chart-series-marker/styles.selectors.js +5 -5
- package/internal/components/chart-wrapper/styles.css.js +9 -9
- package/internal/components/chart-wrapper/styles.scoped.css +12 -15
- package/internal/components/chart-wrapper/styles.selectors.js +9 -9
- package/internal/components/dropdown/styles.css.js +20 -20
- package/internal/components/dropdown/styles.scoped.css +38 -41
- package/internal/components/dropdown/styles.selectors.js +20 -20
- package/internal/components/dropdown-footer/styles.css.js +3 -3
- package/internal/components/dropdown-footer/styles.scoped.css +6 -9
- package/internal/components/dropdown-footer/styles.selectors.js +3 -3
- package/internal/components/dropdown-status/styles.css.js +2 -2
- package/internal/components/dropdown-status/styles.scoped.css +5 -8
- package/internal/components/dropdown-status/styles.selectors.js +2 -2
- package/internal/components/focus-lock/utils.d.ts +1 -0
- package/internal/components/focus-lock/utils.d.ts.map +1 -1
- package/internal/components/focus-lock/utils.js +4 -3
- package/internal/components/focus-lock/utils.js.map +1 -1
- package/internal/components/menu-dropdown/styles.css.js +7 -7
- package/internal/components/menu-dropdown/styles.scoped.css +16 -19
- package/internal/components/menu-dropdown/styles.selectors.js +7 -7
- package/internal/components/option/styles.css.js +17 -17
- package/internal/components/option/styles.scoped.css +32 -35
- package/internal/components/option/styles.selectors.js +17 -17
- package/internal/components/options-list/styles.css.js +2 -2
- package/internal/components/options-list/styles.scoped.css +5 -8
- package/internal/components/options-list/styles.selectors.js +2 -2
- package/internal/components/token-list/styles.css.js +9 -9
- package/internal/components/token-list/styles.scoped.css +23 -26
- package/internal/components/token-list/styles.selectors.js +9 -9
- package/internal/context/single-tab-stop-navigation-context.d.ts +9 -4
- package/internal/context/single-tab-stop-navigation-context.d.ts.map +1 -1
- package/internal/context/single-tab-stop-navigation-context.js +15 -5
- package/internal/context/single-tab-stop-navigation-context.js.map +1 -1
- package/internal/environment.js +1 -1
- package/internal/environment.json +1 -1
- package/internal/manifest.json +1 -1
- package/internal/utils/scrollable-containers.d.ts +2 -1
- package/internal/utils/scrollable-containers.d.ts.map +1 -1
- package/internal/utils/scrollable-containers.js +11 -2
- package/internal/utils/scrollable-containers.js.map +1 -1
- package/link/styles.css.js +20 -20
- package/link/styles.scoped.css +74 -77
- package/link/styles.selectors.js +20 -20
- package/modal/styles.css.js +23 -23
- package/modal/styles.scoped.css +44 -50
- package/modal/styles.selectors.js +23 -23
- package/multiselect/styles.css.js +2 -2
- package/multiselect/styles.scoped.css +5 -8
- package/multiselect/styles.selectors.js +2 -2
- package/package.json +1 -1
- package/pagination/styles.css.js +9 -9
- package/pagination/styles.scoped.css +26 -29
- package/pagination/styles.selectors.js +9 -9
- package/popover/styles.css.js +50 -50
- package/popover/styles.scoped.css +72 -81
- package/popover/styles.selectors.js +50 -50
- package/popover/use-popover-position.d.ts.map +1 -1
- package/popover/use-popover-position.js +4 -2
- package/popover/use-popover-position.js.map +1 -1
- package/progress-bar/styles.css.js +18 -18
- package/progress-bar/styles.scoped.css +35 -38
- package/progress-bar/styles.selectors.js +18 -18
- package/property-filter/styles.css.js +31 -31
- package/property-filter/styles.scoped.css +36 -39
- package/property-filter/styles.selectors.js +31 -31
- package/radio-group/styles.css.js +9 -9
- package/radio-group/styles.scoped.css +18 -21
- package/radio-group/styles.selectors.js +9 -9
- package/segmented-control/styles.css.js +14 -14
- package/segmented-control/styles.scoped.css +36 -39
- package/segmented-control/styles.selectors.js +14 -14
- package/select/styles.css.js +1 -1
- package/select/styles.scoped.css +4 -7
- package/select/styles.selectors.js +1 -1
- package/side-navigation/styles.css.js +28 -28
- package/side-navigation/styles.scoped.css +41 -44
- package/side-navigation/styles.selectors.js +28 -28
- package/split-panel/styles.css.js +55 -55
- package/split-panel/styles.scoped.css +78 -81
- package/split-panel/styles.selectors.js +55 -55
- package/table/resizer/styles.css.js +8 -8
- package/table/resizer/styles.scoped.css +17 -20
- package/table/resizer/styles.selectors.js +8 -8
- package/table/table-role/grid-navigation.d.ts.map +1 -1
- package/table/table-role/grid-navigation.js +73 -41
- package/table/table-role/grid-navigation.js.map +1 -1
- package/table/table-role/utils.d.ts +1 -16
- package/table/table-role/utils.d.ts.map +1 -1
- package/table/table-role/utils.js +0 -53
- package/table/table-role/utils.js.map +1 -1
- package/tabs/styles.css.js +21 -21
- package/tabs/styles.scoped.css +42 -45
- package/tabs/styles.selectors.js +21 -21
- package/text-content/styles.css.js +1 -1
- package/text-content/styles.scoped.css +63 -66
- package/text-content/styles.selectors.js +1 -1
- package/text-filter/styles.css.js +3 -3
- package/text-filter/styles.scoped.css +6 -9
- package/text-filter/styles.selectors.js +3 -3
- package/textarea/styles.css.js +4 -4
- package/textarea/styles.scoped.css +15 -18
- package/textarea/styles.selectors.js +4 -4
- package/tiles/styles.css.js +29 -29
- package/tiles/styles.scoped.css +76 -82
- package/tiles/styles.selectors.js +29 -29
- package/toggle/styles.css.js +8 -8
- package/toggle/styles.scoped.css +16 -19
- package/toggle/styles.selectors.js +8 -8
- package/token-group/styles.css.js +8 -8
- package/token-group/styles.scoped.css +19 -22
- package/token-group/styles.selectors.js +8 -8
- package/top-navigation/1.0-beta/styles.css.js +25 -25
- package/top-navigation/1.0-beta/styles.scoped.css +45 -48
- package/top-navigation/1.0-beta/styles.selectors.js +25 -25
- package/top-navigation/styles.css.js +47 -47
- package/top-navigation/styles.scoped.css +75 -84
- package/top-navigation/styles.selectors.js +47 -47
- package/tutorial-panel/components/tutorial-detail-view/styles.css.js +20 -20
- package/tutorial-panel/components/tutorial-detail-view/styles.scoped.css +24 -27
- package/tutorial-panel/components/tutorial-detail-view/styles.selectors.js +20 -20
- package/tutorial-panel/components/tutorial-list/styles.css.js +18 -18
- package/tutorial-panel/components/tutorial-list/styles.scoped.css +36 -45
- package/tutorial-panel/components/tutorial-list/styles.selectors.js +18 -18
- package/tutorial-panel/styles.css.js +1 -1
- package/tutorial-panel/styles.scoped.css +4 -7
- package/tutorial-panel/styles.selectors.js +1 -1
- package/wizard/styles.css.js +31 -31
- package/wizard/styles.scoped.css +65 -68
- package/wizard/styles.selectors.js +31 -31
|
@@ -90,13 +90,13 @@ surrounding text. (WCAG F73) https://www.w3.org/WAI/WCAG21/Techniques/failures/F
|
|
|
90
90
|
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
91
91
|
SPDX-License-Identifier: Apache-2.0
|
|
92
92
|
*/
|
|
93
|
-
.awsui_resize-
|
|
93
|
+
.awsui_resize-active_x7peu_5w5bo_93:not(#\9):not(.awsui_resize-active-with-focus_x7peu_5w5bo_93) * {
|
|
94
94
|
cursor: col-resize;
|
|
95
95
|
-webkit-user-select: none;
|
|
96
96
|
user-select: none;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
th:not(#\9):not(:last-child) > .
|
|
99
|
+
th:not(#\9):not(:last-child) > .awsui_divider_x7peu_5w5bo_98 {
|
|
100
100
|
position: absolute;
|
|
101
101
|
outline: none;
|
|
102
102
|
pointer-events: none;
|
|
@@ -109,26 +109,26 @@ th:not(#\9):not(:last-child) > .awsui_divider_x7peu_1n0ne_98 {
|
|
|
109
109
|
border-left: var(--border-item-width-yel47s, 2px) solid var(--color-border-divider-interactive-default-byy830, #7d8998);
|
|
110
110
|
box-sizing: border-box;
|
|
111
111
|
}
|
|
112
|
-
th:not(#\9):not(:last-child) > .awsui_divider-
|
|
112
|
+
th:not(#\9):not(:last-child) > .awsui_divider-disabled_x7peu_5w5bo_111 {
|
|
113
113
|
border-left-color: var(--color-border-divider-default-j74lyz, #b6bec9);
|
|
114
114
|
}
|
|
115
|
-
th:not(#\9):not(:last-child) > .awsui_divider-
|
|
115
|
+
th:not(#\9):not(:last-child) > .awsui_divider-active_x7peu_5w5bo_114 {
|
|
116
116
|
border-left: 2px solid var(--color-border-divider-active-k4haaf, #000716);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
.
|
|
120
|
-
/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
|
|
119
|
+
.awsui_resizer_x7peu_5w5bo_118:not(#\9) {
|
|
121
120
|
border-collapse: separate;
|
|
122
121
|
border-spacing: 0;
|
|
122
|
+
box-sizing: border-box;
|
|
123
123
|
caption-side: top;
|
|
124
124
|
cursor: auto;
|
|
125
|
-
direction:
|
|
125
|
+
direction: inherit;
|
|
126
126
|
empty-cells: show;
|
|
127
127
|
font-family: serif;
|
|
128
128
|
font-size: medium;
|
|
129
129
|
font-style: normal;
|
|
130
130
|
font-variant: normal;
|
|
131
|
-
font-weight:
|
|
131
|
+
font-weight: 400;
|
|
132
132
|
font-stretch: normal;
|
|
133
133
|
line-height: normal;
|
|
134
134
|
-webkit-hyphens: none;
|
|
@@ -137,15 +137,12 @@ th:not(#\9):not(:last-child) > .awsui_divider-active_x7peu_1n0ne_114 {
|
|
|
137
137
|
list-style: disc outside none;
|
|
138
138
|
tab-size: 8;
|
|
139
139
|
text-align: left;
|
|
140
|
-
text-align-last: auto;
|
|
141
140
|
text-indent: 0;
|
|
142
141
|
text-shadow: none;
|
|
143
142
|
text-transform: none;
|
|
144
143
|
visibility: visible;
|
|
145
144
|
white-space: normal;
|
|
146
|
-
widows: 2;
|
|
147
145
|
word-spacing: normal;
|
|
148
|
-
box-sizing: border-box;
|
|
149
146
|
font-size: var(--font-size-body-m-x4okxb, 14px);
|
|
150
147
|
line-height: var(--line-height-body-m-30ar75, 20px);
|
|
151
148
|
color: var(--color-text-body-default-at06ol, #000716);
|
|
@@ -163,29 +160,29 @@ th:not(#\9):not(:last-child) > .awsui_divider-active_x7peu_1n0ne_114 {
|
|
|
163
160
|
width: var(--space-l-t419sm, 20px);
|
|
164
161
|
z-index: 10;
|
|
165
162
|
}
|
|
166
|
-
.
|
|
163
|
+
.awsui_resizer_x7peu_5w5bo_118:not(#\9):focus {
|
|
167
164
|
outline: none;
|
|
168
165
|
text-decoration: none;
|
|
169
166
|
}
|
|
170
|
-
.awsui_resize-
|
|
167
|
+
.awsui_resize-active_x7peu_5w5bo_93 .awsui_resizer_x7peu_5w5bo_118:not(#\9) {
|
|
171
168
|
pointer-events: none;
|
|
172
169
|
}
|
|
173
|
-
th:not(#\9):last-child > .
|
|
170
|
+
th:not(#\9):last-child > .awsui_resizer_x7peu_5w5bo_118 {
|
|
174
171
|
width: calc(var(--space-l-t419sm, 20px) / 2);
|
|
175
172
|
right: 0;
|
|
176
173
|
}
|
|
177
|
-
.
|
|
174
|
+
.awsui_resizer_x7peu_5w5bo_118:not(#\9):hover + .awsui_divider_x7peu_5w5bo_98 {
|
|
178
175
|
border-left: 2px solid var(--color-border-divider-active-k4haaf, #000716);
|
|
179
176
|
}
|
|
180
|
-
body[data-awsui-focus-visible=true] .
|
|
177
|
+
body[data-awsui-focus-visible=true] .awsui_resizer_x7peu_5w5bo_118.awsui_has-focus_x7peu_5w5bo_175:not(#\9) {
|
|
181
178
|
position: relative;
|
|
182
179
|
position: absolute;
|
|
183
180
|
}
|
|
184
|
-
body[data-awsui-focus-visible=true] .
|
|
181
|
+
body[data-awsui-focus-visible=true] .awsui_resizer_x7peu_5w5bo_118.awsui_has-focus_x7peu_5w5bo_175:not(#\9) {
|
|
185
182
|
outline: 2px dotted transparent;
|
|
186
183
|
outline-offset: calc(calc(var(--space-table-header-focus-outline-gutter-7js4en, 0px) - 2px) - 1px);
|
|
187
184
|
}
|
|
188
|
-
body[data-awsui-focus-visible=true] .
|
|
185
|
+
body[data-awsui-focus-visible=true] .awsui_resizer_x7peu_5w5bo_118.awsui_has-focus_x7peu_5w5bo_175:not(#\9)::before {
|
|
189
186
|
content: " ";
|
|
190
187
|
display: block;
|
|
191
188
|
position: absolute;
|
|
@@ -197,7 +194,7 @@ body[data-awsui-focus-visible=true] .awsui_resizer_x7peu_1n0ne_118.awsui_has-foc
|
|
|
197
194
|
box-shadow: 0 0 0 2px var(--color-border-item-focused-b2ntyl, #0972d3);
|
|
198
195
|
}
|
|
199
196
|
|
|
200
|
-
.
|
|
197
|
+
.awsui_tracker_x7peu_5w5bo_195:not(#\9) {
|
|
201
198
|
display: none;
|
|
202
199
|
position: absolute;
|
|
203
200
|
border-left: var(--border-divider-list-width-27y3k5, 1px) dashed var(--color-border-divider-active-k4haaf, #000716);
|
|
@@ -205,6 +202,6 @@ body[data-awsui-focus-visible=true] .awsui_resizer_x7peu_1n0ne_118.awsui_has-foc
|
|
|
205
202
|
top: 0;
|
|
206
203
|
bottom: 0;
|
|
207
204
|
}
|
|
208
|
-
.awsui_resize-
|
|
205
|
+
.awsui_resize-active_x7peu_5w5bo_93 .awsui_tracker_x7peu_5w5bo_195:not(#\9) {
|
|
209
206
|
display: block;
|
|
210
207
|
}
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// es-module interop with Babel and Typescript
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
module.exports.default = {
|
|
5
|
-
"resize-active": "awsui_resize-
|
|
6
|
-
"resize-active-with-focus": "awsui_resize-active-with-
|
|
7
|
-
"divider": "
|
|
8
|
-
"divider-disabled": "awsui_divider-
|
|
9
|
-
"divider-active": "awsui_divider-
|
|
10
|
-
"resizer": "
|
|
11
|
-
"has-focus": "awsui_has-
|
|
12
|
-
"tracker": "
|
|
5
|
+
"resize-active": "awsui_resize-active_x7peu_5w5bo_93",
|
|
6
|
+
"resize-active-with-focus": "awsui_resize-active-with-focus_x7peu_5w5bo_93",
|
|
7
|
+
"divider": "awsui_divider_x7peu_5w5bo_98",
|
|
8
|
+
"divider-disabled": "awsui_divider-disabled_x7peu_5w5bo_111",
|
|
9
|
+
"divider-active": "awsui_divider-active_x7peu_5w5bo_114",
|
|
10
|
+
"resizer": "awsui_resizer_x7peu_5w5bo_118",
|
|
11
|
+
"has-focus": "awsui_has-focus_x7peu_5w5bo_175",
|
|
12
|
+
"tracker": "awsui_tracker_x7peu_5w5bo_195"
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-navigation.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"grid-navigation.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":";AAMA,OAAO,EAAe,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAWhE;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,eAoC/G"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import React from 'react';
|
|
3
4
|
import { useEffect, useMemo } from 'react';
|
|
4
|
-
import { defaultIsSuppressed,
|
|
5
|
+
import { defaultIsSuppressed, findTableRowByAriaRowIndex, findTableRowCellByAriaColIndex } from './utils';
|
|
5
6
|
import { KeyCode } from '../../internal/keycode';
|
|
6
7
|
import { useStableCallback } from '@cloudscape-design/component-toolkit/internal';
|
|
7
|
-
import React from 'react';
|
|
8
8
|
import { nodeBelongs } from '../../internal/utils/node-belongs';
|
|
9
|
+
import { getAllFocusables } from '../../internal/components/focus-lock/utils';
|
|
10
|
+
import { SingleTabStopNavigationContext, } from '../../internal/context/single-tab-stop-navigation-context';
|
|
9
11
|
/**
|
|
10
12
|
* Makes table navigable with keyboard commands.
|
|
11
13
|
* See grid-navigation.md
|
|
@@ -31,7 +33,10 @@ export function GridNavigationProvider({ keyboardNavigation, pageSize, getTable,
|
|
|
31
33
|
gridNavigation.refresh();
|
|
32
34
|
}
|
|
33
35
|
});
|
|
34
|
-
return React.createElement(
|
|
36
|
+
return (React.createElement(SingleTabStopNavigationContext.Provider, { value: {
|
|
37
|
+
navigationActive: keyboardNavigation,
|
|
38
|
+
registerFocusable: gridNavigation.registerFocusable,
|
|
39
|
+
} }, children));
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
42
|
* This helper encapsulates the grid navigation behaviors which are:
|
|
@@ -46,6 +51,19 @@ class GridNavigationProcessor {
|
|
|
46
51
|
this._table = null;
|
|
47
52
|
// State
|
|
48
53
|
this.focusedCell = null;
|
|
54
|
+
this.focusables = new Set();
|
|
55
|
+
this.focusHandlers = new Map();
|
|
56
|
+
this.focusTarget = null;
|
|
57
|
+
this.registerFocusable = (focusable, changeHandler) => {
|
|
58
|
+
this.focusables.add(focusable);
|
|
59
|
+
this.focusHandlers.set(focusable, changeHandler);
|
|
60
|
+
changeHandler(this.focusTarget, this.isSuppressed(focusable.current));
|
|
61
|
+
return () => this.unregisterFocusable(focusable);
|
|
62
|
+
};
|
|
63
|
+
this.unregisterFocusable = (focusable) => {
|
|
64
|
+
this.focusables.delete(focusable);
|
|
65
|
+
this.focusHandlers.delete(focusable);
|
|
66
|
+
};
|
|
49
67
|
this.onFocusin = (event) => {
|
|
50
68
|
var _a;
|
|
51
69
|
if (!(event.target instanceof HTMLElement)) {
|
|
@@ -56,11 +74,11 @@ class GridNavigationProcessor {
|
|
|
56
74
|
return;
|
|
57
75
|
}
|
|
58
76
|
this.focusedCell = cell;
|
|
59
|
-
this.
|
|
77
|
+
this.updateFocusTarget();
|
|
60
78
|
// Focusing on cell is not eligible when it contains focusable elements in the content.
|
|
61
79
|
// If content focusables are available - move the focus to the first one.
|
|
62
80
|
if (cell.element === cell.cellElement) {
|
|
63
|
-
(_a =
|
|
81
|
+
(_a = this.getFocusablesFrom(cell.cellElement)[0]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
64
82
|
}
|
|
65
83
|
};
|
|
66
84
|
this.onFocusout = () => {
|
|
@@ -91,8 +109,7 @@ class GridNavigationProcessor {
|
|
|
91
109
|
const from = this.focusedCell;
|
|
92
110
|
const minExtreme = Number.NEGATIVE_INFINITY;
|
|
93
111
|
const maxExtreme = Number.POSITIVE_INFINITY;
|
|
94
|
-
|
|
95
|
-
if (this.isSuppressed(from.element)) {
|
|
112
|
+
if (this.isSuppressed(document.activeElement) || !this.isRegistered(document.activeElement)) {
|
|
96
113
|
return;
|
|
97
114
|
}
|
|
98
115
|
switch (key) {
|
|
@@ -130,18 +147,27 @@ class GridNavigationProcessor {
|
|
|
130
147
|
return;
|
|
131
148
|
}
|
|
132
149
|
};
|
|
150
|
+
this.getRegisteredElements = () => {
|
|
151
|
+
const registeredElements = new Set();
|
|
152
|
+
for (const focusable of this.focusables) {
|
|
153
|
+
if (focusable.current) {
|
|
154
|
+
registeredElements.add(focusable.current);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return registeredElements;
|
|
158
|
+
};
|
|
133
159
|
}
|
|
134
160
|
init(table) {
|
|
135
161
|
this._table = table;
|
|
136
162
|
this.table.addEventListener('focusin', this.onFocusin);
|
|
137
163
|
this.table.addEventListener('focusout', this.onFocusout);
|
|
138
164
|
this.table.addEventListener('keydown', this.onKeydown);
|
|
139
|
-
this.
|
|
165
|
+
this.updateFocusTarget();
|
|
140
166
|
this.cleanup = () => {
|
|
141
167
|
this.table.removeEventListener('focusin', this.onFocusin);
|
|
142
168
|
this.table.removeEventListener('focusout', this.onFocusout);
|
|
143
169
|
this.table.removeEventListener('keydown', this.onKeydown);
|
|
144
|
-
|
|
170
|
+
this.focusables.forEach(this.unregisterFocusable);
|
|
145
171
|
};
|
|
146
172
|
}
|
|
147
173
|
cleanup() {
|
|
@@ -151,14 +177,16 @@ class GridNavigationProcessor {
|
|
|
151
177
|
this._pageSize = pageSize;
|
|
152
178
|
}
|
|
153
179
|
refresh() {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (this.
|
|
157
|
-
|
|
180
|
+
// Timeout ensures the newly rendered content elements are registered.
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
if (this._table) {
|
|
183
|
+
// Update focused cell indices in case table rows, columns, or firstIndex change.
|
|
184
|
+
if (this.focusedCell) {
|
|
185
|
+
this.focusedCell = this.findFocusedCell(this.focusedCell.element);
|
|
186
|
+
}
|
|
187
|
+
this.updateFocusTarget();
|
|
158
188
|
}
|
|
159
|
-
|
|
160
|
-
this.ensureSingleFocusable();
|
|
161
|
-
}
|
|
189
|
+
}, 0);
|
|
162
190
|
}
|
|
163
191
|
get pageSize() {
|
|
164
192
|
return this._pageSize;
|
|
@@ -169,36 +197,40 @@ class GridNavigationProcessor {
|
|
|
169
197
|
}
|
|
170
198
|
return this._table;
|
|
171
199
|
}
|
|
172
|
-
isSuppressed(focusedElement) {
|
|
173
|
-
return defaultIsSuppressed(focusedElement);
|
|
174
|
-
}
|
|
175
200
|
moveFocusBy(cell, delta) {
|
|
176
201
|
var _a;
|
|
177
202
|
(_a = this.getNextFocusable(cell, delta)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
178
203
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
204
|
+
updateFocusTarget() {
|
|
205
|
+
this.focusTarget = this.getSingleFocusable();
|
|
206
|
+
this.focusables.forEach(focusable => {
|
|
207
|
+
const element = focusable.current;
|
|
208
|
+
const handler = this.focusHandlers.get(focusable);
|
|
209
|
+
handler(this.focusTarget, this.isSuppressed(element));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
isSuppressed(element) {
|
|
213
|
+
return !element || defaultIsSuppressed(element);
|
|
214
|
+
}
|
|
215
|
+
isRegistered(element) {
|
|
216
|
+
return !element || this.getRegisteredElements().has(element);
|
|
217
|
+
}
|
|
183
218
|
findFocusedCell(focusedElement) {
|
|
184
219
|
var _a, _b;
|
|
185
220
|
const cellElement = focusedElement.closest('td,th');
|
|
186
221
|
const rowElement = cellElement === null || cellElement === void 0 ? void 0 : cellElement.closest('tr');
|
|
187
222
|
if (!cellElement || !rowElement) {
|
|
188
|
-
return
|
|
223
|
+
return this.focusedCell;
|
|
189
224
|
}
|
|
190
225
|
const colIndex = parseInt((_a = cellElement.getAttribute('aria-colindex')) !== null && _a !== void 0 ? _a : '');
|
|
191
226
|
const rowIndex = parseInt((_b = rowElement.getAttribute('aria-rowindex')) !== null && _b !== void 0 ? _b : '');
|
|
192
227
|
if (isNaN(colIndex) || isNaN(rowIndex)) {
|
|
193
|
-
return
|
|
228
|
+
return this.focusedCell;
|
|
194
229
|
}
|
|
195
|
-
const cellFocusables =
|
|
230
|
+
const cellFocusables = this.getFocusablesFrom(cellElement);
|
|
196
231
|
const elementIndex = cellFocusables.indexOf(focusedElement);
|
|
197
232
|
return { rowIndex, colIndex, rowElement, cellElement, element: focusedElement, elementIndex };
|
|
198
233
|
}
|
|
199
|
-
/**
|
|
200
|
-
* Finds element to be focused next. The focus can transition between cells or interactive elements inside cells.
|
|
201
|
-
*/
|
|
202
234
|
getNextFocusable(from, delta) {
|
|
203
235
|
var _a;
|
|
204
236
|
// Find next row to move focus into (can be null if the top/bottom is reached).
|
|
@@ -208,7 +240,7 @@ class GridNavigationProcessor {
|
|
|
208
240
|
return null;
|
|
209
241
|
}
|
|
210
242
|
// Return next interactive cell content element if available.
|
|
211
|
-
const cellFocusables =
|
|
243
|
+
const cellFocusables = this.getFocusablesFrom(from.cellElement);
|
|
212
244
|
const nextElementIndex = from.elementIndex + delta.x;
|
|
213
245
|
if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {
|
|
214
246
|
return cellFocusables[nextElementIndex];
|
|
@@ -224,27 +256,27 @@ class GridNavigationProcessor {
|
|
|
224
256
|
return null;
|
|
225
257
|
}
|
|
226
258
|
// Return cell interactive content or the cell itself.
|
|
227
|
-
const targetCellFocusables =
|
|
259
|
+
const targetCellFocusables = this.getFocusablesFrom(targetCell);
|
|
228
260
|
const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;
|
|
229
261
|
const focusTarget = (_a = targetCellFocusables[focusIndex]) !== null && _a !== void 0 ? _a : targetCell;
|
|
230
262
|
return focusTarget;
|
|
231
263
|
}
|
|
232
|
-
|
|
233
|
-
* Makes the cell element, the first interactive element or the first cell of the table user-focusable.
|
|
234
|
-
*/
|
|
235
|
-
ensureSingleFocusable() {
|
|
264
|
+
getSingleFocusable() {
|
|
236
265
|
var _a;
|
|
237
|
-
const
|
|
238
|
-
muteElementFocusables(this.table, cellSuppressed);
|
|
266
|
+
const cell = this.focusedCell;
|
|
239
267
|
const firstTableCell = this.table.querySelector('td,th');
|
|
240
268
|
// A single element of the table is made user-focusable.
|
|
241
269
|
// It defaults to the first interactive element of the first cell or the first cell itself otherwise.
|
|
242
|
-
let focusTarget = (_a = (firstTableCell &&
|
|
270
|
+
let focusTarget = (_a = (firstTableCell && this.getFocusablesFrom(firstTableCell)[0])) !== null && _a !== void 0 ? _a : firstTableCell;
|
|
243
271
|
// When a navigation-focused element is present in the table it is used for user-navigation instead.
|
|
244
|
-
if (
|
|
245
|
-
focusTarget = this.getNextFocusable(
|
|
272
|
+
if (cell) {
|
|
273
|
+
focusTarget = this.getNextFocusable(cell, { x: 0, y: 0 });
|
|
246
274
|
}
|
|
247
|
-
|
|
275
|
+
return focusTarget;
|
|
276
|
+
}
|
|
277
|
+
getFocusablesFrom(target) {
|
|
278
|
+
const registeredElements = this.getRegisteredElements();
|
|
279
|
+
return getAllFocusables(target).filter(el => registeredElements.has(el));
|
|
248
280
|
}
|
|
249
281
|
}
|
|
250
282
|
//# sourceMappingURL=grid-navigation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-navigation.js","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useEffect, useMemo } from 'react';\nimport {\n defaultIsSuppressed,\n muteElementFocusables,\n restoreElementFocusables,\n getFirstFocusable,\n getFocusables,\n findTableRowByAriaRowIndex,\n findTableRowCellByAriaColIndex,\n setTabIndex,\n} from './utils';\nimport { FocusedCell, GridNavigationProps } from './interfaces';\nimport { KeyCode } from '../../internal/keycode';\nimport { useStableCallback } from '@cloudscape-design/component-toolkit/internal';\nimport React from 'react';\nimport { nodeBelongs } from '../../internal/utils/node-belongs';\n\n/**\n * Makes table navigable with keyboard commands.\n * See grid-navigation.md\n */\nexport function GridNavigationProvider({ keyboardNavigation, pageSize, getTable, children }: GridNavigationProps) {\n const gridNavigation = useMemo(() => new GridNavigationProcessor(), []);\n\n const getTableStable = useStableCallback(getTable);\n\n // Initialize the processor with the table container assuming it is mounted synchronously and only once.\n useEffect(() => {\n if (keyboardNavigation) {\n const table = getTableStable();\n table && gridNavigation.init(table);\n }\n return () => gridNavigation.cleanup();\n }, [keyboardNavigation, gridNavigation, getTableStable]);\n\n // Notify the processor of the props change.\n useEffect(() => {\n gridNavigation.update({ pageSize });\n }, [gridNavigation, pageSize]);\n\n // Notify the processor of the new render.\n useEffect(() => {\n if (keyboardNavigation) {\n gridNavigation.refresh();\n }\n });\n\n return <>{children}</>;\n}\n\n/**\n * This helper encapsulates the grid navigation behaviors which are:\n * 1. Responding to keyboard commands and moving the focus accordingly;\n * 2. Muting table interactive elements for only one to be user-focusable at a time;\n * 3. Suppressing the above behaviors when focusing an element inside a dialog or when instructed explicitly.\n */\nclass GridNavigationProcessor {\n // Props\n private _pageSize = 0;\n private _table: null | HTMLTableElement = null;\n\n // State\n private focusedCell: null | FocusedCell = null;\n\n public init(table: HTMLTableElement) {\n this._table = table;\n\n this.table.addEventListener('focusin', this.onFocusin);\n this.table.addEventListener('focusout', this.onFocusout);\n this.table.addEventListener('keydown', this.onKeydown);\n\n this.ensureSingleFocusable();\n\n this.cleanup = () => {\n this.table.removeEventListener('focusin', this.onFocusin);\n this.table.removeEventListener('focusout', this.onFocusout);\n this.table.removeEventListener('keydown', this.onKeydown);\n\n restoreElementFocusables(this.table);\n };\n }\n\n public cleanup() {\n // Do nothing before initialized.\n }\n\n public update({ pageSize }: { pageSize: number }) {\n this._pageSize = pageSize;\n }\n\n public refresh() {\n if (this._table) {\n // Update focused cell indices in case table rows, columns, or firstIndex change.\n if (this.focusedCell) {\n this.focusedCell = this.findFocusedCell(this.focusedCell.element);\n }\n\n // Ensure newly added elements if any are muted.\n this.ensureSingleFocusable();\n }\n }\n\n private get pageSize() {\n return this._pageSize;\n }\n\n private get table(): HTMLTableElement {\n if (!this._table) {\n throw new Error('Invariant violation: GridNavigationProcessor is used before initialization.');\n }\n return this._table;\n }\n\n private isSuppressed(focusedElement: HTMLElement): boolean {\n return defaultIsSuppressed(focusedElement);\n }\n\n private onFocusin = (event: FocusEvent) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const cell = this.findFocusedCell(event.target);\n if (!cell) {\n return;\n }\n\n this.focusedCell = cell;\n\n this.ensureSingleFocusable();\n\n // Focusing on cell is not eligible when it contains focusable elements in the content.\n // If content focusables are available - move the focus to the first one.\n if (cell.element === cell.cellElement) {\n getFirstFocusable(cell.cellElement)?.focus();\n }\n };\n\n private onFocusout = () => {\n // When focus leaves the cell and the cell no longer belong to the table it indicates the focused element has been unmounted.\n // In that case the focus needs to be restored on the same coordinates.\n setTimeout(() => {\n if (this.focusedCell && !nodeBelongs(this.table, this.focusedCell.element)) {\n this.moveFocusBy(this.focusedCell, { x: 0, y: 0 });\n }\n }, 0);\n };\n\n private onKeydown = (event: KeyboardEvent) => {\n if (!this.focusedCell) {\n return;\n }\n\n const ctrlKey = event.ctrlKey ? 1 : 0;\n const altKey = event.altKey ? 1 : 0;\n const shiftKey = event.shiftKey ? 1 : 0;\n const metaKey = event.metaKey ? 1 : 0;\n const numModifiersPressed = ctrlKey + altKey + shiftKey + metaKey;\n\n let key = event.keyCode;\n if (numModifiersPressed === 1 && event.ctrlKey) {\n key = -key;\n } else if (numModifiersPressed) {\n return;\n }\n\n const from = this.focusedCell;\n const minExtreme = Number.NEGATIVE_INFINITY;\n const maxExtreme = Number.POSITIVE_INFINITY;\n\n // Do not intercept any keys when the navigation is suppressed.\n if (this.isSuppressed(from.element)) {\n return;\n }\n\n switch (key) {\n case KeyCode.up:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -1, x: 0 });\n\n case KeyCode.down:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 1, x: 0 });\n\n case KeyCode.left:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: -1 });\n\n case KeyCode.right:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: 1 });\n\n case KeyCode.pageUp:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -this.pageSize, x: 0 });\n\n case KeyCode.pageDown:\n event.preventDefault();\n return this.moveFocusBy(from, { y: this.pageSize, x: 0 });\n\n case KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: minExtreme });\n\n case KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: maxExtreme });\n\n case -KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: minExtreme, x: minExtreme });\n\n case -KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: maxExtreme, x: maxExtreme });\n\n default:\n return;\n }\n };\n\n private moveFocusBy(cell: FocusedCell, delta: { x: number; y: number }) {\n this.getNextFocusable(cell, delta)?.focus();\n }\n\n /**\n * Finds focused cell props corresponding the focused element inside the table.\n * The function relies on ARIA colindex/rowindex attributes being correctly applied.\n */\n private findFocusedCell(focusedElement: HTMLElement): null | FocusedCell {\n const cellElement = focusedElement.closest('td,th') as null | HTMLTableCellElement;\n const rowElement = cellElement?.closest('tr');\n\n if (!cellElement || !rowElement) {\n return null;\n }\n\n const colIndex = parseInt(cellElement.getAttribute('aria-colindex') ?? '');\n const rowIndex = parseInt(rowElement.getAttribute('aria-rowindex') ?? '');\n if (isNaN(colIndex) || isNaN(rowIndex)) {\n return null;\n }\n\n const cellFocusables = getFocusables(cellElement);\n const elementIndex = cellFocusables.indexOf(focusedElement);\n\n return { rowIndex, colIndex, rowElement, cellElement, element: focusedElement, elementIndex };\n }\n\n /**\n * Finds element to be focused next. The focus can transition between cells or interactive elements inside cells.\n */\n private getNextFocusable(from: FocusedCell, delta: { y: number; x: number }) {\n // Find next row to move focus into (can be null if the top/bottom is reached).\n const targetAriaRowIndex = from.rowIndex + delta.y;\n const targetRow = findTableRowByAriaRowIndex(this.table, targetAriaRowIndex, delta.y);\n if (!targetRow) {\n return null;\n }\n\n // Return next interactive cell content element if available.\n const cellFocusables = getFocusables(from.cellElement);\n const nextElementIndex = from.elementIndex + delta.x;\n if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {\n return cellFocusables[nextElementIndex];\n }\n\n // Find next cell to focus or move focus into (can be null if the left/right edge is reached).\n const targetAriaColIndex = from.colIndex + delta.x;\n const targetCell = findTableRowCellByAriaColIndex(targetRow, targetAriaColIndex, delta.x);\n if (!targetCell) {\n return null;\n }\n\n // When target cell matches the current cell it means we reached the left or right boundary.\n if (targetCell === from.cellElement && delta.x !== 0) {\n return null;\n }\n\n // Return cell interactive content or the cell itself.\n const targetCellFocusables = getFocusables(targetCell);\n const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;\n const focusTarget = targetCellFocusables[focusIndex] ?? targetCell;\n return focusTarget;\n }\n\n /**\n * Makes the cell element, the first interactive element or the first cell of the table user-focusable.\n */\n private ensureSingleFocusable() {\n const cellSuppressed = this.focusedCell ? this.isSuppressed(this.focusedCell.element) : false;\n muteElementFocusables(this.table, cellSuppressed);\n\n const firstTableCell = this.table.querySelector('td,th') as null | HTMLTableCellElement;\n\n // A single element of the table is made user-focusable.\n // It defaults to the first interactive element of the first cell or the first cell itself otherwise.\n let focusTarget: null | HTMLElement = (firstTableCell && getFocusables(firstTableCell)[0]) ?? firstTableCell;\n\n // When a navigation-focused element is present in the table it is used for user-navigation instead.\n if (this.focusedCell) {\n focusTarget = this.getNextFocusable(this.focusedCell, { x: 0, y: 0 });\n }\n\n setTabIndex(focusTarget, 0);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"grid-navigation.js","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport React from 'react';\nimport { useEffect, useMemo } from 'react';\nimport { defaultIsSuppressed, findTableRowByAriaRowIndex, findTableRowCellByAriaColIndex } from './utils';\nimport { FocusedCell, GridNavigationProps } from './interfaces';\nimport { KeyCode } from '../../internal/keycode';\nimport { useStableCallback } from '@cloudscape-design/component-toolkit/internal';\nimport { nodeBelongs } from '../../internal/utils/node-belongs';\nimport { getAllFocusables } from '../../internal/components/focus-lock/utils';\nimport {\n SingleTabStopNavigationContext,\n FocusableDefinition,\n FocusableChangeHandler,\n} from '../../internal/context/single-tab-stop-navigation-context';\n\n/**\n * Makes table navigable with keyboard commands.\n * See grid-navigation.md\n */\nexport function GridNavigationProvider({ keyboardNavigation, pageSize, getTable, children }: GridNavigationProps) {\n const gridNavigation = useMemo(() => new GridNavigationProcessor(), []);\n\n const getTableStable = useStableCallback(getTable);\n\n // Initialize the processor with the table container assuming it is mounted synchronously and only once.\n useEffect(() => {\n if (keyboardNavigation) {\n const table = getTableStable();\n table && gridNavigation.init(table);\n }\n return () => gridNavigation.cleanup();\n }, [keyboardNavigation, gridNavigation, getTableStable]);\n\n // Notify the processor of the props change.\n useEffect(() => {\n gridNavigation.update({ pageSize });\n }, [gridNavigation, pageSize]);\n\n // Notify the processor of the new render.\n useEffect(() => {\n if (keyboardNavigation) {\n gridNavigation.refresh();\n }\n });\n\n return (\n <SingleTabStopNavigationContext.Provider\n value={{\n navigationActive: keyboardNavigation,\n registerFocusable: gridNavigation.registerFocusable,\n }}\n >\n {children}\n </SingleTabStopNavigationContext.Provider>\n );\n}\n\n/**\n * This helper encapsulates the grid navigation behaviors which are:\n * 1. Responding to keyboard commands and moving the focus accordingly;\n * 2. Muting table interactive elements for only one to be user-focusable at a time;\n * 3. Suppressing the above behaviors when focusing an element inside a dialog or when instructed explicitly.\n */\nclass GridNavigationProcessor {\n // Props\n private _pageSize = 0;\n private _table: null | HTMLTableElement = null;\n\n // State\n private focusedCell: null | FocusedCell = null;\n private focusables = new Set<FocusableDefinition>();\n private focusHandlers = new Map<FocusableDefinition, FocusableChangeHandler>();\n private focusTarget: null | Element = null;\n\n public init(table: HTMLTableElement) {\n this._table = table;\n\n this.table.addEventListener('focusin', this.onFocusin);\n this.table.addEventListener('focusout', this.onFocusout);\n this.table.addEventListener('keydown', this.onKeydown);\n\n this.updateFocusTarget();\n\n this.cleanup = () => {\n this.table.removeEventListener('focusin', this.onFocusin);\n this.table.removeEventListener('focusout', this.onFocusout);\n this.table.removeEventListener('keydown', this.onKeydown);\n this.focusables.forEach(this.unregisterFocusable);\n };\n }\n\n public cleanup() {\n // Do nothing before initialized.\n }\n\n public update({ pageSize }: { pageSize: number }) {\n this._pageSize = pageSize;\n }\n\n public refresh() {\n // Timeout ensures the newly rendered content elements are registered.\n setTimeout(() => {\n if (this._table) {\n // Update focused cell indices in case table rows, columns, or firstIndex change.\n if (this.focusedCell) {\n this.focusedCell = this.findFocusedCell(this.focusedCell.element);\n }\n this.updateFocusTarget();\n }\n }, 0);\n }\n\n public registerFocusable = (focusable: FocusableDefinition, changeHandler: FocusableChangeHandler) => {\n this.focusables.add(focusable);\n this.focusHandlers.set(focusable, changeHandler);\n changeHandler(this.focusTarget, this.isSuppressed(focusable.current));\n return () => this.unregisterFocusable(focusable);\n };\n\n public unregisterFocusable = (focusable: FocusableDefinition) => {\n this.focusables.delete(focusable);\n this.focusHandlers.delete(focusable);\n };\n\n private get pageSize() {\n return this._pageSize;\n }\n\n private get table(): HTMLTableElement {\n if (!this._table) {\n throw new Error('Invariant violation: GridNavigationProcessor is used before initialization.');\n }\n return this._table;\n }\n\n private onFocusin = (event: FocusEvent) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const cell = this.findFocusedCell(event.target);\n if (!cell) {\n return;\n }\n\n this.focusedCell = cell;\n\n this.updateFocusTarget();\n\n // Focusing on cell is not eligible when it contains focusable elements in the content.\n // If content focusables are available - move the focus to the first one.\n if (cell.element === cell.cellElement) {\n this.getFocusablesFrom(cell.cellElement)[0]?.focus();\n }\n };\n\n private onFocusout = () => {\n // When focus leaves the cell and the cell no longer belong to the table it indicates the focused element has been unmounted.\n // In that case the focus needs to be restored on the same coordinates.\n setTimeout(() => {\n if (this.focusedCell && !nodeBelongs(this.table, this.focusedCell.element)) {\n this.moveFocusBy(this.focusedCell, { x: 0, y: 0 });\n }\n }, 0);\n };\n\n private onKeydown = (event: KeyboardEvent) => {\n if (!this.focusedCell) {\n return;\n }\n\n const ctrlKey = event.ctrlKey ? 1 : 0;\n const altKey = event.altKey ? 1 : 0;\n const shiftKey = event.shiftKey ? 1 : 0;\n const metaKey = event.metaKey ? 1 : 0;\n const numModifiersPressed = ctrlKey + altKey + shiftKey + metaKey;\n\n let key = event.keyCode;\n if (numModifiersPressed === 1 && event.ctrlKey) {\n key = -key;\n } else if (numModifiersPressed) {\n return;\n }\n\n const from = this.focusedCell;\n const minExtreme = Number.NEGATIVE_INFINITY;\n const maxExtreme = Number.POSITIVE_INFINITY;\n\n if (this.isSuppressed(document.activeElement) || !this.isRegistered(document.activeElement)) {\n return;\n }\n\n switch (key) {\n case KeyCode.up:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -1, x: 0 });\n\n case KeyCode.down:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 1, x: 0 });\n\n case KeyCode.left:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: -1 });\n\n case KeyCode.right:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: 1 });\n\n case KeyCode.pageUp:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -this.pageSize, x: 0 });\n\n case KeyCode.pageDown:\n event.preventDefault();\n return this.moveFocusBy(from, { y: this.pageSize, x: 0 });\n\n case KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: minExtreme });\n\n case KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: maxExtreme });\n\n case -KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: minExtreme, x: minExtreme });\n\n case -KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: maxExtreme, x: maxExtreme });\n\n default:\n return;\n }\n };\n\n private moveFocusBy(cell: FocusedCell, delta: { x: number; y: number }) {\n this.getNextFocusable(cell, delta)?.focus();\n }\n\n private updateFocusTarget() {\n this.focusTarget = this.getSingleFocusable();\n this.focusables.forEach(focusable => {\n const element = focusable.current;\n const handler = this.focusHandlers.get(focusable)!;\n handler(this.focusTarget, this.isSuppressed(element));\n });\n }\n\n private isSuppressed(element: null | Element) {\n return !element || defaultIsSuppressed(element);\n }\n\n private isRegistered(element: null | Element) {\n return !element || this.getRegisteredElements().has(element);\n }\n\n private getRegisteredElements = (): Set<Element> => {\n const registeredElements = new Set<Element>();\n for (const focusable of this.focusables) {\n if (focusable.current) {\n registeredElements.add(focusable.current);\n }\n }\n return registeredElements;\n };\n\n private findFocusedCell(focusedElement: HTMLElement): null | FocusedCell {\n const cellElement = focusedElement.closest('td,th') as null | HTMLTableCellElement;\n const rowElement = cellElement?.closest('tr');\n\n if (!cellElement || !rowElement) {\n return this.focusedCell;\n }\n\n const colIndex = parseInt(cellElement.getAttribute('aria-colindex') ?? '');\n const rowIndex = parseInt(rowElement.getAttribute('aria-rowindex') ?? '');\n if (isNaN(colIndex) || isNaN(rowIndex)) {\n return this.focusedCell;\n }\n\n const cellFocusables = this.getFocusablesFrom(cellElement);\n const elementIndex = cellFocusables.indexOf(focusedElement);\n\n return { rowIndex, colIndex, rowElement, cellElement, element: focusedElement, elementIndex };\n }\n\n private getNextFocusable(from: FocusedCell, delta: { y: number; x: number }) {\n // Find next row to move focus into (can be null if the top/bottom is reached).\n const targetAriaRowIndex = from.rowIndex + delta.y;\n const targetRow = findTableRowByAriaRowIndex(this.table, targetAriaRowIndex, delta.y);\n if (!targetRow) {\n return null;\n }\n\n // Return next interactive cell content element if available.\n const cellFocusables = this.getFocusablesFrom(from.cellElement);\n const nextElementIndex = from.elementIndex + delta.x;\n if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {\n return cellFocusables[nextElementIndex];\n }\n\n // Find next cell to focus or move focus into (can be null if the left/right edge is reached).\n const targetAriaColIndex = from.colIndex + delta.x;\n const targetCell = findTableRowCellByAriaColIndex(targetRow, targetAriaColIndex, delta.x);\n if (!targetCell) {\n return null;\n }\n\n // When target cell matches the current cell it means we reached the left or right boundary.\n if (targetCell === from.cellElement && delta.x !== 0) {\n return null;\n }\n\n // Return cell interactive content or the cell itself.\n const targetCellFocusables = this.getFocusablesFrom(targetCell);\n const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;\n const focusTarget = targetCellFocusables[focusIndex] ?? targetCell;\n return focusTarget;\n }\n\n private getSingleFocusable() {\n const cell = this.focusedCell;\n const firstTableCell = this.table.querySelector('td,th') as null | HTMLTableCellElement;\n\n // A single element of the table is made user-focusable.\n // It defaults to the first interactive element of the first cell or the first cell itself otherwise.\n let focusTarget: null | HTMLElement =\n (firstTableCell && this.getFocusablesFrom(firstTableCell)[0]) ?? firstTableCell;\n\n // When a navigation-focused element is present in the table it is used for user-navigation instead.\n if (cell) {\n focusTarget = this.getNextFocusable(cell, { x: 0, y: 0 });\n }\n\n return focusTarget;\n }\n\n private getFocusablesFrom(target: HTMLElement) {\n const registeredElements = this.getRegisteredElements();\n return getAllFocusables(target).filter(el => registeredElements.has(el));\n }\n}\n"]}
|
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.
|
|
3
|
-
*/
|
|
4
|
-
export declare function muteElementFocusables(element: HTMLElement, suppressed: boolean): void;
|
|
5
|
-
/**
|
|
6
|
-
* This cleanup code ensures all cells are no longer focusable but the interactive elements are.
|
|
7
|
-
* Currently there are no use cases for it as we don't expect the navigation to be used conditionally.
|
|
8
|
-
*/
|
|
9
|
-
export declare function restoreElementFocusables(element: HTMLTableElement): void;
|
|
10
1
|
/**
|
|
11
2
|
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.
|
|
12
3
|
* This is used to suppress navigation for interactive content without a need to use a custom suppression check.
|
|
13
4
|
*/
|
|
14
|
-
export declare function defaultIsSuppressed(target:
|
|
15
|
-
/**
|
|
16
|
-
* Returns actually focusable or pseudo-focusable elements to find navigation targets.
|
|
17
|
-
*/
|
|
18
|
-
export declare function getFocusables(element: HTMLElement): HTMLElement[];
|
|
19
|
-
export declare function getFirstFocusable(element: HTMLElement): HTMLElement | null;
|
|
5
|
+
export declare function defaultIsSuppressed(target: Element): boolean;
|
|
20
6
|
/**
|
|
21
7
|
* Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.
|
|
22
8
|
*/
|
|
@@ -25,5 +11,4 @@ export declare function findTableRowByAriaRowIndex(table: HTMLTableElement, targ
|
|
|
25
11
|
* Finds the closest column to the targetAriaColIndex+delta in the direction of delta.
|
|
26
12
|
*/
|
|
27
13
|
export declare function findTableRowCellByAriaColIndex(tableRow: HTMLTableRowElement, targetAriaColIndex: number, delta: number): HTMLTableCellElement | null;
|
|
28
|
-
export declare function setTabIndex(element: null | HTMLElement, tabIndex: number): void;
|
|
29
14
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,WAiBlD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,8BAqB5G;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,mBAAmB,EAC7B,kBAAkB,EAAE,MAAM,EAC1B,KAAK,EAAE,MAAM,+BAsBd"}
|
|
@@ -1,44 +1,5 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { getFocusables as getActualFocusables } from '../../internal/components/focus-lock/utils';
|
|
4
|
-
// For the grid to have a single Tab stop all interactive element indices are updated to be -999.
|
|
5
|
-
// The elements having tab index -999 are eligible for keyboard navigation but not for Tab navigation.
|
|
6
|
-
const PSEUDO_FOCUSABLE_TAB_INDEX = -999;
|
|
7
|
-
const FOCUSABLES_SELECTOR = `[tabIndex="0"],[tabIndex="${PSEUDO_FOCUSABLE_TAB_INDEX}"]`;
|
|
8
|
-
/**
|
|
9
|
-
* Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.
|
|
10
|
-
*/
|
|
11
|
-
export function muteElementFocusables(element, suppressed) {
|
|
12
|
-
// When grid navigation is suppressed all interactive elements and all cells focus is unmuted to unblock Tab navigation.
|
|
13
|
-
// Leaving the interactive widget using Tab navigation moves the focus to the current or adjacent cell and un-suppresses
|
|
14
|
-
// the navigation when implemented correctly.
|
|
15
|
-
if (suppressed) {
|
|
16
|
-
for (const focusable of getFocusables(element)) {
|
|
17
|
-
setTabIndex(focusable, 0);
|
|
18
|
-
}
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
// Assigning pseudo-focusable tab index to all cells and all interactive elements makes them focusable with grid navigation.
|
|
22
|
-
for (const focusable of getActualFocusables(element)) {
|
|
23
|
-
if (focusable !== document.activeElement) {
|
|
24
|
-
setTabIndex(focusable, PSEUDO_FOCUSABLE_TAB_INDEX);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* This cleanup code ensures all cells are no longer focusable but the interactive elements are.
|
|
30
|
-
* Currently there are no use cases for it as we don't expect the navigation to be used conditionally.
|
|
31
|
-
*/
|
|
32
|
-
export function restoreElementFocusables(element) {
|
|
33
|
-
for (const focusable of getFocusables(element)) {
|
|
34
|
-
if (focusable instanceof HTMLTableCellElement) {
|
|
35
|
-
setTabIndex(focusable, -1);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
setTabIndex(focusable, 0);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
3
|
/**
|
|
43
4
|
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.
|
|
44
5
|
* This is used to suppress navigation for interactive content without a need to use a custom suppression check.
|
|
@@ -59,15 +20,6 @@ export function defaultIsSuppressed(target) {
|
|
|
59
20
|
}
|
|
60
21
|
return false;
|
|
61
22
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Returns actually focusable or pseudo-focusable elements to find navigation targets.
|
|
64
|
-
*/
|
|
65
|
-
export function getFocusables(element) {
|
|
66
|
-
return Array.from(element.querySelectorAll(FOCUSABLES_SELECTOR));
|
|
67
|
-
}
|
|
68
|
-
export function getFirstFocusable(element) {
|
|
69
|
-
return element.querySelector(FOCUSABLES_SELECTOR);
|
|
70
|
-
}
|
|
71
23
|
/**
|
|
72
24
|
* Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.
|
|
73
25
|
*/
|
|
@@ -118,9 +70,4 @@ export function findTableRowCellByAriaColIndex(tableRow, targetAriaColIndex, del
|
|
|
118
70
|
}
|
|
119
71
|
return targetCell;
|
|
120
72
|
}
|
|
121
|
-
export function setTabIndex(element, tabIndex) {
|
|
122
|
-
if (element && element.tabIndex !== tabIndex) {
|
|
123
|
-
element.tabIndex = tabIndex;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
73
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,IAAI,OAAO,GAAmB,MAAM,CAAC;IACrC,OAAO,OAAO,EAAE;QACd,0GAA0G;QAC1G,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC9C,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,EAAE;YACxC,OAAO,KAAK,CAAC;SACd;QACD,IACE,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,QAAQ;YACzC,OAAO,CAAC,YAAY,CAAC,sCAAsC,CAAC,KAAK,MAAM,EACvE;YACA,OAAO,IAAI,CAAC;SACb;QACD,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;KACjC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAuB,EAAE,kBAA0B,EAAE,KAAa;;IAC3G,IAAI,SAAS,GAA+B,IAAI,CAAC;IACjD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC5E,IAAI,KAAK,GAAG,CAAC,EAAE;QACb,WAAW,CAAC,OAAO,EAAE,CAAC;KACvB;IACD,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE;QACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAA,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,mCAAI,EAAE,CAAC,CAAC;QACvE,SAAS,GAAG,OAA8B,CAAC;QAE3C,IAAI,QAAQ,KAAK,kBAAkB,EAAE;YACnC,MAAM;SACP;QACD,IAAI,KAAK,IAAI,CAAC,IAAI,QAAQ,GAAG,kBAAkB,EAAE;YAC/C,MAAM;SACP;QACD,IAAI,KAAK,GAAG,CAAC,IAAI,QAAQ,GAAG,kBAAkB,EAAE;YAC9C,MAAM;SACP;KACF;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,8BAA8B,CAC5C,QAA6B,EAC7B,kBAA0B,EAC1B,KAAa;;IAEb,IAAI,UAAU,GAAgC,IAAI,CAAC;IACnD,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,qCAAqC,CAAC,CAAC,CAAC;IAClG,IAAI,KAAK,GAAG,CAAC,EAAE;QACb,YAAY,CAAC,OAAO,EAAE,CAAC;KACxB;IACD,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE;QAClC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAA,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,mCAAI,EAAE,CAAC,CAAC;QAC1E,UAAU,GAAG,OAA+B,CAAC;QAE7C,IAAI,WAAW,KAAK,kBAAkB,EAAE;YACtC,MAAM;SACP;QACD,IAAI,KAAK,IAAI,CAAC,IAAI,WAAW,GAAG,kBAAkB,EAAE;YAClD,MAAM;SACP;QACD,IAAI,KAAK,GAAG,CAAC,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACjD,MAAM;SACP;KACF;IACD,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.\n * This is used to suppress navigation for interactive content without a need to use a custom suppression check.\n */\nexport function defaultIsSuppressed(target: Element) {\n let current: null | Element = target;\n while (current) {\n // Stop checking for parents upon reaching the cell element as the function only aims at the cell content.\n const tagName = current.tagName.toLowerCase();\n if (tagName === 'td' || tagName === 'th') {\n return false;\n }\n if (\n current.getAttribute('role') === 'dialog' ||\n current.getAttribute('data-awsui-table-suppress-navigation') === 'true'\n ) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n}\n\n/**\n * Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.\n */\nexport function findTableRowByAriaRowIndex(table: HTMLTableElement, targetAriaRowIndex: number, delta: number) {\n let targetRow: null | HTMLTableRowElement = null;\n const rowElements = Array.from(table.querySelectorAll('tr[aria-rowindex]'));\n if (delta < 0) {\n rowElements.reverse();\n }\n for (const element of rowElements) {\n const rowIndex = parseInt(element.getAttribute('aria-rowindex') ?? '');\n targetRow = element as HTMLTableRowElement;\n\n if (rowIndex === targetAriaRowIndex) {\n break;\n }\n if (delta >= 0 && rowIndex > targetAriaRowIndex) {\n break;\n }\n if (delta < 0 && rowIndex < targetAriaRowIndex) {\n break;\n }\n }\n return targetRow;\n}\n\n/**\n * Finds the closest column to the targetAriaColIndex+delta in the direction of delta.\n */\nexport function findTableRowCellByAriaColIndex(\n tableRow: HTMLTableRowElement,\n targetAriaColIndex: number,\n delta: number\n) {\n let targetCell: null | HTMLTableCellElement = null;\n const cellElements = Array.from(tableRow.querySelectorAll('td[aria-colindex],th[aria-colindex]'));\n if (delta < 0) {\n cellElements.reverse();\n }\n for (const element of cellElements) {\n const columnIndex = parseInt(element.getAttribute('aria-colindex') ?? '');\n targetCell = element as HTMLTableCellElement;\n\n if (columnIndex === targetAriaColIndex) {\n break;\n }\n if (delta >= 0 && columnIndex > targetAriaColIndex) {\n break;\n }\n if (delta < 0 && columnIndex < targetAriaColIndex) {\n break;\n }\n }\n return targetCell;\n}\n"]}
|