@instructure/ui-radio-input 8.13.1-snapshot.9 → 8.14.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.
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  /** @jsx jsx */
26
- import { Component } from 'react'
26
+ import React, { Component } from 'react'
27
27
 
28
28
  import { uid } from '@instructure/uid'
29
29
  import { testable } from '@instructure/ui-testable'
@@ -34,27 +34,25 @@ import { withStyle, jsx } from '@instructure/emotion'
34
34
 
35
35
  import generateStyle from './styles'
36
36
  import generateComponentTheme from './theme'
37
- import type { RadioInputProps } from './props'
37
+
38
+ import type { RadioInputProps, RadioInputState } from './props'
38
39
  import { allowedProps, propTypes } from './props'
39
40
 
40
41
  /**
41
42
  ---
42
43
  category: components
43
44
  ---
45
+ @tsProps
44
46
  **/
45
47
  @withStyle(generateStyle, generateComponentTheme)
46
48
  @testable()
47
- class RadioInput extends Component<RadioInputProps> {
49
+ class RadioInput extends Component<RadioInputProps, RadioInputState> {
48
50
  static readonly componentId = 'RadioInput'
49
51
 
50
52
  static allowedProps = allowedProps
51
53
  static propTypes = propTypes
52
54
 
53
55
  static defaultProps = {
54
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
55
- onClick: function (event) {},
56
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
57
- onChange: function (event) {},
58
56
  variant: 'simple',
59
57
  size: 'medium',
60
58
  disabled: false,
@@ -65,18 +63,18 @@ class RadioInput extends Component<RadioInputProps> {
65
63
 
66
64
  ref: Element | null = null
67
65
 
68
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
69
- constructor(props) {
70
- super(props)
66
+ private readonly _defaultId: string
67
+ private _input: HTMLInputElement | null = null
71
68
 
72
- this.state = {}
69
+ constructor(props: RadioInputProps) {
70
+ super(props)
73
71
 
74
72
  if (typeof props.checked === 'undefined') {
75
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'checked' does not exist on type 'Readonl... Remove this comment to see the full error message
76
- this.state.checked = false
73
+ this.state = {
74
+ checked: false
75
+ }
77
76
  }
78
77
 
79
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_defaultId' does not exist on type 'Radi... Remove this comment to see the full error message
80
78
  this._defaultId = uid('RadioInput')
81
79
  }
82
80
 
@@ -88,52 +86,47 @@ class RadioInput extends Component<RadioInputProps> {
88
86
  this.props.makeStyles?.()
89
87
  }
90
88
 
91
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'e' implicitly has an 'any' type.
92
- handleClick = (e) => {
89
+ handleClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
93
90
  if (this.props.disabled || this.props.readOnly) {
94
91
  e.preventDefault()
95
92
  return
96
93
  }
97
94
 
98
- // @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
99
- this.props.onClick(e)
95
+ if (typeof this.props.onClick === 'function') {
96
+ this.props.onClick(e)
97
+ }
100
98
  }
101
99
 
102
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'e' implicitly has an 'any' type.
103
- handleChange = (e) => {
100
+ handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
104
101
  if (this.props.disabled || this.props.readOnly) {
105
102
  e.preventDefault()
106
103
  return
107
104
  }
108
105
 
109
106
  if (typeof this.props.checked === 'undefined') {
110
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'checked' does not exist on type 'Readonl... Remove this comment to see the full error message
111
107
  this.setState({ checked: !this.state.checked })
112
108
  }
113
109
 
114
- // @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
115
- this.props.onChange(e)
110
+ if (typeof this.props.onChange === 'function') {
111
+ this.props.onChange(e)
112
+ }
116
113
  }
117
114
 
118
115
  focus() {
119
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_input' does not exist on type 'RadioInp... Remove this comment to see the full error message
120
- this._input.focus()
116
+ this._input?.focus()
121
117
  }
122
118
 
123
119
  get id() {
124
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_defaultId' does not exist on type 'Radi... Remove this comment to see the full error message
125
120
  return this.props.id || this._defaultId
126
121
  }
127
122
 
128
123
  get focused() {
129
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_input' does not exist on type 'RadioInp... Remove this comment to see the full error message
130
124
  return isActiveElement(this._input)
131
125
  }
132
126
 
133
127
  get checked() {
134
128
  return typeof this.props.checked === 'undefined'
135
- ? // @ts-expect-error ts-migrate(2339) FIXME: Property 'checked' does not exist on type 'Readonl... Remove this comment to see the full error message
136
- this.state.checked
129
+ ? this.state.checked
137
130
  : this.props.checked
138
131
  }
139
132
 
@@ -152,8 +145,7 @@ class RadioInput extends Component<RadioInputProps> {
152
145
  <input
153
146
  {...props}
154
147
  id={this.id}
155
- ref={(c) => {
156
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_input' does not exist on type 'RadioInp... Remove this comment to see the full error message
148
+ ref={(c: HTMLInputElement | null) => {
157
149
  this._input = c
158
150
  }}
159
151
  value={value}
@@ -21,15 +21,17 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
+
25
+ import React from 'react'
24
26
  import PropTypes from 'prop-types'
25
27
 
28
+ import type { InputHTMLAttributes } from 'react'
26
29
  import type {
27
30
  OtherHTMLAttributes,
28
31
  PropValidators,
29
32
  RadioInputTheme
30
33
  } from '@instructure/shared-types'
31
34
  import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
32
- import { InputHTMLAttributes } from 'react'
33
35
 
34
36
  type RadioInputOwnProps = {
35
37
  label: React.ReactNode
@@ -37,14 +39,20 @@ type RadioInputOwnProps = {
37
39
  id?: string
38
40
  name?: string
39
41
  checked?: boolean
42
+ /**
43
+ * Whether or not to disable the input
44
+ */
40
45
  disabled?: boolean
46
+ /**
47
+ * Works just like disabled but keeps the same styles as if it were active
48
+ */
41
49
  readOnly?: boolean
42
50
  variant?: 'simple' | 'toggle'
43
51
  size?: 'small' | 'medium' | 'large'
44
52
  context?: 'success' | 'warning' | 'danger' | 'off'
45
53
  inline?: boolean
46
- onClick?: (...args: any[]) => any
47
- onChange?: (...args: any[]) => any
54
+ onClick?: (event: React.MouseEvent<HTMLInputElement>) => void
55
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
48
56
  }
49
57
 
50
58
  type PropKeys = keyof RadioInputOwnProps
@@ -62,19 +70,17 @@ type RadioInputStyle = ComponentStyle<
62
70
  'radioInput' | 'input' | 'control' | 'facade' | 'label'
63
71
  >
64
72
 
73
+ type RadioInputState = {
74
+ checked?: boolean
75
+ }
76
+
65
77
  const propTypes: PropValidators<PropKeys> = {
66
78
  label: PropTypes.node.isRequired,
67
79
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
68
80
  id: PropTypes.string,
69
81
  name: PropTypes.string,
70
82
  checked: PropTypes.bool,
71
- /**
72
- * Whether or not to disable the input
73
- */
74
83
  disabled: PropTypes.bool,
75
- /**
76
- * Works just like disabled but keeps the same styles as if it were active
77
- */
78
84
  readOnly: PropTypes.bool,
79
85
  variant: PropTypes.oneOf(['simple', 'toggle']),
80
86
  size: PropTypes.oneOf(['small', 'medium', 'large']),
@@ -100,5 +106,5 @@ const allowedProps: AllowedPropKeys = [
100
106
  'onChange'
101
107
  ]
102
108
 
103
- export type { RadioInputProps, RadioInputStyle }
109
+ export type { RadioInputProps, RadioInputState, RadioInputStyle }
104
110
  export { propTypes, allowedProps }
@@ -22,7 +22,7 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- import React, { Children, Component, ReactElement } from 'react'
25
+ import React, { Children, Component } from 'react'
26
26
 
27
27
  import { FormFieldGroup } from '@instructure/ui-form-field'
28
28
  import { uid } from '@instructure/uid'
@@ -35,16 +35,24 @@ import {
35
35
  } from '@instructure/ui-react-utils'
36
36
 
37
37
  import { RadioInput } from '../RadioInput'
38
- import type { RadioInputGroupProps } from './props'
38
+ import type { RadioInputProps } from '../RadioInput/props'
39
+
40
+ import type { RadioInputGroupProps, RadioInputGroupState } from './props'
39
41
  import { allowedProps, propTypes } from './props'
40
42
 
43
+ type RadioInputChild = React.ComponentElement<RadioInputProps, RadioInput>
44
+
41
45
  /**
42
46
  ---
43
47
  category: components
44
48
  ---
49
+ @tsProps
45
50
  **/
46
51
  @testable()
47
- class RadioInputGroup extends Component<RadioInputGroupProps> {
52
+ class RadioInputGroup extends Component<
53
+ RadioInputGroupProps,
54
+ RadioInputGroupState
55
+ > {
48
56
  static readonly componentId = 'RadioInputGroup'
49
57
 
50
58
  static allowedProps = allowedProps
@@ -55,20 +63,19 @@ class RadioInputGroup extends Component<RadioInputGroupProps> {
55
63
  variant: 'simple',
56
64
  size: 'medium',
57
65
  layout: 'stacked',
58
- readOnly: false,
59
- children: null
66
+ readOnly: false
60
67
  }
61
68
 
62
69
  ref: Element | null = null
63
70
 
71
+ private readonly _messagesId: string
72
+
64
73
  handleRef = (el: Element | null) => {
65
74
  this.ref = el
66
75
  }
67
76
 
68
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
69
- constructor(props) {
70
- // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.
71
- super()
77
+ constructor(props: RadioInputGroupProps) {
78
+ super(props)
72
79
 
73
80
  if (typeof props.value === 'undefined') {
74
81
  this.state = {
@@ -76,16 +83,14 @@ class RadioInputGroup extends Component<RadioInputGroupProps> {
76
83
  }
77
84
  }
78
85
 
79
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_messagesId' does not exist on type 'Rad... Remove this comment to see the full error message
80
86
  this._messagesId = uid('RadioInputGroup-messages')
81
87
  }
82
88
 
83
89
  get hasMessages() {
84
- return this.props.messages && this.props.messages.length > 0
90
+ return !!this.props.messages && this.props.messages.length > 0
85
91
  }
86
92
 
87
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'e' implicitly has an 'any' type.
88
- handleChange = (e) => {
93
+ handleChange: RadioInputProps['onChange'] = (e) => {
89
94
  const value = e.target.value
90
95
 
91
96
  if (this.props.disabled || this.props.readOnly) {
@@ -104,8 +109,7 @@ class RadioInputGroup extends Component<RadioInputGroupProps> {
104
109
 
105
110
  get value() {
106
111
  return typeof this.props.value === 'undefined'
107
- ? // @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'Readonly<... Remove this comment to see the full error message
108
- this.state.value
112
+ ? this.state.value
109
113
  : this.props.value
110
114
  }
111
115
 
@@ -115,28 +119,24 @@ class RadioInputGroup extends Component<RadioInputGroupProps> {
115
119
  // This adds the passed in name property to each RadioInput component
116
120
  // and checks the input whose value matches the value property
117
121
  return Children.map(children, (child, index) => {
118
- if (matchComponentTypes(child, [RadioInput])) {
119
- // @ts-expect-error ts-migrate(2533) FIXME: Object is possibly 'null' or 'undefined'.
120
- const isChecked = this.value === child.props.value
122
+ if (matchComponentTypes(child as RadioInputChild, [RadioInput])) {
123
+ const isChecked = this.value === (child as RadioInput).props.value
121
124
  const defaultFocus = !this.value && index === 0
122
- return safeCloneElement(child as ReactElement, {
125
+ return safeCloneElement(child as RadioInputChild, {
123
126
  name,
124
- // @ts-expect-error ts-migrate(2533) FIXME: Object is possibly 'null' or 'undefined'.
125
- disabled: disabled || child.props.disabled,
127
+ disabled: disabled || (child as RadioInputChild).props.disabled,
126
128
  variant,
127
129
  size,
128
130
  checked: isChecked,
129
131
  onChange: this.handleChange,
130
- // @ts-expect-error ts-migrate(2533) FIXME: Object is possibly 'null' or 'undefined'.
131
- readOnly: readOnly || child.props.readOnly,
132
- // @ts-expect-error ts-migrate(2533) FIXME: Object is possibly 'null' or 'undefined'.
133
- width: child.props.width || 'auto',
134
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_messagesId' does not exist on type 'Rad... Remove this comment to see the full error message
135
- 'aria-describedby': this.hasMessages && this._messagesId,
132
+ readOnly: readOnly || (child as RadioInputChild).props.readOnly,
133
+ width: (child as RadioInputChild).props.width || 'auto',
134
+ 'aria-describedby': this.hasMessages ? this._messagesId : undefined,
136
135
  // only one radio in a group should be considered tabbable
137
136
  // if a radio is checked, it should be the input to receive focus when tabbed to
138
137
  // if none of the inputs are checked, the first should receive the focus
139
- tabIndex: isChecked || defaultFocus ? '0' : '-1'
138
+ tabIndex: isChecked || defaultFocus ? 0 : -1,
139
+ label: (child as RadioInputChild).props.label
140
140
  })
141
141
  } else {
142
142
  return child // ignore (but preserve) children that aren't RadioInput
@@ -145,13 +145,13 @@ class RadioInputGroup extends Component<RadioInputGroupProps> {
145
145
  }
146
146
 
147
147
  render() {
148
- const { variant, layout } = this.props
148
+ const { variant, layout, description } = this.props
149
149
 
150
150
  return (
151
- // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
152
151
  <FormFieldGroup
153
152
  {...omitProps(this.props, RadioInputGroup.allowedProps)}
154
153
  {...pickProps(this.props, FormFieldGroup.allowedProps)}
154
+ description={description}
155
155
  // TODO: split out toggle variant into its own component
156
156
  layout={
157
157
  layout === 'columns' && variant === 'toggle' ? 'stacked' : layout
@@ -160,7 +160,6 @@ class RadioInputGroup extends Component<RadioInputGroupProps> {
160
160
  rowSpacing="small"
161
161
  colSpacing={variant === 'toggle' ? 'none' : 'small'} // keep toggles close together
162
162
  startAt={variant === 'toggle' ? 'small' : undefined}
163
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_messagesId' does not exist on type 'Rad... Remove this comment to see the full error message
164
163
  messagesId={this._messagesId}
165
164
  elementRef={this.handleRef}
166
165
  >
@@ -36,16 +36,48 @@ import type {
36
36
 
37
37
  type RadioInputGroupOwnProps = {
38
38
  name: string
39
+
39
40
  description: React.ReactNode
41
+
42
+ /**
43
+ * value to set on initial render
44
+ */
40
45
  defaultValue?: string | number
41
- value?: any // TODO: controllable( PropTypes.oneOfType([PropTypes.string, PropTypes.number]) )
42
- onChange?: (...args: any[]) => any
46
+
47
+ /**
48
+ * the selected value (must be accompanied by an `onChange` prop)
49
+ */
50
+ value?: string | number // TODO: controllable( PropTypes.oneOfType([PropTypes.string, PropTypes.number]) )
51
+
52
+ /**
53
+ * when used with the `value` prop, the component will not control its own state
54
+ */
55
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>, value: string) => void
56
+
43
57
  disabled?: boolean
58
+
59
+ /**
60
+ * works just like disabled but keeps the same styles as if it were active
61
+ */
44
62
  readOnly?: boolean
63
+
64
+ /**
65
+ * Array of objects with shape: `{
66
+ * text: ReactNode,
67
+ * type: One of: ['error', 'hint', 'success', 'screenreader-only']
68
+ * }`
69
+ */
45
70
  messages?: FormMessage[]
46
- variant?: 'simple' | 'toggle'
71
+
72
+ variant?: 'simple' | 'toggle' // TODO: split toggle out to its own component
73
+
47
74
  size?: 'small' | 'medium' | 'large'
75
+
48
76
  layout?: 'stacked' | 'columns' | 'inline'
77
+
78
+ /**
79
+ * any children (ones that aren't `RadioInput` are passed through)
80
+ */
49
81
  children?: React.ReactNode
50
82
  }
51
83
 
@@ -56,38 +88,23 @@ type AllowedPropKeys = Readonly<Array<PropKeys>>
56
88
  type RadioInputGroupProps = RadioInputGroupOwnProps &
57
89
  OtherHTMLAttributes<RadioInputGroupOwnProps>
58
90
 
91
+ type RadioInputGroupState = {
92
+ value?: string | number
93
+ }
94
+
59
95
  const propTypes: PropValidators<PropKeys> = {
60
96
  name: PropTypes.string.isRequired,
61
97
  description: PropTypes.node.isRequired,
62
- /**
63
- * value to set on initial render
64
- */
65
98
  defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
66
- /**
67
- * the selected value (must be accompanied by an `onChange` prop)
68
- */
69
99
  value: controllable(
70
100
  PropTypes.oneOfType([PropTypes.string, PropTypes.number])
71
101
  ),
72
- /**
73
- * when used with the `value` prop, the component will not control its own state
74
- */
75
102
  onChange: PropTypes.func,
76
103
  disabled: PropTypes.bool,
77
- /** works just like disabled but keeps the same styles as if it were active */
78
104
  readOnly: PropTypes.bool,
79
- /**
80
- * object with shape: `{
81
- * text: PropTypes.node,
82
- * type: PropTypes.oneOf(['error', 'hint', 'success', 'screenreader-only'])
83
- * }`
84
- */
85
105
  messages: PropTypes.arrayOf(FormPropTypes.message),
86
- /**
87
- * any children (ones that aren't `RadioInput` are passed through)
88
- */
89
106
  children: PropTypes.node,
90
- variant: PropTypes.oneOf(['simple', 'toggle']), // TODO: split toggle out to its own component
107
+ variant: PropTypes.oneOf(['simple', 'toggle']),
91
108
  size: PropTypes.oneOf(['small', 'medium', 'large']),
92
109
  layout: PropTypes.oneOf(['stacked', 'columns', 'inline'])
93
110
  }
@@ -107,5 +124,5 @@ const allowedProps: AllowedPropKeys = [
107
124
  'layout'
108
125
  ]
109
126
 
110
- export type { RadioInputGroupProps }
127
+ export type { RadioInputGroupProps, RadioInputGroupState }
111
128
  export { propTypes, allowedProps }
@@ -1,7 +1,24 @@
1
1
  {
2
2
  "extends": "../../tsconfig.build.json",
3
3
  "compilerOptions": {
4
- "outDir": "./types"
4
+ "outDir": "./types",
5
+ "rootDir": "./src",
6
+ "composite": true
5
7
  },
6
- "include": ["src/**/*"]
8
+ "include": ["src"],
9
+ "references": [
10
+ { "path": "../emotion/tsconfig.build.json" },
11
+ { "path": "../shared-types/tsconfig.build.json" },
12
+ { "path": "../ui-dom-utils/tsconfig.build.json" },
13
+ { "path": "../ui-form-field/tsconfig.build.json" },
14
+ { "path": "../ui-prop-types/tsconfig.build.json" },
15
+ { "path": "../ui-react-utils/tsconfig.build.json" },
16
+ { "path": "../ui-testable/tsconfig.build.json" },
17
+ { "path": "../uid/tsconfig.build.json" },
18
+ { "path": "../ui-babel-preset/tsconfig.build.json" },
19
+ { "path": "../ui-color-utils/tsconfig.build.json" },
20
+ { "path": "../ui-test-locator/tsconfig.build.json" },
21
+ { "path": "../ui-test-utils/tsconfig.build.json" },
22
+ { "path": "../ui-themes/tsconfig.build.json" }
23
+ ]
7
24
  }