@instructure/ui-radio-input 10.19.2-snapshot-0 → 10.19.2-snapshot-2

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 CHANGED
@@ -3,9 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [10.19.2-snapshot-0](https://github.com/instructure/instructure-ui/compare/v10.19.1...v10.19.2-snapshot-0) (2025-06-06)
6
+ ## [10.19.2-snapshot-2](https://github.com/instructure/instructure-ui/compare/v10.19.1...v10.19.2-snapshot-2) (2025-06-11)
7
7
 
8
- **Note:** Version bump only for package @instructure/ui-radio-input
8
+
9
+ ### Features
10
+
11
+ * **many:** add missing inputRef prop to input components ([e1158fb](https://github.com/instructure/instructure-ui/commit/e1158fb7af5426e6ce13efe197c2148e1c5f15f0))
9
12
 
10
13
 
11
14
 
@@ -53,16 +53,28 @@ describe('<RadioInput />', () => {
53
53
  expect(input).toBeInTheDocument();
54
54
  expect(input).toHaveAttribute('type', 'radio');
55
55
  });
56
+ it('should provide an inputRef prop', async () => {
57
+ const inputRef = vi.fn();
58
+ const _render2 = render(_jsx(RadioInput, {
59
+ label: "fake label",
60
+ value: "someValue",
61
+ name: "someName",
62
+ inputRef: inputRef
63
+ })),
64
+ container = _render2.container;
65
+ const input = container.querySelector('input');
66
+ expect(inputRef).toHaveBeenCalledWith(input);
67
+ });
56
68
  describe('events', () => {
57
69
  it('responds to onClick event', async () => {
58
70
  const onClick = vi.fn();
59
- const _render2 = render(_jsx(RadioInput, {
71
+ const _render3 = render(_jsx(RadioInput, {
60
72
  label: "fake label",
61
73
  value: "someValue",
62
74
  name: "someName",
63
75
  onClick: onClick
64
76
  })),
65
- container = _render2.container;
77
+ container = _render3.container;
66
78
  const input = container.querySelector('input');
67
79
  userEvent.click(input);
68
80
  await waitFor(() => {
@@ -71,14 +83,14 @@ describe('<RadioInput />', () => {
71
83
  });
72
84
  it('does not respond to onClick event when disabled', async () => {
73
85
  const onClick = vi.fn();
74
- const _render3 = render(_jsx(RadioInput, {
86
+ const _render4 = render(_jsx(RadioInput, {
75
87
  disabled: true,
76
88
  label: "fake label",
77
89
  value: "someValue",
78
90
  name: "someName",
79
91
  onClick: onClick
80
92
  })),
81
- container = _render3.container;
93
+ container = _render4.container;
82
94
  const input = container.querySelector('input');
83
95
  fireEvent.click(input);
84
96
  await waitFor(() => {
@@ -88,14 +100,14 @@ describe('<RadioInput />', () => {
88
100
  });
89
101
  it('does not respond to onClick event when readOnly', async () => {
90
102
  const onClick = vi.fn();
91
- const _render4 = render(_jsx(RadioInput, {
103
+ const _render5 = render(_jsx(RadioInput, {
92
104
  readOnly: true,
93
105
  label: "fake label",
94
106
  value: "someValue",
95
107
  name: "someName",
96
108
  onClick: onClick
97
109
  })),
98
- container = _render4.container;
110
+ container = _render5.container;
99
111
  const input = container.querySelector('input');
100
112
  fireEvent.click(input);
101
113
  await waitFor(() => {
@@ -105,13 +117,13 @@ describe('<RadioInput />', () => {
105
117
  });
106
118
  it('responds to onChange event', async () => {
107
119
  const onChange = vi.fn();
108
- const _render5 = render(_jsx(RadioInput, {
120
+ const _render6 = render(_jsx(RadioInput, {
109
121
  label: "fake label",
110
122
  value: "someValue",
111
123
  name: "someName",
112
124
  onChange: onChange
113
125
  })),
114
- container = _render5.container;
126
+ container = _render6.container;
115
127
  const input = container.querySelector('input');
116
128
  userEvent.click(input);
117
129
  await waitFor(() => {
@@ -120,14 +132,14 @@ describe('<RadioInput />', () => {
120
132
  });
121
133
  it('does not respond to onChange event when disabled', async () => {
122
134
  const onChange = vi.fn();
123
- const _render6 = render(_jsx(RadioInput, {
135
+ const _render7 = render(_jsx(RadioInput, {
124
136
  disabled: true,
125
137
  label: "fake label",
126
138
  value: "someValue",
127
139
  name: "someName",
128
140
  onChange: onChange
129
141
  })),
130
- container = _render6.container;
142
+ container = _render7.container;
131
143
  const input = container.querySelector('input');
132
144
  fireEvent.click(input);
133
145
  await waitFor(() => {
@@ -136,14 +148,14 @@ describe('<RadioInput />', () => {
136
148
  });
137
149
  it('does not respond to onChange event when readOnly', async () => {
138
150
  const onChange = vi.fn();
139
- const _render7 = render(_jsx(RadioInput, {
151
+ const _render8 = render(_jsx(RadioInput, {
140
152
  readOnly: true,
141
153
  label: "fake label",
142
154
  value: "someValue",
143
155
  name: "someName",
144
156
  onChange: onChange
145
157
  })),
146
- container = _render7.container;
158
+ container = _render8.container;
147
159
  const input = container.querySelector('input');
148
160
  fireEvent.click(input);
149
161
  await waitFor(() => {
@@ -152,13 +164,13 @@ describe('<RadioInput />', () => {
152
164
  });
153
165
  it('responds to onBlur event', async () => {
154
166
  const onBlur = vi.fn();
155
- const _render8 = render(_jsx(RadioInput, {
167
+ const _render9 = render(_jsx(RadioInput, {
156
168
  label: "fake label",
157
169
  value: "someValue",
158
170
  name: "someName",
159
171
  onBlur: onBlur
160
172
  })),
161
- container = _render8.container;
173
+ container = _render9.container;
162
174
  const input = container.querySelector('input');
163
175
  fireEvent.focusOut(input);
164
176
  await waitFor(() => {
@@ -167,13 +179,13 @@ describe('<RadioInput />', () => {
167
179
  });
168
180
  it('responds to onFocus event', async () => {
169
181
  const onFocus = vi.fn();
170
- const _render9 = render(_jsx(RadioInput, {
182
+ const _render10 = render(_jsx(RadioInput, {
171
183
  label: "fake label",
172
184
  value: "someValue",
173
185
  name: "someName",
174
186
  onFocus: onFocus
175
187
  })),
176
- container = _render9.container;
188
+ container = _render10.container;
177
189
  const input = container.querySelector('input');
178
190
  fireEvent.focus(input);
179
191
  await waitFor(() => {
@@ -181,19 +193,19 @@ describe('<RadioInput />', () => {
181
193
  });
182
194
  });
183
195
  it('sets input to checked when selected', async () => {
184
- const _render10 = render(_RadioInput2 || (_RadioInput2 = _jsx(RadioInput, {
196
+ const _render11 = render(_RadioInput2 || (_RadioInput2 = _jsx(RadioInput, {
185
197
  checked: true,
186
198
  label: "fake label",
187
199
  value: "someValue",
188
200
  name: "someName"
189
201
  }))),
190
- container = _render10.container;
202
+ container = _render11.container;
191
203
  const input = container.querySelector('input');
192
204
  expect(input).toHaveAttribute('checked');
193
205
  });
194
206
  it('focuses with the focus helper', async () => {
195
207
  let ref;
196
- const _render11 = render(_jsx(RadioInput, {
208
+ const _render12 = render(_jsx(RadioInput, {
197
209
  label: "fake label",
198
210
  value: "someValue",
199
211
  name: "someName"
@@ -201,7 +213,7 @@ describe('<RadioInput />', () => {
201
213
  ,
202
214
  ref: el => ref = el
203
215
  })),
204
- container = _render11.container;
216
+ container = _render12.container;
205
217
  const input = container.querySelector('input');
206
218
  ref.focus();
207
219
  await waitFor(() => {
@@ -211,13 +223,13 @@ describe('<RadioInput />', () => {
211
223
  });
212
224
  describe('for a11y', () => {
213
225
  it('simple variant should meet a11y standards', async () => {
214
- const _render12 = render(_RadioInput3 || (_RadioInput3 = _jsx(RadioInput, {
226
+ const _render13 = render(_RadioInput3 || (_RadioInput3 = _jsx(RadioInput, {
215
227
  variant: "simple",
216
228
  label: "fake label",
217
229
  value: "someValue",
218
230
  name: "someName"
219
231
  }))),
220
- container = _render12.container;
232
+ container = _render13.container;
221
233
  const axeCheck = await runAxeCheck(container);
222
234
  expect(axeCheck).toBe(true);
223
235
  });
@@ -44,6 +44,12 @@ let RadioInput = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle,
44
44
  this.ref = null;
45
45
  this._defaultId = void 0;
46
46
  this._input = null;
47
+ this.handleInputRef = el => {
48
+ this._input = el;
49
+ if (typeof this.props.inputRef === 'function') {
50
+ this.props.inputRef(el);
51
+ }
52
+ };
47
53
  this.handleClick = e => {
48
54
  if (this.props.disabled || this.props.readOnly) {
49
55
  e.preventDefault();
@@ -114,9 +120,7 @@ let RadioInput = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle,
114
120
  children: [_jsx("input", {
115
121
  ...props,
116
122
  id: this.id,
117
- ref: c => {
118
- this._input = c;
119
- },
123
+ ref: this.handleInputRef,
120
124
  value: value,
121
125
  name: name,
122
126
  checked: this.checked,
@@ -36,7 +36,8 @@ const propTypes = {
36
36
  context: PropTypes.oneOf(['success', 'warning', 'danger', 'off']),
37
37
  inline: PropTypes.bool,
38
38
  onClick: PropTypes.func,
39
- onChange: PropTypes.func
39
+ onChange: PropTypes.func,
40
+ inputRef: PropTypes.func
40
41
  };
41
- const allowedProps = ['label', 'value', 'id', 'name', 'checked', 'disabled', 'readOnly', 'variant', 'size', 'context', 'inline', 'onClick', 'onChange'];
42
+ const allowedProps = ['label', 'value', 'id', 'name', 'checked', 'disabled', 'readOnly', 'variant', 'size', 'context', 'inline', 'onClick', 'onChange', 'inputRef'];
42
43
  export { propTypes, allowedProps };
@@ -55,16 +55,28 @@ describe('<RadioInput />', () => {
55
55
  expect(input).toBeInTheDocument();
56
56
  expect(input).toHaveAttribute('type', 'radio');
57
57
  });
58
+ it('should provide an inputRef prop', async () => {
59
+ const inputRef = _vitest.vi.fn();
60
+ const _render2 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
61
+ label: "fake label",
62
+ value: "someValue",
63
+ name: "someName",
64
+ inputRef: inputRef
65
+ })),
66
+ container = _render2.container;
67
+ const input = container.querySelector('input');
68
+ expect(inputRef).toHaveBeenCalledWith(input);
69
+ });
58
70
  describe('events', () => {
59
71
  it('responds to onClick event', async () => {
60
72
  const onClick = _vitest.vi.fn();
61
- const _render2 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
73
+ const _render3 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
62
74
  label: "fake label",
63
75
  value: "someValue",
64
76
  name: "someName",
65
77
  onClick: onClick
66
78
  })),
67
- container = _render2.container;
79
+ container = _render3.container;
68
80
  const input = container.querySelector('input');
69
81
  _userEvent.default.click(input);
70
82
  await (0, _react.waitFor)(() => {
@@ -73,14 +85,14 @@ describe('<RadioInput />', () => {
73
85
  });
74
86
  it('does not respond to onClick event when disabled', async () => {
75
87
  const onClick = _vitest.vi.fn();
76
- const _render3 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
88
+ const _render4 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
77
89
  disabled: true,
78
90
  label: "fake label",
79
91
  value: "someValue",
80
92
  name: "someName",
81
93
  onClick: onClick
82
94
  })),
83
- container = _render3.container;
95
+ container = _render4.container;
84
96
  const input = container.querySelector('input');
85
97
  _react.fireEvent.click(input);
86
98
  await (0, _react.waitFor)(() => {
@@ -90,14 +102,14 @@ describe('<RadioInput />', () => {
90
102
  });
91
103
  it('does not respond to onClick event when readOnly', async () => {
92
104
  const onClick = _vitest.vi.fn();
93
- const _render4 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
105
+ const _render5 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
94
106
  readOnly: true,
95
107
  label: "fake label",
96
108
  value: "someValue",
97
109
  name: "someName",
98
110
  onClick: onClick
99
111
  })),
100
- container = _render4.container;
112
+ container = _render5.container;
101
113
  const input = container.querySelector('input');
102
114
  _react.fireEvent.click(input);
103
115
  await (0, _react.waitFor)(() => {
@@ -107,13 +119,13 @@ describe('<RadioInput />', () => {
107
119
  });
108
120
  it('responds to onChange event', async () => {
109
121
  const onChange = _vitest.vi.fn();
110
- const _render5 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
122
+ const _render6 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
111
123
  label: "fake label",
112
124
  value: "someValue",
113
125
  name: "someName",
114
126
  onChange: onChange
115
127
  })),
116
- container = _render5.container;
128
+ container = _render6.container;
117
129
  const input = container.querySelector('input');
118
130
  _userEvent.default.click(input);
119
131
  await (0, _react.waitFor)(() => {
@@ -122,14 +134,14 @@ describe('<RadioInput />', () => {
122
134
  });
123
135
  it('does not respond to onChange event when disabled', async () => {
124
136
  const onChange = _vitest.vi.fn();
125
- const _render6 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
137
+ const _render7 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
126
138
  disabled: true,
127
139
  label: "fake label",
128
140
  value: "someValue",
129
141
  name: "someName",
130
142
  onChange: onChange
131
143
  })),
132
- container = _render6.container;
144
+ container = _render7.container;
133
145
  const input = container.querySelector('input');
134
146
  _react.fireEvent.click(input);
135
147
  await (0, _react.waitFor)(() => {
@@ -138,14 +150,14 @@ describe('<RadioInput />', () => {
138
150
  });
139
151
  it('does not respond to onChange event when readOnly', async () => {
140
152
  const onChange = _vitest.vi.fn();
141
- const _render7 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
153
+ const _render8 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
142
154
  readOnly: true,
143
155
  label: "fake label",
144
156
  value: "someValue",
145
157
  name: "someName",
146
158
  onChange: onChange
147
159
  })),
148
- container = _render7.container;
160
+ container = _render8.container;
149
161
  const input = container.querySelector('input');
150
162
  _react.fireEvent.click(input);
151
163
  await (0, _react.waitFor)(() => {
@@ -154,13 +166,13 @@ describe('<RadioInput />', () => {
154
166
  });
155
167
  it('responds to onBlur event', async () => {
156
168
  const onBlur = _vitest.vi.fn();
157
- const _render8 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
169
+ const _render9 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
158
170
  label: "fake label",
159
171
  value: "someValue",
160
172
  name: "someName",
161
173
  onBlur: onBlur
162
174
  })),
163
- container = _render8.container;
175
+ container = _render9.container;
164
176
  const input = container.querySelector('input');
165
177
  _react.fireEvent.focusOut(input);
166
178
  await (0, _react.waitFor)(() => {
@@ -169,13 +181,13 @@ describe('<RadioInput />', () => {
169
181
  });
170
182
  it('responds to onFocus event', async () => {
171
183
  const onFocus = _vitest.vi.fn();
172
- const _render9 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
184
+ const _render10 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
173
185
  label: "fake label",
174
186
  value: "someValue",
175
187
  name: "someName",
176
188
  onFocus: onFocus
177
189
  })),
178
- container = _render9.container;
190
+ container = _render10.container;
179
191
  const input = container.querySelector('input');
180
192
  _react.fireEvent.focus(input);
181
193
  await (0, _react.waitFor)(() => {
@@ -183,19 +195,19 @@ describe('<RadioInput />', () => {
183
195
  });
184
196
  });
185
197
  it('sets input to checked when selected', async () => {
186
- const _render10 = (0, _react.render)(_RadioInput2 || (_RadioInput2 = (0, _jsxRuntime.jsx)(_index.RadioInput, {
198
+ const _render11 = (0, _react.render)(_RadioInput2 || (_RadioInput2 = (0, _jsxRuntime.jsx)(_index.RadioInput, {
187
199
  checked: true,
188
200
  label: "fake label",
189
201
  value: "someValue",
190
202
  name: "someName"
191
203
  }))),
192
- container = _render10.container;
204
+ container = _render11.container;
193
205
  const input = container.querySelector('input');
194
206
  expect(input).toHaveAttribute('checked');
195
207
  });
196
208
  it('focuses with the focus helper', async () => {
197
209
  let ref;
198
- const _render11 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
210
+ const _render12 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.RadioInput, {
199
211
  label: "fake label",
200
212
  value: "someValue",
201
213
  name: "someName"
@@ -203,7 +215,7 @@ describe('<RadioInput />', () => {
203
215
  ,
204
216
  ref: el => ref = el
205
217
  })),
206
- container = _render11.container;
218
+ container = _render12.container;
207
219
  const input = container.querySelector('input');
208
220
  ref.focus();
209
221
  await (0, _react.waitFor)(() => {
@@ -213,13 +225,13 @@ describe('<RadioInput />', () => {
213
225
  });
214
226
  describe('for a11y', () => {
215
227
  it('simple variant should meet a11y standards', async () => {
216
- const _render12 = (0, _react.render)(_RadioInput3 || (_RadioInput3 = (0, _jsxRuntime.jsx)(_index.RadioInput, {
228
+ const _render13 = (0, _react.render)(_RadioInput3 || (_RadioInput3 = (0, _jsxRuntime.jsx)(_index.RadioInput, {
217
229
  variant: "simple",
218
230
  label: "fake label",
219
231
  value: "someValue",
220
232
  name: "someName"
221
233
  }))),
222
- container = _render12.container;
234
+ container = _render13.container;
223
235
  const axeCheck = await (0, _runAxeCheck.runAxeCheck)(container);
224
236
  expect(axeCheck).toBe(true);
225
237
  });
@@ -50,6 +50,12 @@ let RadioInput = exports.RadioInput = (_dec = (0, _withDeterministicId.withDeter
50
50
  this.ref = null;
51
51
  this._defaultId = void 0;
52
52
  this._input = null;
53
+ this.handleInputRef = el => {
54
+ this._input = el;
55
+ if (typeof this.props.inputRef === 'function') {
56
+ this.props.inputRef(el);
57
+ }
58
+ };
53
59
  this.handleClick = e => {
54
60
  if (this.props.disabled || this.props.readOnly) {
55
61
  e.preventDefault();
@@ -120,9 +126,7 @@ let RadioInput = exports.RadioInput = (_dec = (0, _withDeterministicId.withDeter
120
126
  children: [(0, _jsxRuntime.jsx)("input", {
121
127
  ...props,
122
128
  id: this.id,
123
- ref: c => {
124
- this._input = c;
125
- },
129
+ ref: this.handleInputRef,
126
130
  value: value,
127
131
  name: name,
128
132
  checked: this.checked,
@@ -43,6 +43,7 @@ const propTypes = exports.propTypes = {
43
43
  context: _propTypes.default.oneOf(['success', 'warning', 'danger', 'off']),
44
44
  inline: _propTypes.default.bool,
45
45
  onClick: _propTypes.default.func,
46
- onChange: _propTypes.default.func
46
+ onChange: _propTypes.default.func,
47
+ inputRef: _propTypes.default.func
47
48
  };
48
- const allowedProps = exports.allowedProps = ['label', 'value', 'id', 'name', 'checked', 'disabled', 'readOnly', 'variant', 'size', 'context', 'inline', 'onClick', 'onChange'];
49
+ const allowedProps = exports.allowedProps = ['label', 'value', 'id', 'name', 'checked', 'disabled', 'readOnly', 'variant', 'size', 'context', 'inline', 'onClick', 'onChange', 'inputRef'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-radio-input",
3
- "version": "10.19.2-snapshot-0",
3
+ "version": "10.19.2-snapshot-2",
4
4
  "description": "A styled HTML input type='radio' element",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "module": "./es/index.js",
@@ -24,21 +24,21 @@
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
26
  "@babel/runtime": "^7.26.0",
27
- "@instructure/emotion": "10.19.2-snapshot-0",
28
- "@instructure/shared-types": "10.19.2-snapshot-0",
29
- "@instructure/ui-dom-utils": "10.19.2-snapshot-0",
30
- "@instructure/ui-form-field": "10.19.2-snapshot-0",
31
- "@instructure/ui-prop-types": "10.19.2-snapshot-0",
32
- "@instructure/ui-react-utils": "10.19.2-snapshot-0",
33
- "@instructure/ui-testable": "10.19.2-snapshot-0",
27
+ "@instructure/emotion": "10.19.2-snapshot-2",
28
+ "@instructure/shared-types": "10.19.2-snapshot-2",
29
+ "@instructure/ui-dom-utils": "10.19.2-snapshot-2",
30
+ "@instructure/ui-form-field": "10.19.2-snapshot-2",
31
+ "@instructure/ui-prop-types": "10.19.2-snapshot-2",
32
+ "@instructure/ui-react-utils": "10.19.2-snapshot-2",
33
+ "@instructure/ui-testable": "10.19.2-snapshot-2",
34
34
  "prop-types": "^15.8.1"
35
35
  },
36
36
  "devDependencies": {
37
- "@instructure/ui-axe-check": "10.19.2-snapshot-0",
38
- "@instructure/ui-babel-preset": "10.19.2-snapshot-0",
39
- "@instructure/ui-color-utils": "10.19.2-snapshot-0",
40
- "@instructure/ui-test-utils": "10.19.2-snapshot-0",
41
- "@instructure/ui-themes": "10.19.2-snapshot-0",
37
+ "@instructure/ui-axe-check": "10.19.2-snapshot-2",
38
+ "@instructure/ui-babel-preset": "10.19.2-snapshot-2",
39
+ "@instructure/ui-color-utils": "10.19.2-snapshot-2",
40
+ "@instructure/ui-test-utils": "10.19.2-snapshot-2",
41
+ "@instructure/ui-themes": "10.19.2-snapshot-2",
42
42
  "@testing-library/jest-dom": "^6.6.3",
43
43
  "@testing-library/react": "^16.0.1",
44
44
  "@testing-library/user-event": "^14.5.2",
@@ -61,6 +61,21 @@ describe('<RadioInput />', () => {
61
61
  expect(input).toHaveAttribute('type', 'radio')
62
62
  })
63
63
 
64
+ it('should provide an inputRef prop', async () => {
65
+ const inputRef = vi.fn()
66
+ const { container } = render(
67
+ <RadioInput
68
+ label="fake label"
69
+ value="someValue"
70
+ name="someName"
71
+ inputRef={inputRef}
72
+ />
73
+ )
74
+ const input = container.querySelector('input')
75
+
76
+ expect(inputRef).toHaveBeenCalledWith(input)
77
+ })
78
+
64
79
  describe('events', () => {
65
80
  it('responds to onClick event', async () => {
66
81
  const onClick = vi.fn()
@@ -84,6 +84,13 @@ class RadioInput extends Component<RadioInputProps, RadioInputState> {
84
84
  this.props.makeStyles?.()
85
85
  }
86
86
 
87
+ handleInputRef = (el: HTMLInputElement | null) => {
88
+ this._input = el
89
+ if (typeof this.props.inputRef === 'function') {
90
+ this.props.inputRef(el)
91
+ }
92
+ }
93
+
87
94
  handleClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
88
95
  if (this.props.disabled || this.props.readOnly) {
89
96
  e.preventDefault()
@@ -144,9 +151,7 @@ class RadioInput extends Component<RadioInputProps, RadioInputState> {
144
151
  <input
145
152
  {...props}
146
153
  id={this.id}
147
- ref={(c: HTMLInputElement | null) => {
148
- this._input = c
149
- }}
154
+ ref={this.handleInputRef}
150
155
  value={value}
151
156
  name={name}
152
157
  checked={this.checked}
@@ -72,6 +72,10 @@ type RadioInputOwnProps = {
72
72
  * event.target.value will contain the new value. It will always be a string.
73
73
  */
74
74
  onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
75
+ /**
76
+ * A function that provides a reference to the actual underlying input element
77
+ */
78
+ inputRef?: (inputElement: HTMLInputElement | null) => void
75
79
  }
76
80
 
77
81
  type PropKeys = keyof RadioInputOwnProps
@@ -107,7 +111,8 @@ const propTypes: PropValidators<PropKeys> = {
107
111
  context: PropTypes.oneOf(['success', 'warning', 'danger', 'off']),
108
112
  inline: PropTypes.bool,
109
113
  onClick: PropTypes.func,
110
- onChange: PropTypes.func
114
+ onChange: PropTypes.func,
115
+ inputRef: PropTypes.func
111
116
  }
112
117
 
113
118
  const allowedProps: AllowedPropKeys = [
@@ -123,7 +128,8 @@ const allowedProps: AllowedPropKeys = [
123
128
  'context',
124
129
  'inline',
125
130
  'onClick',
126
- 'onChange'
131
+ 'onChange',
132
+ 'inputRef'
127
133
  ]
128
134
 
129
135
  export type { RadioInputProps, RadioInputState, RadioInputStyle }