@primer/react 38.40.0 → 38.40.1-rc.65ba5ef2b
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/CHANGELOG.md +6 -0
- package/dist/FilteredActionList/FilteredActionList.js +3 -1
- package/dist/FilteredActionList/FilteredActionListInput.d.ts +3 -0
- package/dist/FilteredActionList/FilteredActionListInput.js +56 -37
- package/dist/FilteredActionList/useAnnouncements.js +62 -40
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @primer/react
|
|
2
2
|
|
|
3
|
+
## 38.40.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#8413](https://github.com/primer/react/pull/8413) [`d4e30ed`](https://github.com/primer/react/commit/d4e30ed186af6ae781b3adcf83278e0c2001a834) Thanks [@liuliu-dev](https://github.com/liuliu-dev)! - SelectPanel: Announce the filter input label when focus moves into the panel
|
|
8
|
+
|
|
3
9
|
## 38.40.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
|
@@ -96,6 +96,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
96
96
|
}
|
|
97
97
|
}, [activeDescendantRef]);
|
|
98
98
|
const listContainerRefCallback = useCallback((node) => {
|
|
99
|
+
listRef.current = node;
|
|
99
100
|
setListContainerElement(node);
|
|
100
101
|
onListContainerRefChanged === null || onListContainerRefChanged === void 0 || onListContainerRefChanged(node);
|
|
101
102
|
}, [onListContainerRefChanged]);
|
|
@@ -201,7 +202,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
201
202
|
readInputRef,
|
|
202
203
|
usingRovingTabindex
|
|
203
204
|
]);
|
|
204
|
-
useAnnouncements(items,
|
|
205
|
+
const onInputFocus = useAnnouncements(items, listRef, readInputRef, announcementsEnabled, loading, messageText, _PrivateFocusManagement, filterValue);
|
|
205
206
|
useScrollFlash(readScrollContainerRef);
|
|
206
207
|
const handleSelectAllChange = useCallback((e) => {
|
|
207
208
|
if (onSelectAllChange) onSelectAllChange(e.target.checked);
|
|
@@ -302,6 +303,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
302
303
|
children: [
|
|
303
304
|
/*#__PURE__*/ jsx(FilteredActionListInput, {
|
|
304
305
|
inputRef: appliedInputRef,
|
|
306
|
+
onInputFocus,
|
|
305
307
|
value: filterValue,
|
|
306
308
|
onInputChange,
|
|
307
309
|
onInputKeyPress,
|
|
@@ -5,6 +5,7 @@ import React from "react";
|
|
|
5
5
|
interface FilteredActionListInputProps extends Partial<Omit<TextInputProps, 'onChange' | 'onKeyDown'>> {
|
|
6
6
|
inputRef: React.Ref<HTMLInputElement | null>;
|
|
7
7
|
onInputChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
8
|
+
onInputFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
8
9
|
onInputKeyPress?: React.KeyboardEventHandler<HTMLInputElement>;
|
|
9
10
|
onInputKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
|
|
10
11
|
placeholderText?: string;
|
|
@@ -17,6 +18,7 @@ declare function FilteredActionListInput({
|
|
|
17
18
|
inputRef,
|
|
18
19
|
value,
|
|
19
20
|
onInputChange,
|
|
21
|
+
onInputFocus,
|
|
20
22
|
onInputKeyPress,
|
|
21
23
|
onInputKeyDown,
|
|
22
24
|
placeholderText,
|
|
@@ -25,6 +27,7 @@ declare function FilteredActionListInput({
|
|
|
25
27
|
loading,
|
|
26
28
|
fullScreenOnNarrow,
|
|
27
29
|
className,
|
|
30
|
+
onFocus,
|
|
28
31
|
...restTextInputProps
|
|
29
32
|
}: FilteredActionListInputProps): React.JSX.Element;
|
|
30
33
|
//#endregion
|
|
@@ -5,21 +5,23 @@ import { jsx } from "react/jsx-runtime";
|
|
|
5
5
|
import { clsx } from "clsx";
|
|
6
6
|
//#region src/FilteredActionList/FilteredActionListInput.tsx
|
|
7
7
|
function FilteredActionListInput(t0) {
|
|
8
|
-
const $ = c(
|
|
8
|
+
const $ = c(34);
|
|
9
9
|
let className;
|
|
10
10
|
let fullScreenOnNarrow;
|
|
11
11
|
let inputDescriptionTextId;
|
|
12
12
|
let inputRef;
|
|
13
13
|
let listId;
|
|
14
14
|
let loading;
|
|
15
|
+
let onFocus;
|
|
15
16
|
let onInputChange;
|
|
17
|
+
let onInputFocus;
|
|
16
18
|
let onInputKeyDown;
|
|
17
19
|
let onInputKeyPress;
|
|
18
20
|
let placeholderText;
|
|
19
21
|
let restTextInputProps;
|
|
20
22
|
let value;
|
|
21
23
|
if ($[0] !== t0) {
|
|
22
|
-
({inputRef, value, onInputChange, onInputKeyPress, onInputKeyDown, placeholderText, listId, inputDescriptionTextId, loading, fullScreenOnNarrow, className, ...restTextInputProps} = t0);
|
|
24
|
+
({inputRef, value, onInputChange, onInputFocus, onInputKeyPress, onInputKeyDown, placeholderText, listId, inputDescriptionTextId, loading, fullScreenOnNarrow, className, onFocus, ...restTextInputProps} = t0);
|
|
23
25
|
$[0] = t0;
|
|
24
26
|
$[1] = className;
|
|
25
27
|
$[2] = fullScreenOnNarrow;
|
|
@@ -27,12 +29,14 @@ function FilteredActionListInput(t0) {
|
|
|
27
29
|
$[4] = inputRef;
|
|
28
30
|
$[5] = listId;
|
|
29
31
|
$[6] = loading;
|
|
30
|
-
$[7] =
|
|
31
|
-
$[8] =
|
|
32
|
-
$[9] =
|
|
33
|
-
$[10] =
|
|
34
|
-
$[11] =
|
|
35
|
-
$[12] =
|
|
32
|
+
$[7] = onFocus;
|
|
33
|
+
$[8] = onInputChange;
|
|
34
|
+
$[9] = onInputFocus;
|
|
35
|
+
$[10] = onInputKeyDown;
|
|
36
|
+
$[11] = onInputKeyPress;
|
|
37
|
+
$[12] = placeholderText;
|
|
38
|
+
$[13] = restTextInputProps;
|
|
39
|
+
$[14] = value;
|
|
36
40
|
} else {
|
|
37
41
|
className = $[1];
|
|
38
42
|
fullScreenOnNarrow = $[2];
|
|
@@ -40,23 +44,36 @@ function FilteredActionListInput(t0) {
|
|
|
40
44
|
inputRef = $[4];
|
|
41
45
|
listId = $[5];
|
|
42
46
|
loading = $[6];
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
onFocus = $[7];
|
|
48
|
+
onInputChange = $[8];
|
|
49
|
+
onInputFocus = $[9];
|
|
50
|
+
onInputKeyDown = $[10];
|
|
51
|
+
onInputKeyPress = $[11];
|
|
52
|
+
placeholderText = $[12];
|
|
53
|
+
restTextInputProps = $[13];
|
|
54
|
+
value = $[14];
|
|
49
55
|
}
|
|
50
56
|
let t1;
|
|
51
|
-
if ($[
|
|
52
|
-
t1 =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
if ($[15] !== onFocus || $[16] !== onInputFocus) {
|
|
58
|
+
t1 = (event) => {
|
|
59
|
+
var _onInputFocus, _onFocus;
|
|
60
|
+
(_onInputFocus = onInputFocus) === null || _onInputFocus === void 0 || _onInputFocus(event);
|
|
61
|
+
(_onFocus = onFocus) === null || _onFocus === void 0 || _onFocus(event);
|
|
62
|
+
};
|
|
63
|
+
$[15] = onFocus;
|
|
64
|
+
$[16] = onInputFocus;
|
|
65
|
+
$[17] = t1;
|
|
66
|
+
} else t1 = $[17];
|
|
57
67
|
let t2;
|
|
58
|
-
if ($[
|
|
59
|
-
t2 =
|
|
68
|
+
if ($[18] !== className || $[19] !== fullScreenOnNarrow) {
|
|
69
|
+
t2 = clsx(className, { [FilteredActionList_module_css_default.FullScreenTextInput]: fullScreenOnNarrow });
|
|
70
|
+
$[18] = className;
|
|
71
|
+
$[19] = fullScreenOnNarrow;
|
|
72
|
+
$[20] = t2;
|
|
73
|
+
} else t2 = $[20];
|
|
74
|
+
let t3;
|
|
75
|
+
if ($[21] !== inputDescriptionTextId || $[22] !== inputRef || $[23] !== listId || $[24] !== loading || $[25] !== onInputChange || $[26] !== onInputKeyDown || $[27] !== onInputKeyPress || $[28] !== placeholderText || $[29] !== restTextInputProps || $[30] !== t1 || $[31] !== t2 || $[32] !== value) {
|
|
76
|
+
t3 = /*#__PURE__*/ jsx("div", {
|
|
60
77
|
className: FilteredActionList_module_css_default.Header,
|
|
61
78
|
"data-component": "FilteredActionList.Header",
|
|
62
79
|
children: /*#__PURE__*/ jsx(TextInput_default, {
|
|
@@ -66,6 +83,7 @@ function FilteredActionListInput(t0) {
|
|
|
66
83
|
color: "fg.default",
|
|
67
84
|
value,
|
|
68
85
|
onChange: onInputChange,
|
|
86
|
+
onFocus: t1,
|
|
69
87
|
onKeyPress: onInputKeyPress,
|
|
70
88
|
onKeyDown: onInputKeyDown,
|
|
71
89
|
placeholder: placeholderText,
|
|
@@ -77,24 +95,25 @@ function FilteredActionListInput(t0) {
|
|
|
77
95
|
"aria-describedby": inputDescriptionTextId,
|
|
78
96
|
loaderPosition: "leading",
|
|
79
97
|
loading,
|
|
80
|
-
className:
|
|
98
|
+
className: t2,
|
|
81
99
|
...restTextInputProps
|
|
82
100
|
})
|
|
83
101
|
});
|
|
84
|
-
$[
|
|
85
|
-
$[
|
|
86
|
-
$[
|
|
87
|
-
$[
|
|
88
|
-
$[
|
|
89
|
-
$[
|
|
90
|
-
$[
|
|
91
|
-
$[
|
|
92
|
-
$[
|
|
93
|
-
$[
|
|
94
|
-
$[
|
|
95
|
-
$[
|
|
96
|
-
|
|
97
|
-
|
|
102
|
+
$[21] = inputDescriptionTextId;
|
|
103
|
+
$[22] = inputRef;
|
|
104
|
+
$[23] = listId;
|
|
105
|
+
$[24] = loading;
|
|
106
|
+
$[25] = onInputChange;
|
|
107
|
+
$[26] = onInputKeyDown;
|
|
108
|
+
$[27] = onInputKeyPress;
|
|
109
|
+
$[28] = placeholderText;
|
|
110
|
+
$[29] = restTextInputProps;
|
|
111
|
+
$[30] = t1;
|
|
112
|
+
$[31] = t2;
|
|
113
|
+
$[32] = value;
|
|
114
|
+
$[33] = t3;
|
|
115
|
+
} else t3 = $[33];
|
|
116
|
+
return t3;
|
|
98
117
|
}
|
|
99
118
|
//#endregion
|
|
100
119
|
export { FilteredActionListInput };
|
|
@@ -2,12 +2,20 @@ import { useCallback, useEffect, useRef } from "react";
|
|
|
2
2
|
import { announce } from "@primer/live-region-element";
|
|
3
3
|
//#region src/FilteredActionList/useAnnouncements.tsx
|
|
4
4
|
const delayMs = 500;
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
const getInputLabel = (input) => {
|
|
6
|
+
var _input$labels;
|
|
7
|
+
if (!input) return;
|
|
8
|
+
const labelledBy = input.getAttribute("aria-labelledby");
|
|
9
|
+
if (labelledBy) {
|
|
10
|
+
const label = labelledBy.split(/\s+/).map((id) => {
|
|
11
|
+
var _input$ownerDocument$;
|
|
12
|
+
return (_input$ownerDocument$ = input.ownerDocument.getElementById(id)) === null || _input$ownerDocument$ === void 0 ? void 0 : _input$ownerDocument$.textContent.trim();
|
|
13
|
+
}).filter(Boolean).join(" ");
|
|
14
|
+
if (label) return label;
|
|
15
|
+
}
|
|
16
|
+
const ariaLabel = input.getAttribute("aria-label");
|
|
17
|
+
if (ariaLabel) return ariaLabel;
|
|
18
|
+
return Array.from((_input$labels = input.labels) !== null && _input$labels !== void 0 ? _input$labels : []).map((label) => label.textContent.trim()).filter(Boolean).join(" ") || void 0;
|
|
11
19
|
};
|
|
12
20
|
const getItemWithActiveDescendant = (listRef, items) => {
|
|
13
21
|
const listElement = listRef.current;
|
|
@@ -22,52 +30,65 @@ const getItemWithActiveDescendant = (listRef, items) => {
|
|
|
22
30
|
selected: activeItem === null || activeItem === void 0 ? void 0 : activeItem.selected
|
|
23
31
|
};
|
|
24
32
|
};
|
|
25
|
-
const
|
|
33
|
+
const getAnnouncementState = (items, loading, message, filterValue) => JSON.stringify({
|
|
34
|
+
items: items.map((item, index) => {
|
|
35
|
+
var _ref, _item$id;
|
|
36
|
+
return [
|
|
37
|
+
(_ref = (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : item.text) !== null && _ref !== void 0 ? _ref : index,
|
|
38
|
+
item.text,
|
|
39
|
+
item.selected
|
|
40
|
+
];
|
|
41
|
+
}),
|
|
42
|
+
loading,
|
|
43
|
+
message,
|
|
44
|
+
filterValue
|
|
45
|
+
});
|
|
46
|
+
const useAnnouncements = (items, listContainerRef, inputRef, enabled = true, loading = false, message, focusManagement, filterValue) => {
|
|
26
47
|
const usingRovingTabindex = focusManagement === "roving-tabindex";
|
|
27
48
|
const liveRegion = document.querySelector("live-region");
|
|
28
49
|
const selectedItems = items.filter((item) => item.selected).length;
|
|
29
50
|
const announce$1 = useCallback((...args) => {
|
|
30
51
|
if (enabled) return announce(...args);
|
|
31
52
|
}, [enabled]);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
const onInputFocus = useCallback(() => {
|
|
54
|
+
if (usingRovingTabindex) {
|
|
55
|
+
const announcementText = `${items.length} item${items.length > 1 ? "s" : ""} available, ${selectedItems} selected.`;
|
|
56
|
+
announce$1(announcementText, {
|
|
57
|
+
delayMs,
|
|
58
|
+
from: liveRegion ? liveRegion : void 0
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
window.setTimeout(() => {
|
|
63
|
+
const activeItem = getItemWithActiveDescendant(listContainerRef, items);
|
|
64
|
+
if (!activeItem) return;
|
|
65
|
+
const { index, text, selected } = activeItem;
|
|
66
|
+
const inputLabel = getInputLabel(inputRef.current);
|
|
67
|
+
const announcementText = [
|
|
68
|
+
inputLabel ? `${inputLabel}, filter text box and list of items` : "Focus on filter text box and list of items",
|
|
69
|
+
`Focused item: ${text}`,
|
|
70
|
+
`${selected ? "selected" : "not selected"}`,
|
|
71
|
+
`${index + 1} of ${items.length}`
|
|
72
|
+
].join(", ");
|
|
73
|
+
announce$1(announcementText, {
|
|
74
|
+
delayMs,
|
|
75
|
+
from: liveRegion ? liveRegion : void 0
|
|
54
76
|
});
|
|
55
|
-
};
|
|
56
|
-
const inputElement = inputRef.current;
|
|
57
|
-
inputElement === null || inputElement === void 0 || inputElement.addEventListener("focus", focusHandler);
|
|
58
|
-
return () => inputElement === null || inputElement === void 0 ? void 0 : inputElement.removeEventListener("focus", focusHandler);
|
|
77
|
+
});
|
|
59
78
|
}, [
|
|
60
|
-
|
|
79
|
+
announce$1,
|
|
61
80
|
inputRef,
|
|
62
81
|
items,
|
|
82
|
+
listContainerRef,
|
|
63
83
|
liveRegion,
|
|
64
|
-
|
|
65
|
-
usingRovingTabindex
|
|
66
|
-
selectedItems
|
|
84
|
+
selectedItems,
|
|
85
|
+
usingRovingTabindex
|
|
67
86
|
]);
|
|
68
|
-
const
|
|
87
|
+
const announcementState = getAnnouncementState(items, loading, message, filterValue);
|
|
88
|
+
const previousAnnouncementState = useRef(announcementState);
|
|
69
89
|
useEffect(function announceListUpdates() {
|
|
70
|
-
if (
|
|
90
|
+
if (previousAnnouncementState.current === announcementState) return;
|
|
91
|
+
previousAnnouncementState.current = announcementState;
|
|
71
92
|
liveRegion === null || liveRegion === void 0 || liveRegion.clear();
|
|
72
93
|
if (items.length === 0 && !loading) {
|
|
73
94
|
announce$1(`${message === null || message === void 0 ? void 0 : message.title}. ${message === null || message === void 0 ? void 0 : message.description}`, { delayMs });
|
|
@@ -96,7 +117,7 @@ const useAnnouncements = (items, listContainerRef, inputRef, enabled = true, loa
|
|
|
96
117
|
});
|
|
97
118
|
}, [
|
|
98
119
|
announce$1,
|
|
99
|
-
|
|
120
|
+
announcementState,
|
|
100
121
|
items,
|
|
101
122
|
listContainerRef,
|
|
102
123
|
liveRegion,
|
|
@@ -106,6 +127,7 @@ const useAnnouncements = (items, listContainerRef, inputRef, enabled = true, loa
|
|
|
106
127
|
loading,
|
|
107
128
|
selectedItems
|
|
108
129
|
]);
|
|
130
|
+
return onInputFocus;
|
|
109
131
|
};
|
|
110
132
|
//#endregion
|
|
111
133
|
export { useAnnouncements };
|
package/package.json
CHANGED