@rc-component/util 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/Dom/focus.d.ts +11 -7
- package/es/Dom/focus.js +89 -38
- package/es/getScrollBarSize.d.ts +2 -4
- package/lib/Dom/focus.d.ts +11 -7
- package/lib/Dom/focus.js +91 -42
- package/lib/getScrollBarSize.d.ts +2 -4
- package/package.json +1 -1
package/es/Dom/focus.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
export declare function getFocusNodeList(node: HTMLElement, includePositive?: boolean): HTMLElement[];
|
|
2
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
3
|
-
export declare function saveLastFocusNode(): void;
|
|
4
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
5
|
-
export declare function clearLastFocusNode(): void;
|
|
6
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
7
|
-
export declare function backLastFocusNode(): void;
|
|
8
|
-
export declare function limitTabRange(node: HTMLElement, e: KeyboardEvent): void;
|
|
9
2
|
export interface InputFocusOptions extends FocusOptions {
|
|
10
3
|
cursor?: 'start' | 'end' | 'all';
|
|
11
4
|
}
|
|
@@ -13,3 +6,14 @@ export interface InputFocusOptions extends FocusOptions {
|
|
|
13
6
|
* Focus element and set cursor position for input/textarea elements.
|
|
14
7
|
*/
|
|
15
8
|
export declare function triggerFocus(element?: HTMLElement, option?: InputFocusOptions): void;
|
|
9
|
+
/**
|
|
10
|
+
* Lock focus in the element.
|
|
11
|
+
* It will force back to the first focusable element when focus leaves the element.
|
|
12
|
+
*/
|
|
13
|
+
export declare function lockFocus(element: HTMLElement): VoidFunction;
|
|
14
|
+
/**
|
|
15
|
+
* Lock focus within an element.
|
|
16
|
+
* When locked, focus will be restricted to focusable elements within the specified element.
|
|
17
|
+
* If multiple elements are locked, only the last locked element will be effective.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useLockFocus(lock: boolean, getElement: () => HTMLElement | null): void;
|
package/es/Dom/focus.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
1
2
|
import isVisible from "./isVisible";
|
|
2
3
|
function focusable(node, includePositive = false) {
|
|
3
4
|
if (isVisible(node)) {
|
|
@@ -39,44 +40,6 @@ export function getFocusNodeList(node, includePositive = false) {
|
|
|
39
40
|
}
|
|
40
41
|
return res;
|
|
41
42
|
}
|
|
42
|
-
let lastFocusElement = null;
|
|
43
|
-
|
|
44
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
45
|
-
export function saveLastFocusNode() {
|
|
46
|
-
lastFocusElement = document.activeElement;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
50
|
-
export function clearLastFocusNode() {
|
|
51
|
-
lastFocusElement = null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
55
|
-
export function backLastFocusNode() {
|
|
56
|
-
if (lastFocusElement) {
|
|
57
|
-
try {
|
|
58
|
-
// 元素可能已经被移动了
|
|
59
|
-
lastFocusElement.focus();
|
|
60
|
-
|
|
61
|
-
/* eslint-disable no-empty */
|
|
62
|
-
} catch (e) {
|
|
63
|
-
// empty
|
|
64
|
-
}
|
|
65
|
-
/* eslint-enable no-empty */
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
export function limitTabRange(node, e) {
|
|
69
|
-
if (e.keyCode === 9) {
|
|
70
|
-
const tabNodeList = getFocusNodeList(node);
|
|
71
|
-
const lastTabNode = tabNodeList[e.shiftKey ? 0 : tabNodeList.length - 1];
|
|
72
|
-
const leavingTab = lastTabNode === document.activeElement || node === document.activeElement;
|
|
73
|
-
if (leavingTab) {
|
|
74
|
-
const target = tabNodeList[e.shiftKey ? tabNodeList.length - 1 : 0];
|
|
75
|
-
target.focus();
|
|
76
|
-
e.preventDefault();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
43
|
// Used for `rc-input` `rc-textarea` `rc-input-number`
|
|
81
44
|
/**
|
|
82
45
|
* Focus element and set cursor position for input/textarea elements.
|
|
@@ -102,4 +65,92 @@ export function triggerFocus(element, option) {
|
|
|
102
65
|
element.setSelectionRange(0, len);
|
|
103
66
|
}
|
|
104
67
|
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ======================================================
|
|
71
|
+
// == Lock Focus ==
|
|
72
|
+
// ======================================================
|
|
73
|
+
let lastFocusElement = null;
|
|
74
|
+
let focusElements = [];
|
|
75
|
+
function getLastElement() {
|
|
76
|
+
return focusElements[focusElements.length - 1];
|
|
77
|
+
}
|
|
78
|
+
function hasFocus(element) {
|
|
79
|
+
const {
|
|
80
|
+
activeElement
|
|
81
|
+
} = document;
|
|
82
|
+
return element === activeElement || element.contains(activeElement);
|
|
83
|
+
}
|
|
84
|
+
function syncFocus() {
|
|
85
|
+
const lastElement = getLastElement();
|
|
86
|
+
const {
|
|
87
|
+
activeElement
|
|
88
|
+
} = document;
|
|
89
|
+
if (lastElement && !hasFocus(lastElement)) {
|
|
90
|
+
const focusableList = getFocusNodeList(lastElement);
|
|
91
|
+
const matchElement = focusableList.includes(lastFocusElement) ? lastFocusElement : focusableList[0];
|
|
92
|
+
matchElement?.focus();
|
|
93
|
+
} else {
|
|
94
|
+
lastFocusElement = activeElement;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function onWindowKeyDown(e) {
|
|
98
|
+
if (e.key === 'Tab') {
|
|
99
|
+
const {
|
|
100
|
+
activeElement
|
|
101
|
+
} = document;
|
|
102
|
+
const lastElement = getLastElement();
|
|
103
|
+
const focusableList = getFocusNodeList(lastElement);
|
|
104
|
+
const last = focusableList[focusableList.length - 1];
|
|
105
|
+
if (e.shiftKey && activeElement === focusableList[0]) {
|
|
106
|
+
// Tab backward on first focusable element
|
|
107
|
+
lastFocusElement = last;
|
|
108
|
+
} else if (!e.shiftKey && activeElement === last) {
|
|
109
|
+
// Tab forward on last focusable element
|
|
110
|
+
lastFocusElement = focusableList[0];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Lock focus in the element.
|
|
117
|
+
* It will force back to the first focusable element when focus leaves the element.
|
|
118
|
+
*/
|
|
119
|
+
export function lockFocus(element) {
|
|
120
|
+
if (element) {
|
|
121
|
+
// Refresh focus elements
|
|
122
|
+
focusElements = focusElements.filter(ele => ele !== element);
|
|
123
|
+
focusElements.push(element);
|
|
124
|
+
|
|
125
|
+
// Just add event since it will de-duplicate
|
|
126
|
+
window.addEventListener('focusin', syncFocus);
|
|
127
|
+
window.addEventListener('keydown', onWindowKeyDown, true);
|
|
128
|
+
syncFocus();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Always return unregister function
|
|
132
|
+
return () => {
|
|
133
|
+
lastFocusElement = null;
|
|
134
|
+
focusElements = focusElements.filter(ele => ele !== element);
|
|
135
|
+
if (focusElements.length === 0) {
|
|
136
|
+
window.removeEventListener('focusin', syncFocus);
|
|
137
|
+
window.removeEventListener('keydown', onWindowKeyDown, true);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Lock focus within an element.
|
|
144
|
+
* When locked, focus will be restricted to focusable elements within the specified element.
|
|
145
|
+
* If multiple elements are locked, only the last locked element will be effective.
|
|
146
|
+
*/
|
|
147
|
+
export function useLockFocus(lock, getElement) {
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (lock) {
|
|
150
|
+
const element = getElement();
|
|
151
|
+
if (element) {
|
|
152
|
+
return lockFocus(element);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}, [lock]);
|
|
105
156
|
}
|
package/es/getScrollBarSize.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
export default function getScrollBarSize(fresh?: boolean): number;
|
|
2
|
+
export declare function getTargetScrollBarSize(target: HTMLElement): {
|
|
2
3
|
width: number;
|
|
3
4
|
height: number;
|
|
4
5
|
};
|
|
5
|
-
export default function getScrollBarSize(fresh?: boolean): number;
|
|
6
|
-
export declare function getTargetScrollBarSize(target: HTMLElement): ScrollBarSize;
|
|
7
|
-
export {};
|
package/lib/Dom/focus.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
export declare function getFocusNodeList(node: HTMLElement, includePositive?: boolean): HTMLElement[];
|
|
2
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
3
|
-
export declare function saveLastFocusNode(): void;
|
|
4
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
5
|
-
export declare function clearLastFocusNode(): void;
|
|
6
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
7
|
-
export declare function backLastFocusNode(): void;
|
|
8
|
-
export declare function limitTabRange(node: HTMLElement, e: KeyboardEvent): void;
|
|
9
2
|
export interface InputFocusOptions extends FocusOptions {
|
|
10
3
|
cursor?: 'start' | 'end' | 'all';
|
|
11
4
|
}
|
|
@@ -13,3 +6,14 @@ export interface InputFocusOptions extends FocusOptions {
|
|
|
13
6
|
* Focus element and set cursor position for input/textarea elements.
|
|
14
7
|
*/
|
|
15
8
|
export declare function triggerFocus(element?: HTMLElement, option?: InputFocusOptions): void;
|
|
9
|
+
/**
|
|
10
|
+
* Lock focus in the element.
|
|
11
|
+
* It will force back to the first focusable element when focus leaves the element.
|
|
12
|
+
*/
|
|
13
|
+
export declare function lockFocus(element: HTMLElement): VoidFunction;
|
|
14
|
+
/**
|
|
15
|
+
* Lock focus within an element.
|
|
16
|
+
* When locked, focus will be restricted to focusable elements within the specified element.
|
|
17
|
+
* If multiple elements are locked, only the last locked element will be effective.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useLockFocus(lock: boolean, getElement: () => HTMLElement | null): void;
|
package/lib/Dom/focus.js
CHANGED
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.backLastFocusNode = backLastFocusNode;
|
|
7
|
-
exports.clearLastFocusNode = clearLastFocusNode;
|
|
8
6
|
exports.getFocusNodeList = getFocusNodeList;
|
|
9
|
-
exports.
|
|
10
|
-
exports.saveLastFocusNode = saveLastFocusNode;
|
|
7
|
+
exports.lockFocus = lockFocus;
|
|
11
8
|
exports.triggerFocus = triggerFocus;
|
|
9
|
+
exports.useLockFocus = useLockFocus;
|
|
10
|
+
var _react = require("react");
|
|
12
11
|
var _isVisible = _interopRequireDefault(require("./isVisible"));
|
|
13
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
13
|
function focusable(node, includePositive = false) {
|
|
@@ -51,44 +50,6 @@ function getFocusNodeList(node, includePositive = false) {
|
|
|
51
50
|
}
|
|
52
51
|
return res;
|
|
53
52
|
}
|
|
54
|
-
let lastFocusElement = null;
|
|
55
|
-
|
|
56
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
57
|
-
function saveLastFocusNode() {
|
|
58
|
-
lastFocusElement = document.activeElement;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
62
|
-
function clearLastFocusNode() {
|
|
63
|
-
lastFocusElement = null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** @deprecated Do not use since this may failed when used in async */
|
|
67
|
-
function backLastFocusNode() {
|
|
68
|
-
if (lastFocusElement) {
|
|
69
|
-
try {
|
|
70
|
-
// 元素可能已经被移动了
|
|
71
|
-
lastFocusElement.focus();
|
|
72
|
-
|
|
73
|
-
/* eslint-disable no-empty */
|
|
74
|
-
} catch (e) {
|
|
75
|
-
// empty
|
|
76
|
-
}
|
|
77
|
-
/* eslint-enable no-empty */
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function limitTabRange(node, e) {
|
|
81
|
-
if (e.keyCode === 9) {
|
|
82
|
-
const tabNodeList = getFocusNodeList(node);
|
|
83
|
-
const lastTabNode = tabNodeList[e.shiftKey ? 0 : tabNodeList.length - 1];
|
|
84
|
-
const leavingTab = lastTabNode === document.activeElement || node === document.activeElement;
|
|
85
|
-
if (leavingTab) {
|
|
86
|
-
const target = tabNodeList[e.shiftKey ? tabNodeList.length - 1 : 0];
|
|
87
|
-
target.focus();
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
53
|
// Used for `rc-input` `rc-textarea` `rc-input-number`
|
|
93
54
|
/**
|
|
94
55
|
* Focus element and set cursor position for input/textarea elements.
|
|
@@ -114,4 +75,92 @@ function triggerFocus(element, option) {
|
|
|
114
75
|
element.setSelectionRange(0, len);
|
|
115
76
|
}
|
|
116
77
|
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ======================================================
|
|
81
|
+
// == Lock Focus ==
|
|
82
|
+
// ======================================================
|
|
83
|
+
let lastFocusElement = null;
|
|
84
|
+
let focusElements = [];
|
|
85
|
+
function getLastElement() {
|
|
86
|
+
return focusElements[focusElements.length - 1];
|
|
87
|
+
}
|
|
88
|
+
function hasFocus(element) {
|
|
89
|
+
const {
|
|
90
|
+
activeElement
|
|
91
|
+
} = document;
|
|
92
|
+
return element === activeElement || element.contains(activeElement);
|
|
93
|
+
}
|
|
94
|
+
function syncFocus() {
|
|
95
|
+
const lastElement = getLastElement();
|
|
96
|
+
const {
|
|
97
|
+
activeElement
|
|
98
|
+
} = document;
|
|
99
|
+
if (lastElement && !hasFocus(lastElement)) {
|
|
100
|
+
const focusableList = getFocusNodeList(lastElement);
|
|
101
|
+
const matchElement = focusableList.includes(lastFocusElement) ? lastFocusElement : focusableList[0];
|
|
102
|
+
matchElement?.focus();
|
|
103
|
+
} else {
|
|
104
|
+
lastFocusElement = activeElement;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function onWindowKeyDown(e) {
|
|
108
|
+
if (e.key === 'Tab') {
|
|
109
|
+
const {
|
|
110
|
+
activeElement
|
|
111
|
+
} = document;
|
|
112
|
+
const lastElement = getLastElement();
|
|
113
|
+
const focusableList = getFocusNodeList(lastElement);
|
|
114
|
+
const last = focusableList[focusableList.length - 1];
|
|
115
|
+
if (e.shiftKey && activeElement === focusableList[0]) {
|
|
116
|
+
// Tab backward on first focusable element
|
|
117
|
+
lastFocusElement = last;
|
|
118
|
+
} else if (!e.shiftKey && activeElement === last) {
|
|
119
|
+
// Tab forward on last focusable element
|
|
120
|
+
lastFocusElement = focusableList[0];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Lock focus in the element.
|
|
127
|
+
* It will force back to the first focusable element when focus leaves the element.
|
|
128
|
+
*/
|
|
129
|
+
function lockFocus(element) {
|
|
130
|
+
if (element) {
|
|
131
|
+
// Refresh focus elements
|
|
132
|
+
focusElements = focusElements.filter(ele => ele !== element);
|
|
133
|
+
focusElements.push(element);
|
|
134
|
+
|
|
135
|
+
// Just add event since it will de-duplicate
|
|
136
|
+
window.addEventListener('focusin', syncFocus);
|
|
137
|
+
window.addEventListener('keydown', onWindowKeyDown, true);
|
|
138
|
+
syncFocus();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Always return unregister function
|
|
142
|
+
return () => {
|
|
143
|
+
lastFocusElement = null;
|
|
144
|
+
focusElements = focusElements.filter(ele => ele !== element);
|
|
145
|
+
if (focusElements.length === 0) {
|
|
146
|
+
window.removeEventListener('focusin', syncFocus);
|
|
147
|
+
window.removeEventListener('keydown', onWindowKeyDown, true);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Lock focus within an element.
|
|
154
|
+
* When locked, focus will be restricted to focusable elements within the specified element.
|
|
155
|
+
* If multiple elements are locked, only the last locked element will be effective.
|
|
156
|
+
*/
|
|
157
|
+
function useLockFocus(lock, getElement) {
|
|
158
|
+
(0, _react.useEffect)(() => {
|
|
159
|
+
if (lock) {
|
|
160
|
+
const element = getElement();
|
|
161
|
+
if (element) {
|
|
162
|
+
return lockFocus(element);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}, [lock]);
|
|
117
166
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
export default function getScrollBarSize(fresh?: boolean): number;
|
|
2
|
+
export declare function getTargetScrollBarSize(target: HTMLElement): {
|
|
2
3
|
width: number;
|
|
3
4
|
height: number;
|
|
4
5
|
};
|
|
5
|
-
export default function getScrollBarSize(fresh?: boolean): number;
|
|
6
|
-
export declare function getTargetScrollBarSize(target: HTMLElement): ScrollBarSize;
|
|
7
|
-
export {};
|