@instructure/ui-editable 8.25.1-snapshot.0 → 8.26.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.
@@ -21,20 +21,26 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
- import { Component } from 'react'
24
+ import React, { Component } from 'react'
25
25
 
26
26
  import { deepEqual } from '@instructure/ui-utils'
27
27
  import { logWarn as warn } from '@instructure/console'
28
28
  import { requestAnimationFrame } from '@instructure/ui-dom-utils'
29
29
 
30
- import { propTypes, allowedProps } from './props'
31
- import type { EditableProps } from './props'
30
+ import { propTypes, allowedProps, EditableState } from './props'
31
+ import type {
32
+ EditableProps,
33
+ GetContainerProps,
34
+ GetEditButtonProps,
35
+ GetEditorProps,
36
+ GetViewerProps
37
+ } from './props'
32
38
 
33
39
  /**
34
40
  ---
35
41
  category: components
36
- experimental: true
37
42
  ---
43
+ @tsProps
38
44
  **/
39
45
  class Editable extends Component<EditableProps> {
40
46
  static propTypes = propTypes
@@ -44,16 +50,15 @@ class Editable extends Component<EditableProps> {
44
50
  children: null
45
51
  }
46
52
 
47
- state = {
53
+ state: EditableState = {
48
54
  showModeToggle: false,
49
55
  valueOnEdit: null // the value when mode flips from view -> edit
50
56
  }
51
57
 
52
- _editorRef = null
53
- _editButtonRef = null
58
+ _editorRef: HTMLInputElement | null = null
59
+ _editButtonRef: HTMLButtonElement | null = null
54
60
 
55
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
56
- constructor(props) {
61
+ constructor(props: EditableProps) {
57
62
  super(props)
58
63
 
59
64
  warn(
@@ -67,10 +72,8 @@ class Editable extends Component<EditableProps> {
67
72
  this.focusEditor()
68
73
  }
69
74
  }
70
- componentWillUnmount() {}
71
75
 
72
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'prevProps' implicitly has an 'any' type... Remove this comment to see the full error message
73
- componentDidUpdate(prevProps) {
76
+ componentDidUpdate(prevProps: EditableProps) {
74
77
  const { mode, value, onChange } = this.props
75
78
 
76
79
  // on the switch from view -> edit
@@ -81,7 +84,6 @@ class Editable extends Component<EditableProps> {
81
84
 
82
85
  // on the switch from edit to view
83
86
  if (prevProps.mode === 'edit' && mode !== 'edit') {
84
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
85
87
  this._editButtonRef && this._editButtonRef.focus()
86
88
  if (onChange && !deepEqual(this.state.valueOnEdit, value)) {
87
89
  onChange(value)
@@ -95,7 +97,6 @@ class Editable extends Component<EditableProps> {
95
97
  '[Editable] Did you forget to connect editorRef to your editor component?'
96
98
  )
97
99
  if (this._editorRef) {
98
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
99
100
  this._editorRef.focus()
100
101
  }
101
102
  }
@@ -116,15 +117,13 @@ class Editable extends Component<EditableProps> {
116
117
  }
117
118
  }
118
119
 
119
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
120
- handleEditESC = (event) => {
120
+ handleEditESC = (event: React.KeyboardEvent) => {
121
121
  if (event.key === 'Escape') {
122
122
  this.enterView()
123
123
  }
124
124
  }
125
125
 
126
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
127
- handleViewMouseOver = (event) => {
126
+ handleViewMouseOver = (event: React.MouseEvent) => {
128
127
  if (this.props.mode === 'view') {
129
128
  // because the mouse event handlers are on the container, not the view
130
129
  event.stopPropagation()
@@ -132,8 +131,7 @@ class Editable extends Component<EditableProps> {
132
131
  }
133
132
  }
134
133
 
135
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
136
- handleViewMouseOut = (event) => {
134
+ handleViewMouseOut = (event: React.MouseEvent) => {
137
135
  if (this.props.mode === 'view') {
138
136
  event.stopPropagation()
139
137
  this.setState({
@@ -142,8 +140,7 @@ class Editable extends Component<EditableProps> {
142
140
  }
143
141
  }
144
142
 
145
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
146
- handleViewClick = (event) => {
143
+ handleViewClick = (event: React.MouseEvent) => {
147
144
  if (event.buttons === 1) {
148
145
  requestAnimationFrame(() => {
149
146
  this.enterEdit()
@@ -151,23 +148,19 @@ class Editable extends Component<EditableProps> {
151
148
  }
152
149
  }
153
150
 
154
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
155
- handleEditBlur = (event) => {
151
+ handleEditBlur = () => {
156
152
  this.enterView()
157
153
  }
158
154
 
159
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
160
- handleEditButtonFocus = (event) => {
155
+ handleEditButtonFocus = () => {
161
156
  this.setState({ showModeToggle: true })
162
157
  }
163
158
 
164
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
165
- handleEditButtonBlur = (event) => {
159
+ handleEditButtonBlur = () => {
166
160
  this.setState({ showModeToggle: false })
167
161
  }
168
162
 
169
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
170
- handleEditButtonClick = (event) => {
163
+ handleEditButtonClick = () => {
171
164
  this.enterEdit()
172
165
  }
173
166
 
@@ -184,20 +177,20 @@ class Editable extends Component<EditableProps> {
184
177
  }
185
178
 
186
179
  // ------- prop getters ------
187
- getContainerProps = (props = {}) => {
180
+ getContainerProps: GetContainerProps = (props = {}) => {
188
181
  const { mode, readOnly } = this.props
189
182
  return {
190
183
  onMouseOver: this.handleViewMouseOver,
191
184
  onMouseOut: this.handleViewMouseOut,
192
- onMouseDown: mode !== 'edit' ? this.handleViewClick : null,
193
- onKeyUp: mode === 'edit' ? this.handleEditESC : null,
185
+ onMouseDown: mode !== 'edit' ? this.handleViewClick : undefined,
186
+ onKeyUp: mode === 'edit' ? this.handleEditESC : undefined,
194
187
  readOnly,
195
188
  ...props,
196
189
  ref: this.handleContainerRef
197
190
  }
198
191
  }
199
192
 
200
- getViewerProps = (props = {}) => {
193
+ getViewerProps: GetViewerProps = (props = {}) => {
201
194
  return {
202
195
  mode: this.props.mode,
203
196
  readOnly: this.props.readOnly,
@@ -205,29 +198,26 @@ class Editable extends Component<EditableProps> {
205
198
  }
206
199
  }
207
200
 
208
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
209
- getEditorProps = (props) => {
201
+ getEditorProps: GetEditorProps = (props = {}) => {
210
202
  return {
211
203
  mode: this.props.mode,
212
204
  onBlur: this.handleEditBlur,
213
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'el' implicitly has an 'any' type.
214
- editorRef: (el) => {
215
- this._editorRef = el
205
+ editorRef: (el: HTMLElement | null) => {
206
+ this._editorRef = el as HTMLInputElement
216
207
  },
217
208
  readOnly: this.props.readOnly,
218
209
  ...props
219
210
  }
220
211
  }
221
212
 
222
- getEditButtonProps = (props = {}) => {
213
+ getEditButtonProps: GetEditButtonProps = (props = {}) => {
223
214
  return {
224
215
  onClick: this.handleEditButtonClick,
225
216
  onFocus: this.handleEditButtonFocus,
226
217
  onBlur: this.handleEditButtonBlur,
227
218
  isVisible: this.state.showModeToggle,
228
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'el' implicitly has an 'any' type.
229
- buttonRef: (el) => {
230
- this._editButtonRef = el
219
+ buttonRef: (el: Element) => {
220
+ this._editButtonRef = el as HTMLButtonElement
231
221
  },
232
222
  readOnly: this.props.readOnly,
233
223
  ...props
@@ -21,71 +21,106 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
-
24
+ import React from 'react'
25
25
  import PropTypes from 'prop-types'
26
26
 
27
27
  import type { PropValidators } from '@instructure/shared-types'
28
28
 
29
- type EditableOwnProps = {
29
+ type GetContainerProps = (props?: Record<string, any>) => {
30
+ ref: React.RefCallback<any>
31
+ onMouseOver: (event: React.MouseEvent) => void
32
+ onMouseOut: (event: React.MouseEvent) => void
33
+ onMouseDown?: (event: React.MouseEvent) => void
34
+ onKeyUp?: (event: React.KeyboardEvent) => void
35
+ readOnly?: boolean
36
+ } & Record<string, any>
37
+
38
+ type GetViewerProps = (props?: Record<string, any>) => {
30
39
  mode: 'view' | 'edit'
31
- onChangeMode: (...args: any[]) => any
32
- children?: (...args: any[]) => any
33
- render?: (...args: any[]) => any
34
- value?: any
35
- onChange?: (...args: any[]) => any
36
40
  readOnly?: boolean
37
- elementRef?: (element: Element | null) => void
38
- }
41
+ } & Record<string, any>
39
42
 
40
- type PropKeys = keyof EditableOwnProps
43
+ type GetEditorProps = (props?: Record<string, any>) => {
44
+ mode: 'view' | 'edit'
45
+ onBlur: () => void
46
+ editorRef: (el: HTMLElement | null) => void
47
+ readOnly?: boolean
48
+ } & Record<string, any>
41
49
 
42
- type AllowedPropKeys = Readonly<Array<PropKeys>>
50
+ type GetEditButtonProps = (props?: Record<string, any>) => {
51
+ onClick: () => void
52
+ onFocus: () => void
53
+ onBlur: () => void
54
+ isVisible: boolean
55
+ buttonRef: (el: Element) => void
56
+ readOnly?: boolean
57
+ } & Record<string, any>
43
58
 
44
- type EditableProps = EditableOwnProps
59
+ type EditableRenderProps = {
60
+ mode: string
61
+ getContainerProps: GetContainerProps
62
+ getViewerProps: GetViewerProps
63
+ getEditorProps: GetEditorProps
64
+ getEditButtonProps: GetEditButtonProps
65
+ }
45
66
 
46
- const propTypes: PropValidators<PropKeys> = {
67
+ type EditableOwnProps = {
47
68
  /**
48
69
  * If `'view'`: the view component is rendered,
49
70
  * if `'edit'`: the edit component is rendered
50
71
  */
51
- mode: PropTypes.oneOf(['view', 'edit']).isRequired,
72
+ mode: 'view' | 'edit'
52
73
  /**
53
- * Called when the component's mode changes
54
- * @param {string} new_mode
74
+ * Called when the component's mode changes.
55
75
  */
56
- onChangeMode: PropTypes.func.isRequired,
57
-
76
+ onChangeMode: (newMode: string) => void
58
77
  /**
59
- * @param {Object} renderProps
60
- * @param {Boolean} mode
61
- * @param {Function} renderProps.getContainerProps - Props to be spread onto the container element
62
- * @param {Function} renderProps.getEditorProps - Props to be spread onto the editor element
63
- * @param {Function} renderProps.getEditButtonProps - Props to be spread onto the edit button element
78
+ * Function that you can supply that will return the children of this component.
79
+ * It has one parameter has the following fields:
80
+ * - mode: `view` or `edit`, depending on whether the view or the editor should be rendered.
81
+ * - getContainerProps(props) - Props to be spread onto the container element
82
+ * - getEditorProps(props) - Props to be spread onto the editor element
83
+ * - getEditButtonProps(props) - Props to be spread onto the edit button element
64
84
  */
65
- children: PropTypes.func,
85
+ children?: (props: EditableRenderProps) => React.ReactNode
66
86
  /**
67
87
  * Identical to children
68
88
  */
69
- render: PropTypes.func,
70
-
89
+ render?: (props: EditableRenderProps) => React.ReactNode
71
90
  /**
72
91
  * The current value.
73
92
  * The value is managed by the consuming app, but we need to tell Editable
74
93
  * it's changed or it won't re-render
75
94
  */
76
- value: PropTypes.any,
95
+ value?: any
77
96
  /**
78
97
  * Called when Editable switches from edit to view mode and the value has changed.
79
- * @param {any} value
80
98
  */
81
- onChange: PropTypes.func,
99
+ onChange?: (value: any) => void
82
100
  /**
83
101
  * The mode is fixed as 'view'
84
102
  */
85
- readOnly: PropTypes.bool,
103
+ readOnly?: boolean
86
104
  /**
87
105
  * provides a reference to the underlying html root element (container)
88
106
  */
107
+ elementRef?: (element: Element | null) => void
108
+ }
109
+
110
+ type PropKeys = keyof EditableOwnProps
111
+
112
+ type AllowedPropKeys = Readonly<Array<PropKeys>>
113
+
114
+ type EditableProps = EditableOwnProps
115
+
116
+ const propTypes: PropValidators<PropKeys> = {
117
+ mode: PropTypes.oneOf(['view', 'edit']).isRequired,
118
+ onChangeMode: PropTypes.func.isRequired,
119
+ children: PropTypes.func,
120
+ render: PropTypes.func,
121
+ value: PropTypes.any,
122
+ onChange: PropTypes.func,
123
+ readOnly: PropTypes.bool,
89
124
  elementRef: PropTypes.func
90
125
  }
91
126
 
@@ -100,5 +135,17 @@ const allowedProps: AllowedPropKeys = [
100
135
  'elementRef'
101
136
  ]
102
137
 
103
- export type { EditableProps }
138
+ type EditableState = {
139
+ showModeToggle: boolean
140
+ valueOnEdit: any
141
+ }
142
+ export type {
143
+ EditableProps,
144
+ EditableRenderProps,
145
+ EditableState,
146
+ GetContainerProps,
147
+ GetEditButtonProps,
148
+ GetEditorProps,
149
+ GetViewerProps
150
+ }
104
151
  export { propTypes, allowedProps }
@@ -27,6 +27,7 @@ import { Component } from 'react'
27
27
 
28
28
  import { Flex } from '@instructure/ui-flex'
29
29
  import { IconButton } from '@instructure/ui-buttons'
30
+ import type { IconButtonProps } from '@instructure/ui-buttons'
30
31
  import { IconEditLine } from '@instructure/ui-icons'
31
32
  import { logWarn as warn } from '@instructure/console'
32
33
  import { createChainedFunction } from '@instructure/ui-utils'
@@ -38,11 +39,13 @@ import generateStyle from './styles'
38
39
 
39
40
  import { propTypes, allowedProps } from './props'
40
41
  import type { InPlaceEditProps } from './props'
42
+ import type { EditableRenderProps } from '../Editable/props'
41
43
 
42
44
  /**
43
45
  ---
44
46
  category: components
45
47
  ---
48
+ @tsProps
46
49
  **/
47
50
  @withStyle(generateStyle, null)
48
51
  class InPlaceEdit extends Component<InPlaceEditProps> {
@@ -57,13 +60,13 @@ class InPlaceEdit extends Component<InPlaceEditProps> {
57
60
  }
58
61
 
59
62
  ref: Element | null = null
63
+ _editButtonRef: HTMLButtonElement | null = null
60
64
 
61
65
  handleRef = (el: Element | null) => {
62
66
  this.ref = el
63
67
  }
64
68
 
65
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
66
- constructor(props) {
69
+ constructor(props: InPlaceEditProps) {
67
70
  super(props)
68
71
 
69
72
  warn(
@@ -73,24 +76,23 @@ class InPlaceEdit extends Component<InPlaceEditProps> {
73
76
  }
74
77
 
75
78
  componentDidMount() {
76
- // @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
77
- this.props.makeStyles()
79
+ this.props.makeStyles?.()
78
80
  }
79
81
 
80
- // @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
81
- componentDidUpdate(prevProps, prevState, snapshot) {
82
- // @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
83
- this.props.makeStyles()
82
+ componentDidUpdate() {
83
+ this.props.makeStyles?.()
84
84
  }
85
85
 
86
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'el' implicitly has an 'any' type.
87
- handleEditButtonRef = (el) => {
88
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_editButtonRef' does not exist on type '... Remove this comment to see the full error message
86
+ handleEditButtonRef = (el: HTMLButtonElement) => {
89
87
  this._editButtonRef = el
90
88
  }
91
89
 
92
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'mode' implicitly has an 'any' typ... Remove this comment to see the full error message
93
- renderEditor({ mode, onBlur, editorRef, readOnly }) {
90
+ renderEditor({
91
+ mode,
92
+ onBlur,
93
+ editorRef,
94
+ readOnly
95
+ }: ReturnType<EditableRenderProps['getEditorProps']>) {
94
96
  const { showFocusRing, renderEditor } = this.props
95
97
  const isEditMode = !readOnly && mode === 'edit'
96
98
 
@@ -109,13 +111,17 @@ class InPlaceEdit extends Component<InPlaceEditProps> {
109
111
  ) : null
110
112
  }
111
113
 
112
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'readOnly' implicitly has an 'any'... Remove this comment to see the full error message
113
- renderViewer({ readOnly, mode }) {
114
+ renderViewer({
115
+ readOnly,
116
+ mode
117
+ }: ReturnType<EditableRenderProps['getViewerProps']>) {
114
118
  return readOnly || mode === 'view' ? this.props.renderViewer() : null
115
119
  }
116
120
 
117
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'buttonRef' implicitly has an 'any... Remove this comment to see the full error message
118
- renderEditButton({ buttonRef, ...rest }) {
121
+ renderEditButton({
122
+ buttonRef,
123
+ ...rest
124
+ }: ReturnType<EditableRenderProps['getEditButtonProps']>) {
119
125
  return this.props.renderEditButton({
120
126
  elementRef: createChainedFunction(this.handleEditButtonRef, buttonRef),
121
127
  ...rest
@@ -125,14 +131,15 @@ class InPlaceEdit extends Component<InPlaceEditProps> {
125
131
  // Render a default edit button, an icon button with the edit icon
126
132
  // the margin makes room for the focus ring
127
133
  static renderDefaultEditButton = ({
128
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'isVisible' implicitly has an 'any... Remove this comment to see the full error message
129
134
  isVisible,
130
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'readOnly' implicitly has an 'any'... Remove this comment to see the full error message
131
135
  readOnly,
132
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'label' implicitly has an 'any' ty... Remove this comment to see the full error message
133
136
  label,
134
137
  ...buttonProps
135
- }) => {
138
+ }: {
139
+ isVisible: boolean
140
+ readOnly?: boolean
141
+ label: string
142
+ } & Partial<IconButtonProps>) => {
136
143
  if (readOnly) {
137
144
  return null
138
145
  }
@@ -150,15 +157,11 @@ class InPlaceEdit extends Component<InPlaceEditProps> {
150
157
  }
151
158
 
152
159
  renderAll = ({
153
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'getContainerProps' implicitly has... Remove this comment to see the full error message
154
160
  getContainerProps,
155
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'getViewerProps' implicitly has an... Remove this comment to see the full error message
156
161
  getViewerProps,
157
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'getEditorProps' implicitly has an... Remove this comment to see the full error message
158
162
  getEditorProps,
159
- // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'getEditButtonProps' implicitly ha... Remove this comment to see the full error message
160
163
  getEditButtonProps
161
- }) => {
164
+ }: EditableRenderProps) => {
162
165
  const flexDir =
163
166
  this.props.editButtonPlacement === 'start' ? 'row-reverse' : 'row'
164
167
  const justifyItems = flexDir === 'row-reverse' ? 'end' : 'start'
@@ -26,39 +26,28 @@ import PropTypes from 'prop-types'
26
26
 
27
27
  import type { PropValidators } from '@instructure/shared-types'
28
28
  import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
29
+ import type { EditableProps } from '../Editable/props'
30
+ import React from 'react'
29
31
 
30
- type InPlaceEditOwnProps = {
31
- renderViewer: (...args: any[]) => any
32
- renderEditor: (...args: any[]) => any
33
- renderEditButton: (...args: any[]) => any
34
- mode: 'view' | 'edit'
35
- onChangeMode: (...args: any[]) => any
36
- value?: any
37
- onChange?: (...args: any[]) => any
32
+ type ExtendedRenderEditButton = {
33
+ elementRef?: (el: HTMLButtonElement) => void
34
+ onClick: () => void
35
+ onFocus: () => void
36
+ onBlur: () => void
37
+ isVisible: boolean
38
38
  readOnly?: boolean
39
- showFocusRing?: boolean
40
- editButtonPlacement?: 'start' | 'end'
41
- inline?: boolean
42
39
  }
43
40
 
44
- type PropKeys = keyof InPlaceEditOwnProps
45
-
46
- type AllowedPropKeys = Readonly<Array<PropKeys>>
47
-
48
- type InPlaceEditProps = InPlaceEditOwnProps &
49
- WithStyleProps<null, InPlaceEditStyle>
50
-
51
- type InPlaceEditStyle = ComponentStyle<'inPlaceEdit'>
52
-
53
- const propTypes: PropValidators<PropKeys> = {
41
+ type InPlaceEditOwnProps = {
54
42
  /**
55
43
  * Function to render the view mode component.
56
44
  * It is the consumer's responsibility to provide the
57
45
  * current value or children.
58
46
  *
59
- * @returns {element} the viewer DOM sub-tree.
47
+ * Return value:
48
+ * - element: the viewer DOM sub-tree.
60
49
  */
61
- renderViewer: PropTypes.func.isRequired,
50
+ renderViewer: () => React.ReactNode
62
51
  /**
63
52
  * Function to render the edit mode component
64
53
  * It is the consumer's responsibility to provide the
@@ -66,14 +55,25 @@ const propTypes: PropValidators<PropKeys> = {
66
55
  * event handler needed to capture the updated value. This
67
56
  * new value must then be forwarded to the view mode component.
68
57
  *
69
- * @returns {element} the editor DOM sub-tree.
58
+ * Return value:
59
+ * - element: the editor DOM sub-tree.
70
60
  */
71
- renderEditor: PropTypes.func.isRequired,
61
+ renderEditor: ({
62
+ onBlur,
63
+ editorRef
64
+ }: {
65
+ onBlur: () => void
66
+ editorRef: (el: HTMLElement | null) => void
67
+ }) => React.ReactNode
72
68
  /**
73
69
  * Function to render the edit button.
74
70
  *
75
- * @param {Object} { isVisible, onClick, onFocus, onBlur, buttonRef }
76
- * @returns {element} the edit button DOM sub-tree
71
+ * Parameters:
72
+ * - object: { isVisible, onClick, onFocus, onBlur, buttonRef }
73
+ *
74
+ * Return value:
75
+ *
76
+ * - element: the edit button DOM sub-tree
77
77
  *
78
78
  * If you choose to use the default edit button, add `label` to the
79
79
  * incoming `props` parameter and call `InPlaceEdit.renderDefaultEditButton(props)`
@@ -84,43 +84,68 @@ const propTypes: PropValidators<PropKeys> = {
84
84
  * `isVisible` is a hint as to whether the button is _typically_ shown,
85
85
  * but you're free to ignore it for your use-case.
86
86
  */
87
- renderEditButton: PropTypes.func.isRequired,
87
+ renderEditButton: (props: ExtendedRenderEditButton) => React.ReactNode | null
88
88
  /**
89
89
  * If `'view'`: the view component is rendered,
90
90
  * if `'edit'`: the edit component is rendered
91
91
  */
92
- mode: PropTypes.oneOf(['view', 'edit']).isRequired,
92
+ mode: 'view' | 'edit'
93
93
  /**
94
94
  * Called when the component's mode changes
95
- * @param {string} newMode
95
+ * Parameter:
96
+ * - newMode: string
96
97
  */
97
- onChangeMode: PropTypes.func.isRequired,
98
+ onChangeMode: EditableProps['onChangeMode']
98
99
  /**
99
100
  * The current value.
100
101
  * The value is managed by the consuming app, but we need to tell InPlaceEdit
101
102
  * it's changed or it won't re-render
102
103
  */
103
- value: PropTypes.any,
104
+ value?: any
104
105
  /**
105
106
  * Called when Editable switches from edit to view mode and the value has changed.
106
- * @param {any} value
107
+ * Parameter:
108
+ * - value: any
107
109
  */
108
- onChange: PropTypes.func,
110
+ onChange?: EditableProps['onChange']
109
111
  /**
110
112
  * The mode is fixed as 'view'
111
113
  */
112
- readOnly: PropTypes.bool,
114
+ readOnly?: boolean
113
115
  /**
114
116
  * Show a focus outline when the input is focused
115
117
  */
116
- showFocusRing: PropTypes.bool,
118
+ showFocusRing?: boolean
117
119
  /**
118
120
  * Put the edit button before or after the view
119
121
  */
120
- editButtonPlacement: PropTypes.oneOf(['start', 'end']),
122
+ editButtonPlacement?: 'start' | 'end'
121
123
  /**
122
124
  * Render outermost element inline v. block
123
125
  */
126
+ inline?: boolean
127
+ }
128
+
129
+ type PropKeys = keyof InPlaceEditOwnProps
130
+
131
+ type AllowedPropKeys = Readonly<Array<PropKeys>>
132
+
133
+ type InPlaceEditProps = InPlaceEditOwnProps &
134
+ WithStyleProps<null, InPlaceEditStyle>
135
+
136
+ type InPlaceEditStyle = ComponentStyle<'inPlaceEdit'>
137
+
138
+ const propTypes: PropValidators<PropKeys> = {
139
+ renderViewer: PropTypes.func.isRequired,
140
+ renderEditor: PropTypes.func.isRequired,
141
+ renderEditButton: PropTypes.func.isRequired,
142
+ mode: PropTypes.oneOf(['view', 'edit']).isRequired,
143
+ onChangeMode: PropTypes.func.isRequired,
144
+ value: PropTypes.any,
145
+ onChange: PropTypes.func,
146
+ readOnly: PropTypes.bool,
147
+ showFocusRing: PropTypes.bool,
148
+ editButtonPlacement: PropTypes.oneOf(['start', 'end']),
124
149
  inline: PropTypes.bool
125
150
  }
126
151