@instructure/ui-focusable 8.12.0 → 8.12.1-snapshot.3

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/LICENSE.md ADDED
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: The MIT License (MIT)
3
+ category: Getting Started
4
+ order: 9
5
+ ---
6
+
7
+ # The MIT License (MIT)
8
+
9
+ Copyright (c) 2015 Instructure, Inc.
10
+
11
+ **Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions.**
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
@@ -26,12 +26,13 @@ import { addInputModeListener, addEventListener, containsActiveElement, findFocu
26
26
  import { logWarn as warn } from '@instructure/console';
27
27
  import { propTypes, allowedProps } from './props';
28
28
  import { createChainedFunction } from '@instructure/ui-utils';
29
+
29
30
  /**
30
31
  ---
31
32
  category: components/utilities
32
33
  ---
34
+ @tsProps
33
35
  **/
34
-
35
36
  class Focusable extends Component {
36
37
  constructor(...args) {
37
38
  super(...args);
@@ -40,21 +41,21 @@ class Focusable extends Component {
40
41
  this._inputModeListener = null;
41
42
  this.state = {
42
43
  focused: false,
43
- focusable: false
44
+ focusable: void 0
44
45
  };
45
46
 
46
47
  this.handleInputModeChange = () => {
47
48
  this.forceUpdate();
48
49
  };
49
50
 
50
- this.handleFocus = event => {
51
+ this.handleFocus = () => {
51
52
  this.removeFocusListener();
52
53
  this.setState({
53
54
  focused: true
54
55
  });
55
56
  };
56
57
 
57
- this.handleBlur = event => {
58
+ this.handleBlur = () => {
58
59
  this.removeBlurListener();
59
60
  this.setState({
60
61
  focused: false
@@ -71,7 +72,7 @@ class Focusable extends Component {
71
72
  componentDidMount() {
72
73
  const focusable = this.focusable,
73
74
  focused = this.focused;
74
- this.addFocusableListeners(focusable, focused);
75
+ this.addFocusableListeners(focused, focusable);
75
76
  this._inputModeListener = addInputModeListener({
76
77
  onInputModeChange: this.handleInputModeChange
77
78
  });
@@ -81,7 +82,7 @@ class Focusable extends Component {
81
82
  });
82
83
  }
83
84
 
84
- getSnapshotBeforeUpdate(prevProps, prevState) {
85
+ getSnapshotBeforeUpdate(prevProps) {
85
86
  const _this$props = this.props,
86
87
  render = _this$props.render,
87
88
  children = _this$props.children; // prevent blur from firing when focusable element is replaced
@@ -93,28 +94,29 @@ class Focusable extends Component {
93
94
  return null;
94
95
  }
95
96
 
96
- componentDidUpdate(prevProps, prevState) {
97
+ componentDidUpdate() {
97
98
  const focusable = this.focusable;
98
99
 
99
100
  if (!focusable && this.state.focusable) {
100
101
  this.removeFocusableListeners();
101
102
  this.setState({
102
- focusable: false,
103
+ focusable: void 0,
103
104
  focused: false
104
105
  });
105
106
  } else if (focusable !== this.state.focusable) {
106
107
  this.removeFocusableListeners();
107
108
 
108
109
  if (this.state.focused) {
110
+ ;
109
111
  focusable.focus();
110
112
  }
111
113
 
112
- this.addFocusableListeners(focusable, this.state.focused);
114
+ this.addFocusableListeners(this.state.focused, focusable);
113
115
  this.setState({
114
116
  focusable
115
117
  });
116
118
  } else {
117
- this.addFocusableListeners(focusable, this.state.focused);
119
+ this.addFocusableListeners(this.state.focused, focusable);
118
120
  }
119
121
  }
120
122
 
@@ -128,7 +130,7 @@ class Focusable extends Component {
128
130
  this.removeFocusableListeners();
129
131
  }
130
132
 
131
- addFocusableListeners(focusable, focused) {
133
+ addFocusableListeners(focused, focusable) {
132
134
  if (!focusable) return;
133
135
 
134
136
  if (focused && !this._blurListener) {
@@ -164,15 +166,15 @@ class Focusable extends Component {
164
166
  }
165
167
 
166
168
  get focusable() {
167
- let focusable = findFocusable(this, () => true, true) || [];
168
- const focusableCount = focusable && focusable.length || 0;
169
+ const focusableArr = findFocusable(this, () => true, true) || [];
170
+ const focusableCount = focusableArr && focusableArr.length || 0;
169
171
  warn(focusableCount === 1, `[Focusable] Exactly one focusable child is required (${focusableCount} found).`);
170
- focusable = focusable ? focusable[0] : false;
172
+ const focusable = focusableArr ? focusableArr[0] : false;
171
173
 
172
174
  if (focusable && typeof focusable.focus === 'function') {
173
175
  return focusable;
174
176
  } else {
175
- return false;
177
+ return void 0;
176
178
  }
177
179
  }
178
180
 
@@ -180,7 +182,7 @@ class Focusable extends Component {
180
182
  const _this$state = this.state,
181
183
  focusable = _this$state.focusable,
182
184
  focused = _this$state.focused;
183
- return this.isFocusVisible(focusable, focused);
185
+ return this.isFocusVisible(focused, focusable);
184
186
  }
185
187
 
186
188
  focus() {
@@ -191,10 +193,11 @@ class Focusable extends Component {
191
193
  }
192
194
  }
193
195
 
194
- isFocusVisible(focusable, focused) {
196
+ isFocusVisible(focused, focusable) {
195
197
  if (!focusable || !focused) return false; // always show focus for keyboard input mode
196
198
 
197
- if (this._inputModeListener && this._inputModeListener.isKeyboardMode()) return true;
199
+ if (this._inputModeListener && this._inputModeListener.isKeyboardMode()) return true; // note: the type property exist on input fields like HtmlInputElement
200
+
198
201
  const tagName = focusable.tagName,
199
202
  type = focusable.type,
200
203
  isContentEditable = focusable.isContentEditable;
@@ -227,7 +230,7 @@ class Focusable extends Component {
227
230
  const rendered = render({
228
231
  focused,
229
232
  focusable,
230
- focusVisible: this.isFocusVisible(focusable, focused),
233
+ focusVisible: this.isFocusVisible(focused, focusable),
231
234
  attachRef: this.attachRef
232
235
  });
233
236
  return /*#__PURE__*/cloneElement(rendered, {
@@ -23,17 +23,7 @@
23
23
  */
24
24
  import PropTypes from 'prop-types';
25
25
  const propTypes = {
26
- /**
27
- * @param {Object} renderProps
28
- * @param {Boolean} renderProps.focused - Is the element focused (via keyboard only)?
29
- * @param {HTMLElement} renderProps.focusable - The focusable element
30
- * @param {Boolean} renderProps.focusVisible - Whether the focus state should be visible or not
31
- */
32
26
  children: PropTypes.func,
33
-
34
- /**
35
- * Identical to children
36
- */
37
27
  render: PropTypes.func
38
28
  };
39
29
  const allowedProps = ['children', 'render'];
@@ -49,6 +49,7 @@ var _createChainedFunction = require("@instructure/ui-utils/lib/createChainedFun
49
49
  ---
50
50
  category: components/utilities
51
51
  ---
52
+ @tsProps
52
53
  **/
53
54
  class Focusable extends _react.Component {
54
55
  constructor(...args) {
@@ -58,21 +59,21 @@ class Focusable extends _react.Component {
58
59
  this._inputModeListener = null;
59
60
  this.state = {
60
61
  focused: false,
61
- focusable: false
62
+ focusable: void 0
62
63
  };
63
64
 
64
65
  this.handleInputModeChange = () => {
65
66
  this.forceUpdate();
66
67
  };
67
68
 
68
- this.handleFocus = event => {
69
+ this.handleFocus = () => {
69
70
  this.removeFocusListener();
70
71
  this.setState({
71
72
  focused: true
72
73
  });
73
74
  };
74
75
 
75
- this.handleBlur = event => {
76
+ this.handleBlur = () => {
76
77
  this.removeBlurListener();
77
78
  this.setState({
78
79
  focused: false
@@ -89,7 +90,7 @@ class Focusable extends _react.Component {
89
90
  componentDidMount() {
90
91
  const focusable = this.focusable,
91
92
  focused = this.focused;
92
- this.addFocusableListeners(focusable, focused);
93
+ this.addFocusableListeners(focused, focusable);
93
94
  this._inputModeListener = (0, _addInputModeListener.addInputModeListener)({
94
95
  onInputModeChange: this.handleInputModeChange
95
96
  });
@@ -99,7 +100,7 @@ class Focusable extends _react.Component {
99
100
  });
100
101
  }
101
102
 
102
- getSnapshotBeforeUpdate(prevProps, prevState) {
103
+ getSnapshotBeforeUpdate(prevProps) {
103
104
  const _this$props = this.props,
104
105
  render = _this$props.render,
105
106
  children = _this$props.children; // prevent blur from firing when focusable element is replaced
@@ -111,28 +112,29 @@ class Focusable extends _react.Component {
111
112
  return null;
112
113
  }
113
114
 
114
- componentDidUpdate(prevProps, prevState) {
115
+ componentDidUpdate() {
115
116
  const focusable = this.focusable;
116
117
 
117
118
  if (!focusable && this.state.focusable) {
118
119
  this.removeFocusableListeners();
119
120
  this.setState({
120
- focusable: false,
121
+ focusable: void 0,
121
122
  focused: false
122
123
  });
123
124
  } else if (focusable !== this.state.focusable) {
124
125
  this.removeFocusableListeners();
125
126
 
126
127
  if (this.state.focused) {
128
+ ;
127
129
  focusable.focus();
128
130
  }
129
131
 
130
- this.addFocusableListeners(focusable, this.state.focused);
132
+ this.addFocusableListeners(this.state.focused, focusable);
131
133
  this.setState({
132
134
  focusable
133
135
  });
134
136
  } else {
135
- this.addFocusableListeners(focusable, this.state.focused);
137
+ this.addFocusableListeners(this.state.focused, focusable);
136
138
  }
137
139
  }
138
140
 
@@ -146,7 +148,7 @@ class Focusable extends _react.Component {
146
148
  this.removeFocusableListeners();
147
149
  }
148
150
 
149
- addFocusableListeners(focusable, focused) {
151
+ addFocusableListeners(focused, focusable) {
150
152
  if (!focusable) return;
151
153
 
152
154
  if (focused && !this._blurListener) {
@@ -182,15 +184,15 @@ class Focusable extends _react.Component {
182
184
  }
183
185
 
184
186
  get focusable() {
185
- let focusable = (0, _findFocusable.findFocusable)(this, () => true, true) || [];
186
- const focusableCount = focusable && focusable.length || 0;
187
+ const focusableArr = (0, _findFocusable.findFocusable)(this, () => true, true) || [];
188
+ const focusableCount = focusableArr && focusableArr.length || 0;
187
189
  (0, _console.logWarn)(focusableCount === 1, `[Focusable] Exactly one focusable child is required (${focusableCount} found).`);
188
- focusable = focusable ? focusable[0] : false;
190
+ const focusable = focusableArr ? focusableArr[0] : false;
189
191
 
190
192
  if (focusable && typeof focusable.focus === 'function') {
191
193
  return focusable;
192
194
  } else {
193
- return false;
195
+ return void 0;
194
196
  }
195
197
  }
196
198
 
@@ -198,7 +200,7 @@ class Focusable extends _react.Component {
198
200
  const _this$state = this.state,
199
201
  focusable = _this$state.focusable,
200
202
  focused = _this$state.focused;
201
- return this.isFocusVisible(focusable, focused);
203
+ return this.isFocusVisible(focused, focusable);
202
204
  }
203
205
 
204
206
  focus() {
@@ -209,10 +211,11 @@ class Focusable extends _react.Component {
209
211
  }
210
212
  }
211
213
 
212
- isFocusVisible(focusable, focused) {
214
+ isFocusVisible(focused, focusable) {
213
215
  if (!focusable || !focused) return false; // always show focus for keyboard input mode
214
216
 
215
- if (this._inputModeListener && this._inputModeListener.isKeyboardMode()) return true;
217
+ if (this._inputModeListener && this._inputModeListener.isKeyboardMode()) return true; // note: the type property exist on input fields like HtmlInputElement
218
+
216
219
  const tagName = focusable.tagName,
217
220
  type = focusable.type,
218
221
  isContentEditable = focusable.isContentEditable;
@@ -245,7 +248,7 @@ class Focusable extends _react.Component {
245
248
  const rendered = render({
246
249
  focused,
247
250
  focusable,
248
- focusVisible: this.isFocusVisible(focusable, focused),
251
+ focusVisible: this.isFocusVisible(focused, focusable),
249
252
  attachRef: this.attachRef
250
253
  });
251
254
  return /*#__PURE__*/(0, _react.cloneElement)(rendered, {
@@ -33,17 +33,7 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
33
33
  * SOFTWARE.
34
34
  */
35
35
  const propTypes = {
36
- /**
37
- * @param {Object} renderProps
38
- * @param {Boolean} renderProps.focused - Is the element focused (via keyboard only)?
39
- * @param {HTMLElement} renderProps.focusable - The focusable element
40
- * @param {Boolean} renderProps.focusVisible - Whether the focus state should be visible or not
41
- */
42
36
  children: _propTypes.default.func,
43
-
44
- /**
45
- * Identical to children
46
- */
47
37
  render: _propTypes.default.func
48
38
  };
49
39
  exports.propTypes = propTypes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-focusable",
3
- "version": "8.12.0",
3
+ "version": "8.12.1-snapshot.3+ff273fca9",
4
4
  "description": "A utility used to identify when an element receives focus.",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "type": "commonjs",
@@ -24,16 +24,16 @@
24
24
  },
25
25
  "license": "MIT",
26
26
  "devDependencies": {
27
- "@instructure/ui-babel-preset": "8.12.0",
28
- "@instructure/ui-test-utils": "8.12.0"
27
+ "@instructure/ui-babel-preset": "8.12.1-snapshot.3+ff273fca9",
28
+ "@instructure/ui-test-utils": "8.12.1-snapshot.3+ff273fca9"
29
29
  },
30
30
  "dependencies": {
31
31
  "@babel/runtime": "^7.13.10",
32
- "@instructure/console": "8.12.0",
33
- "@instructure/ui-dom-utils": "8.12.0",
34
- "@instructure/ui-react-utils": "8.12.0",
35
- "@instructure/ui-utils": "8.12.0",
36
- "@instructure/ui-view": "8.12.0",
32
+ "@instructure/console": "8.12.1-snapshot.3+ff273fca9",
33
+ "@instructure/ui-dom-utils": "8.12.1-snapshot.3+ff273fca9",
34
+ "@instructure/ui-react-utils": "8.12.1-snapshot.3+ff273fca9",
35
+ "@instructure/ui-utils": "8.12.1-snapshot.3+ff273fca9",
36
+ "@instructure/ui-view": "8.12.1-snapshot.3+ff273fca9",
37
37
  "prop-types": "^15"
38
38
  },
39
39
  "peerDependencies": {
@@ -42,5 +42,6 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "sideEffects": false
45
+ "sideEffects": false,
46
+ "gitHead": "ff273fca985c08abf804c155bbd3a6a893a142c8"
46
47
  }
@@ -11,26 +11,27 @@ a `render` or `children` method that returns content which must have exactly one
11
11
  example: true
12
12
  ---
13
13
  <Focusable>
14
- {({ focused }) => (
15
- <span>
16
- <div>
17
- <Button>Focus me!</Button>
18
- </div>
19
- {focused && (
20
- <ContextView
21
- margin="small 0"
22
- placement="bottom"
23
- as="div"
24
- background="primary"
25
- padding="small"
26
- borderWidth="small"
27
- display="block"
28
- >
29
- I&#39;m focused!
30
- </ContextView>
31
- )}
32
- </span>
33
- )}
14
+ {(options) => {
15
+ console.log(options)
16
+ return <span>
17
+ <div>
18
+ <Button>Focus me!</Button>
19
+ </div>
20
+ {options.focused && (
21
+ <ContextView
22
+ margin="small 0"
23
+ placement="bottom"
24
+ as="div"
25
+ background="inverse"
26
+ padding="small"
27
+ borderWidth="small"
28
+ display="block"
29
+ >
30
+ I&#39;m focused!
31
+ </ContextView>
32
+ )}
33
+ </span>
34
+ }}
34
35
  </Focusable>
35
36
  ```
36
37
 
@@ -32,16 +32,21 @@ import {
32
32
  } from '@instructure/ui-dom-utils'
33
33
  import { logWarn as warn } from '@instructure/console'
34
34
 
35
- import { propTypes, allowedProps } from './props'
35
+ import { propTypes, allowedProps, FocusableState } from './props'
36
36
  import type { FocusableProps } from './props'
37
37
  import { createChainedFunction } from '@instructure/ui-utils'
38
38
 
39
+ type HTMLElementWithType = HTMLElement & {
40
+ type?: keyof typeof Focusable.inputTypes
41
+ }
42
+
39
43
  /**
40
44
  ---
41
45
  category: components/utilities
42
46
  ---
47
+ @tsProps
43
48
  **/
44
- class Focusable extends Component<FocusableProps> {
49
+ class Focusable extends Component<FocusableProps, FocusableState> {
45
50
  static propTypes = propTypes
46
51
  static allowedProps = allowedProps
47
52
  static defaultProps = {
@@ -71,14 +76,14 @@ class Focusable extends Component<FocusableProps> {
71
76
  remove(): void
72
77
  } | null = null
73
78
 
74
- state = {
79
+ state: FocusableState = {
75
80
  focused: false,
76
- focusable: false
81
+ focusable: undefined
77
82
  }
78
83
 
79
84
  componentDidMount() {
80
85
  const { focusable, focused } = this
81
- this.addFocusableListeners(focusable, focused)
86
+ this.addFocusableListeners(focused, focusable)
82
87
  this._inputModeListener = addInputModeListener({
83
88
  onInputModeChange: this.handleInputModeChange
84
89
  })
@@ -88,8 +93,7 @@ class Focusable extends Component<FocusableProps> {
88
93
  })
89
94
  }
90
95
 
91
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'prevProps' implicitly has an 'any' type... Remove this comment to see the full error message
92
- getSnapshotBeforeUpdate(prevProps, prevState) {
96
+ getSnapshotBeforeUpdate(prevProps: FocusableProps) {
93
97
  const { render, children } = this.props
94
98
  // prevent blur from firing when focusable element is replaced
95
99
  if (prevProps.children !== children || prevProps.render !== render) {
@@ -98,30 +102,24 @@ class Focusable extends Component<FocusableProps> {
98
102
  return null
99
103
  }
100
104
 
101
- // @ts-expect-error ts-migrate(6133) FIXME: 'prevProps' is declared but its value is never rea... Remove this comment to see the full error message
102
- componentDidUpdate(prevProps, prevState) {
103
- const { focusable } = this
104
-
105
+ componentDidUpdate() {
106
+ const focusable = this.focusable
105
107
  if (!focusable && this.state.focusable) {
106
108
  this.removeFocusableListeners()
107
109
 
108
110
  this.setState({
109
- focusable: false,
111
+ focusable: undefined,
110
112
  focused: false
111
113
  })
112
114
  } else if (focusable !== this.state.focusable) {
113
115
  this.removeFocusableListeners()
114
-
115
116
  if (this.state.focused) {
116
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'focus' does not exist on type 'false | u... Remove this comment to see the full error message
117
- focusable.focus()
117
+ ;(focusable as HTMLElement).focus()
118
118
  }
119
-
120
- this.addFocusableListeners(focusable, this.state.focused)
121
-
119
+ this.addFocusableListeners(this.state.focused, focusable)
122
120
  this.setState({ focusable })
123
121
  } else {
124
- this.addFocusableListeners(focusable, this.state.focused)
122
+ this.addFocusableListeners(this.state.focused, focusable)
125
123
  }
126
124
  }
127
125
 
@@ -133,8 +131,7 @@ class Focusable extends Component<FocusableProps> {
133
131
  this.removeFocusableListeners()
134
132
  }
135
133
 
136
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'focusable' implicitly has an 'any' type... Remove this comment to see the full error message
137
- addFocusableListeners(focusable, focused) {
134
+ addFocusableListeners(focused: boolean, focusable?: HTMLElement) {
138
135
  if (!focusable) return
139
136
 
140
137
  if (focused && !this._blurListener) {
@@ -177,14 +174,12 @@ class Focusable extends Component<FocusableProps> {
177
174
  this.forceUpdate()
178
175
  }
179
176
 
180
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
181
- handleFocus = (event) => {
177
+ handleFocus = () => {
182
178
  this.removeFocusListener()
183
179
  this.setState({ focused: true })
184
180
  }
185
181
 
186
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
187
- handleBlur = (event) => {
182
+ handleBlur = () => {
188
183
  this.removeBlurListener()
189
184
  this.setState({ focused: false })
190
185
  }
@@ -194,34 +189,31 @@ class Focusable extends Component<FocusableProps> {
194
189
  }
195
190
 
196
191
  get focusable() {
197
- let focusable = findFocusable(this, () => true, true) || []
198
- const focusableCount = (focusable && focusable.length) || 0
192
+ const focusableArr = findFocusable(this, () => true, true) || []
193
+ const focusableCount = (focusableArr && focusableArr.length) || 0
199
194
 
200
195
  warn(
201
196
  focusableCount === 1,
202
197
  `[Focusable] Exactly one focusable child is required (${focusableCount} found).`
203
198
  )
204
199
 
205
- // @ts-expect-error ts-migrate(2322) FIXME: Type 'unknown' is not assignable to type 'unknown[... Remove this comment to see the full error message
206
- focusable = focusable ? focusable[0] : false
200
+ const focusable = focusableArr ? focusableArr[0] : false
207
201
 
208
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'focus' does not exist on type 'unknown[]... Remove this comment to see the full error message
209
- if (focusable && typeof focusable.focus === 'function') {
210
- return focusable
202
+ if (focusable && typeof (focusable as HTMLElement).focus === 'function') {
203
+ return focusable as HTMLElement
211
204
  } else {
212
- return false
205
+ return undefined
213
206
  }
214
207
  }
215
208
 
216
209
  get focusVisible() {
217
210
  const { focusable, focused } = this.state
218
- return this.isFocusVisible(focusable, focused)
211
+ return this.isFocusVisible(focused, focusable)
219
212
  }
220
213
 
221
214
  focus() {
222
215
  const { focusable } = this
223
216
  if (focusable) {
224
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'focus' does not exist on type 'unknown[]... Remove this comment to see the full error message
225
217
  focusable.focus()
226
218
  }
227
219
  }
@@ -232,29 +224,24 @@ class Focusable extends Component<FocusableProps> {
232
224
  this.ref = el
233
225
  }
234
226
 
235
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'focusable' implicitly has an 'any' type... Remove this comment to see the full error message
236
- isFocusVisible(focusable, focused) {
227
+ isFocusVisible(focused: boolean, focusable?: HTMLElementWithType) {
237
228
  if (!focusable || !focused) return false
238
229
 
239
230
  // always show focus for keyboard input mode
240
231
  if (this._inputModeListener && this._inputModeListener.isKeyboardMode())
241
232
  return true
242
-
233
+ // note: the type property exist on input fields like HtmlInputElement
243
234
  const { tagName, type, isContentEditable } = focusable
244
235
 
245
- // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
246
- if (tagName == 'INPUT' && Focusable.inputTypes[type]) {
236
+ if (tagName == 'INPUT' && Focusable.inputTypes[type!]) {
247
237
  return true
248
238
  }
249
-
250
239
  if (tagName == 'TEXTAREA') {
251
240
  return true
252
241
  }
253
-
254
242
  if (isContentEditable) {
255
243
  return true
256
244
  }
257
-
258
245
  return false
259
246
  }
260
247
 
@@ -266,10 +253,9 @@ class Focusable extends Component<FocusableProps> {
266
253
  const rendered = render({
267
254
  focused,
268
255
  focusable,
269
- focusVisible: this.isFocusVisible(focusable, focused),
256
+ focusVisible: this.isFocusVisible(focused, focusable),
270
257
  attachRef: this.attachRef
271
258
  })
272
-
273
259
  return cloneElement(rendered, {
274
260
  ref: rendered.ref
275
261
  ? createChainedFunction(rendered.ref, this.attachRef)
@@ -24,10 +24,59 @@
24
24
 
25
25
  import type { PropValidators } from '@instructure/shared-types'
26
26
  import PropTypes from 'prop-types'
27
+ import {
28
+ CElement,
29
+ DOMElement,
30
+ FunctionComponentElement,
31
+ ReactComponentElement,
32
+ ReactElement
33
+ } from 'react'
34
+
35
+ export type FocusableRenderOptions = {
36
+ /**
37
+ * Is the element focused (via keyboard only)?
38
+ */
39
+ focused: boolean
40
+ /**
41
+ * The focusable element
42
+ */
43
+ focusable?: HTMLElement
44
+ /**
45
+ * Whether the focus state should be visible or not
46
+ */
47
+ focusVisible: boolean
48
+ attachRef: (el: Element) => void
49
+ }
50
+
51
+ type FocusableRenderFunction = (
52
+ opts: FocusableRenderOptions
53
+ ) => (
54
+ | ReactElement
55
+ | ReactComponentElement<any>
56
+ | DOMElement<any, any>
57
+ | CElement<any, any>
58
+ | FunctionComponentElement<any>
59
+ ) & { ref?: (args: any[]) => unknown }
27
60
 
28
61
  type FocusableOwnProps = {
29
- children?: (...args: any[]) => any
30
- render?: (...args: any[]) => any
62
+ /**
63
+ * The function called on each render. Identical to `render()`
64
+ * @param {Object} opts - Render options
65
+ * @param {boolean} opts.focused - Is the element focused (via keyboard only)?
66
+ * @param {HTMLElement} opts.focusable - The focusable element.
67
+ * @param {boolean} opts.focusVisible - Whether the focus state should be visible or not.
68
+ * @param {function} opts.attachRef - Used internally to get a reference to the object.
69
+ */
70
+ children?: FocusableRenderFunction
71
+ /**
72
+ * The function called on each render. Identical to `children()`.
73
+ * @param {Object} opts - Render options
74
+ * @param {boolean} opts.focused - Is the element focused (via keyboard only)?
75
+ * @param {HTMLElement} opts.focusable - The focusable element.
76
+ * @param {boolean} opts.focusVisible - Whether the focus state should be visible or not.
77
+ * @param {function} opts.attachRef - Used internally to get a reference to the object.
78
+ */
79
+ render?: FocusableRenderFunction
31
80
  }
32
81
 
33
82
  type PropKeys = keyof FocusableOwnProps
@@ -37,20 +86,16 @@ type AllowedPropKeys = Readonly<Array<PropKeys>>
37
86
  type FocusableProps = FocusableOwnProps
38
87
 
39
88
  const propTypes: PropValidators<PropKeys> = {
40
- /**
41
- * @param {Object} renderProps
42
- * @param {Boolean} renderProps.focused - Is the element focused (via keyboard only)?
43
- * @param {HTMLElement} renderProps.focusable - The focusable element
44
- * @param {Boolean} renderProps.focusVisible - Whether the focus state should be visible or not
45
- */
46
89
  children: PropTypes.func,
47
- /**
48
- * Identical to children
49
- */
50
90
  render: PropTypes.func
51
91
  }
52
92
 
53
93
  const allowedProps: AllowedPropKeys = ['children', 'render']
54
94
 
55
- export type { FocusableProps }
95
+ type FocusableState = {
96
+ focused: boolean
97
+ focusable?: HTMLElement
98
+ }
99
+
100
+ export type { FocusableProps, FocusableState }
56
101
  export { propTypes, allowedProps }
@@ -1,18 +1,31 @@
1
1
  import { Component } from 'react';
2
+ import { FocusableState } from './props';
2
3
  import type { FocusableProps } from './props';
4
+ declare type HTMLElementWithType = HTMLElement & {
5
+ type?: keyof typeof Focusable.inputTypes;
6
+ };
3
7
  /**
4
8
  ---
5
9
  category: components/utilities
6
10
  ---
11
+ @tsProps
7
12
  **/
8
- declare class Focusable extends Component<FocusableProps> {
13
+ declare class Focusable extends Component<FocusableProps, FocusableState> {
9
14
  static propTypes: import("@instructure/shared-types/types/UtilityTypes").PropValidators<keyof {
10
- children?: ((...args: any[]) => any) | undefined;
11
- render?: ((...args: any[]) => any) | undefined;
15
+ children?: ((opts: import("./props").FocusableRenderOptions) => (import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactComponentElement<any, Pick<any, string | number | symbol>> | import("react").DOMElement<any, any> | import("react").CElement<any, any> | import("react").FunctionComponentElement<any>) & {
16
+ ref?: ((args: any[]) => unknown) | undefined;
17
+ }) | undefined;
18
+ render?: ((opts: import("./props").FocusableRenderOptions) => (import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactComponentElement<any, Pick<any, string | number | symbol>> | import("react").DOMElement<any, any> | import("react").CElement<any, any> | import("react").FunctionComponentElement<any>) & {
19
+ ref?: ((args: any[]) => unknown) | undefined;
20
+ }) | undefined;
12
21
  }>;
13
22
  static allowedProps: readonly (keyof {
14
- children?: ((...args: any[]) => any) | undefined;
15
- render?: ((...args: any[]) => any) | undefined;
23
+ children?: ((opts: import("./props").FocusableRenderOptions) => (import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactComponentElement<any, Pick<any, string | number | symbol>> | import("react").DOMElement<any, any> | import("react").CElement<any, any> | import("react").FunctionComponentElement<any>) & {
24
+ ref?: ((args: any[]) => unknown) | undefined;
25
+ }) | undefined;
26
+ render?: ((opts: import("./props").FocusableRenderOptions) => (import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactComponentElement<any, Pick<any, string | number | symbol>> | import("react").DOMElement<any, any> | import("react").CElement<any, any> | import("react").FunctionComponentElement<any>) & {
27
+ ref?: ((args: any[]) => unknown) | undefined;
28
+ }) | undefined;
16
29
  })[];
17
30
  static defaultProps: {
18
31
  children: null;
@@ -42,31 +55,26 @@ declare class Focusable extends Component<FocusableProps> {
42
55
  isKeyboardMode(): boolean;
43
56
  remove(): void;
44
57
  } | null;
45
- state: {
46
- focused: boolean;
47
- focusable: boolean;
48
- };
58
+ state: FocusableState;
49
59
  componentDidMount(): void;
50
- getSnapshotBeforeUpdate(prevProps: any, prevState: any): null;
51
- componentDidUpdate(prevProps: any, prevState: any): void;
60
+ getSnapshotBeforeUpdate(prevProps: FocusableProps): null;
61
+ componentDidUpdate(): void;
52
62
  componentWillUnmount(): void;
53
- addFocusableListeners(focusable: any, focused: any): void;
63
+ addFocusableListeners(focused: boolean, focusable?: HTMLElement): void;
54
64
  removeFocusableListeners(): void;
55
65
  removeFocusListener(): void;
56
66
  removeBlurListener(): void;
57
67
  handleInputModeChange: () => void;
58
- handleFocus: (event: any) => void;
59
- handleBlur: (event: any) => void;
68
+ handleFocus: () => void;
69
+ handleBlur: () => void;
60
70
  get focused(): boolean;
61
- get focusable(): false | Element[];
71
+ get focusable(): HTMLElement | undefined;
62
72
  get focusVisible(): boolean;
63
73
  focus(): void;
64
74
  ref: Element | null;
65
75
  attachRef: (el: Element) => void;
66
- isFocusVisible(focusable: any, focused: any): boolean;
67
- render(): import("react").FunctionComponentElement<{
68
- ref: (...args: any[]) => any;
69
- }> | null;
76
+ isFocusVisible(focused: boolean, focusable?: HTMLElementWithType): boolean;
77
+ render(): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | null;
70
78
  }
71
79
  export default Focusable;
72
80
  export { Focusable };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Focusable/index.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAW/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG7C;;;;GAIG;AACH,cAAM,SAAU,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC/C,MAAM,CAAC,SAAS;;;OAAY;IAC5B,MAAM,CAAC,YAAY;;;SAAe;IAClC,MAAM,CAAC,YAAY;;MAElB;IAED,MAAM,CAAC,UAAU;;;;;;;;;;;;;;MAchB;IAED,cAAc,EAAE;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAO;IAChD,aAAa,EAAE;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAO;IAC/C,kBAAkB,EAAE;QAClB,cAAc,IAAI,OAAO,CAAA;QACzB,MAAM,IAAI,IAAI,CAAA;KACf,GAAG,IAAI,CAAO;IAEf,KAAK;;;MAGJ;IAED,iBAAiB;IAajB,uBAAuB,CAAC,SAAS,KAAA,EAAE,SAAS,KAAA;IAU5C,kBAAkB,CAAC,SAAS,KAAA,EAAE,SAAS,KAAA;IA0BvC,oBAAoB;IASpB,qBAAqB,CAAC,SAAS,KAAA,EAAE,OAAO,KAAA;IAoBxC,wBAAwB;IAKxB,mBAAmB;IAOnB,kBAAkB;IAOlB,qBAAqB,aAEpB;IAGD,WAAW,uBAGV;IAGD,UAAU,uBAGT;IAED,IAAI,OAAO,YAEV;IAED,IAAI,SAAS,sBAkBZ;IAED,IAAI,YAAY,YAGf;IAED,KAAK;IAQL,GAAG,EAAE,OAAO,GAAG,IAAI,CAAO;IAE1B,SAAS,OAAQ,OAAO,UAEvB;IAGD,cAAc,CAAC,SAAS,KAAA,EAAE,OAAO,KAAA;IAyBjC,MAAM;;;CAqBP;AAED,eAAe,SAAS,CAAA;AACxB,OAAO,EAAE,SAAS,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Focusable/index.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAU/C,OAAO,EAA2B,cAAc,EAAE,MAAM,SAAS,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG7C,aAAK,mBAAmB,GAAG,WAAW,GAAG;IACvC,IAAI,CAAC,EAAE,MAAM,OAAO,SAAS,CAAC,UAAU,CAAA;CACzC,CAAA;AAED;;;;;GAKG;AACH,cAAM,SAAU,SAAQ,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IAC/D,MAAM,CAAC,SAAS;;;;;;;OAAY;IAC5B,MAAM,CAAC,YAAY;;;;;;;SAAe;IAClC,MAAM,CAAC,YAAY;;MAElB;IAED,MAAM,CAAC,UAAU;;;;;;;;;;;;;;MAchB;IAED,cAAc,EAAE;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAO;IAChD,aAAa,EAAE;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAO;IAC/C,kBAAkB,EAAE;QAClB,cAAc,IAAI,OAAO,CAAA;QACzB,MAAM,IAAI,IAAI,CAAA;KACf,GAAG,IAAI,CAAO;IAEf,KAAK,EAAE,cAAc,CAGpB;IAED,iBAAiB;IAYjB,uBAAuB,CAAC,SAAS,EAAE,cAAc;IASjD,kBAAkB;IAqBlB,oBAAoB;IAQpB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,WAAW;IAoB/D,wBAAwB;IAKxB,mBAAmB;IAOnB,kBAAkB;IAOlB,qBAAqB,aAEpB;IAED,WAAW,aAGV;IAED,UAAU,aAGT;IAED,IAAI,OAAO,YAEV;IAED,IAAI,SAAS,4BAgBZ;IAED,IAAI,YAAY,YAGf;IAED,KAAK;IAOL,GAAG,EAAE,OAAO,GAAG,IAAI,CAAO;IAE1B,SAAS,OAAQ,OAAO,UAEvB;IAED,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,mBAAmB;IAqBhE,MAAM;CAoBP;AAED,eAAe,SAAS,CAAA;AACxB,OAAO,EAAE,SAAS,EAAE,CAAA"}
@@ -1,13 +1,52 @@
1
1
  import type { PropValidators } from '@instructure/shared-types';
2
+ import { CElement, DOMElement, FunctionComponentElement, ReactComponentElement, ReactElement } from 'react';
3
+ export declare type FocusableRenderOptions = {
4
+ /**
5
+ * Is the element focused (via keyboard only)?
6
+ */
7
+ focused: boolean;
8
+ /**
9
+ * The focusable element
10
+ */
11
+ focusable?: HTMLElement;
12
+ /**
13
+ * Whether the focus state should be visible or not
14
+ */
15
+ focusVisible: boolean;
16
+ attachRef: (el: Element) => void;
17
+ };
18
+ declare type FocusableRenderFunction = (opts: FocusableRenderOptions) => (ReactElement | ReactComponentElement<any> | DOMElement<any, any> | CElement<any, any> | FunctionComponentElement<any>) & {
19
+ ref?: (args: any[]) => unknown;
20
+ };
2
21
  declare type FocusableOwnProps = {
3
- children?: (...args: any[]) => any;
4
- render?: (...args: any[]) => any;
22
+ /**
23
+ * The function called on each render. Identical to `render()`
24
+ * @param {Object} opts - Render options
25
+ * @param {boolean} opts.focused - Is the element focused (via keyboard only)?
26
+ * @param {HTMLElement} opts.focusable - The focusable element.
27
+ * @param {boolean} opts.focusVisible - Whether the focus state should be visible or not.
28
+ * @param {function} opts.attachRef - Used internally to get a reference to the object.
29
+ */
30
+ children?: FocusableRenderFunction;
31
+ /**
32
+ * The function called on each render. Identical to `children()`.
33
+ * @param {Object} opts - Render options
34
+ * @param {boolean} opts.focused - Is the element focused (via keyboard only)?
35
+ * @param {HTMLElement} opts.focusable - The focusable element.
36
+ * @param {boolean} opts.focusVisible - Whether the focus state should be visible or not.
37
+ * @param {function} opts.attachRef - Used internally to get a reference to the object.
38
+ */
39
+ render?: FocusableRenderFunction;
5
40
  };
6
41
  declare type PropKeys = keyof FocusableOwnProps;
7
42
  declare type AllowedPropKeys = Readonly<Array<PropKeys>>;
8
43
  declare type FocusableProps = FocusableOwnProps;
9
44
  declare const propTypes: PropValidators<PropKeys>;
10
45
  declare const allowedProps: AllowedPropKeys;
11
- export type { FocusableProps };
46
+ declare type FocusableState = {
47
+ focused: boolean;
48
+ focusable?: HTMLElement;
49
+ };
50
+ export type { FocusableProps, FocusableState };
12
51
  export { propTypes, allowedProps };
13
52
  //# sourceMappingURL=props.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/Focusable/props.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAG/D,aAAK,iBAAiB,GAAG;IACvB,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;CACjC,CAAA;AAED,aAAK,QAAQ,GAAG,MAAM,iBAAiB,CAAA;AAEvC,aAAK,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;AAEhD,aAAK,cAAc,GAAG,iBAAiB,CAAA;AAEvC,QAAA,MAAM,SAAS,EAAE,cAAc,CAAC,QAAQ,CAYvC,CAAA;AAED,QAAA,MAAM,YAAY,EAAE,eAAwC,CAAA;AAE5D,YAAY,EAAE,cAAc,EAAE,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/Focusable/props.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAE/D,OAAO,EACL,QAAQ,EACR,UAAU,EACV,wBAAwB,EACxB,qBAAqB,EACrB,YAAY,EACb,MAAM,OAAO,CAAA;AAEd,oBAAY,sBAAsB,GAAG;IACnC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,CAAA;CACjC,CAAA;AAED,aAAK,uBAAuB,GAAG,CAC7B,IAAI,EAAE,sBAAsB,KACzB,CACD,YAAY,GACZ,qBAAqB,CAAC,GAAG,CAAC,GAC1B,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,GACpB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,GAClB,wBAAwB,CAAC,GAAG,CAAC,CAChC,GAAG;IAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAA;CAAE,CAAA;AAEtC,aAAK,iBAAiB,GAAG;IACvB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAA;IAClC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAA;CACjC,CAAA;AAED,aAAK,QAAQ,GAAG,MAAM,iBAAiB,CAAA;AAEvC,aAAK,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;AAEhD,aAAK,cAAc,GAAG,iBAAiB,CAAA;AAEvC,QAAA,MAAM,SAAS,EAAE,cAAc,CAAC,QAAQ,CAGvC,CAAA;AAED,QAAA,MAAM,YAAY,EAAE,eAAwC,CAAA;AAE5D,aAAK,cAAc,GAAG;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,WAAW,CAAA;CACxB,CAAA;AAED,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA"}