@kaspernj/api-maker 1.0.339 → 1.0.341
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as inflection from "inflection"
|
|
2
2
|
|
|
3
|
-
export default function apiMakerIdForComponent
|
|
3
|
+
export default function apiMakerIdForComponent(component) {
|
|
4
4
|
if ("id" in component.props) {
|
|
5
5
|
return component.props.id
|
|
6
6
|
} else if (component.props.attribute && component.props.model) {
|
|
@@ -1,184 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
componentDidMount() {
|
|
16
|
-
this.setForm()
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
componentDidUpdate() {
|
|
20
|
-
this.setForm()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
inputProps() {
|
|
24
|
-
const givenInputProps = this.props.inputProps || {}
|
|
25
|
-
const inputProps = Object.assign(
|
|
26
|
-
{
|
|
27
|
-
id: idForComponent(this),
|
|
28
|
-
name: nameForComponent(this),
|
|
29
|
-
ref: this.inputRef()
|
|
30
|
-
},
|
|
31
|
-
givenInputProps
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
if (this.handleAsCheckbox()) {
|
|
35
|
-
if ("checked" in this.props) {
|
|
36
|
-
inputProps.checked = this.props.checked
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if ("defaultChecked" in this.props || (this.props.attribute && this.props.model)) {
|
|
40
|
-
inputProps.defaultChecked = this.inputDefaultChecked()
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
inputProps.defaultValue = this.inputDefaultValue()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return inputProps
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
render() {
|
|
50
|
-
const {inputProps: oldInputProps, ...restProps} = this.props
|
|
51
|
-
const {errors, form} = digs(this.state, "errors", "form")
|
|
52
|
-
const type = this.inputType()
|
|
53
|
-
const inputProps = this.inputProps()
|
|
54
|
-
|
|
55
|
-
if (!inputProps.ref) throw new Error("No input ref?")
|
|
56
|
-
if (!this.handleAsSelect()) inputProps.type = type
|
|
57
|
-
|
|
58
|
-
const wrapperOpts = {
|
|
59
|
-
errors,
|
|
60
|
-
form,
|
|
61
|
-
label: this.label()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<>
|
|
66
|
-
{form &&
|
|
67
|
-
<EventListener event="validation-errors" onCalled={digg(this, "onValidationErrors")} target={form} />
|
|
68
|
-
}
|
|
69
|
-
<WrapperComponentClass
|
|
70
|
-
inputProps={inputProps}
|
|
71
|
-
wrapperOpts={wrapperOpts}
|
|
72
|
-
{...restProps}
|
|
73
|
-
/>
|
|
74
|
-
</>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
formatValue (value) {
|
|
79
|
-
const {formatValue} = this.props
|
|
80
|
-
|
|
81
|
-
if (formatValue) {
|
|
82
|
-
return formatValue(value)
|
|
83
|
-
} else if (value instanceof Date && !isNaN(value.getTime())) {
|
|
84
|
-
// We need to use a certain format for datetime-local
|
|
85
|
-
if (this.inputType() == "datetime-local") {
|
|
86
|
-
return strftime("%Y-%m-%dT%H:%M:%S", value)
|
|
87
|
-
} else if (this.inputType() == "date") {
|
|
88
|
-
return strftime("%Y-%m-%d", value)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return value
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
handleAsCheckbox() {
|
|
96
|
-
if (this.props.type == "checkbox") return true
|
|
97
|
-
if (!("type" in this.props) && wrapperOptions.type == "checkbox") return true
|
|
98
|
-
|
|
99
|
-
return false
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
handleAsSelect() {
|
|
103
|
-
if (wrapperOptions.type == "select") return true
|
|
104
|
-
|
|
105
|
-
return false
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
inputDefaultChecked () {
|
|
109
|
-
if ("defaultChecked" in this.props) {
|
|
110
|
-
return this.props.defaultChecked
|
|
111
|
-
} else if (this.props.model) {
|
|
112
|
-
if (!this.props.model[this.props.attribute])
|
|
113
|
-
throw new Error(`No such attribute: ${this.props.attribute}`)
|
|
114
|
-
|
|
115
|
-
return this.props.model[this.props.attribute]()
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
inputDefaultValue() {
|
|
120
|
-
if ("defaultValue" in this.props) {
|
|
121
|
-
return this.formatValue(this.props.defaultValue)
|
|
122
|
-
} else if (this.props.model) {
|
|
123
|
-
if (!this.props.model[this.props.attribute]) {
|
|
124
|
-
throw new Error(`No such attribute defined on resource: ${digg(this.props.model.modelClassData(), "name")}#${this.props.attribute}`)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return this.formatValue(this.props.model[this.props.attribute]())
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
inputName() {
|
|
132
|
-
if (this.state.blankInputName) return ""
|
|
133
|
-
|
|
134
|
-
return nameForComponent(this)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
inputRefBackup() {
|
|
138
|
-
if (!this._inputRefBackup) this._inputRefBackup = React.createRef()
|
|
139
|
-
|
|
140
|
-
return this._inputRefBackup
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
inputRef = () => this.props.inputRef || this.inputRefBackup()
|
|
144
|
-
|
|
145
|
-
inputType() {
|
|
146
|
-
if ("type" in this.props) {
|
|
147
|
-
return this.props.type
|
|
148
|
-
} else if (wrapperOptions.type == "checkbox") {
|
|
149
|
-
return "checkbox"
|
|
150
|
-
} else {
|
|
151
|
-
return "text"
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
label() {
|
|
156
|
-
if ("label" in this.props) {
|
|
157
|
-
return this.props.label
|
|
158
|
-
} else if (this.props.attribute && this.props.model) {
|
|
159
|
-
return this.props.model.modelClass().humanAttributeName(this.props.attribute)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
onValidationErrors = (event) => {
|
|
164
|
-
const errors = event.detail.getValidationErrorsForInput({
|
|
165
|
-
attribute: this.props.attribute,
|
|
166
|
-
inputName: this.inputName(),
|
|
167
|
-
onMatchValidationError: this.props.onMatchValidationError
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
this.setState({errors})
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
setForm () {
|
|
174
|
-
const inputElement = this.inputRef().current
|
|
175
|
-
|
|
176
|
-
let form
|
|
177
|
-
|
|
178
|
-
if (inputElement) form = dig(inputElement, "form")
|
|
179
|
-
if (form && form != this.state.form) this.setState({form})
|
|
180
|
-
}
|
|
181
|
-
}
|
|
1
|
+
import useInput from "../use-input.mjs"
|
|
2
|
+
|
|
3
|
+
const inputWrapper = (WrapperComponentClass, wrapperOptions = {}) => (props) => {
|
|
4
|
+
const {inputProps, restProps, wrapperOpts} = useInput({props, wrapperOptions})
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<WrapperComponentClass
|
|
8
|
+
inputProps={inputProps}
|
|
9
|
+
wrapperOpts={wrapperOpts}
|
|
10
|
+
{...restProps}
|
|
11
|
+
/>
|
|
12
|
+
)
|
|
182
13
|
}
|
|
183
14
|
|
|
184
15
|
export default inputWrapper
|
|
@@ -2,7 +2,7 @@ import {useCallback, useEffect} from "react"
|
|
|
2
2
|
|
|
3
3
|
const ApiMakerUseEventEmitter = (events, event, onCalled) => {
|
|
4
4
|
const onCalledCallback = useCallback((...args) => {
|
|
5
|
-
onCalled
|
|
5
|
+
onCalled(...args)
|
|
6
6
|
}, [events, event, onCalled])
|
|
7
7
|
|
|
8
8
|
useEffect(() => {
|
|
@@ -6,10 +6,12 @@ const ApiMakerUseEventListener = (target, event, onCalled) => {
|
|
|
6
6
|
}, [target, event, onCalled])
|
|
7
7
|
|
|
8
8
|
useEffect(() => {
|
|
9
|
-
target
|
|
9
|
+
if (target) {
|
|
10
|
+
target.addEventListener(event, onCalledCallback)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
return () => {
|
|
13
|
+
target.removeEventListener(event, onCalledCallback)
|
|
14
|
+
}
|
|
13
15
|
}
|
|
14
16
|
}, [target, event, onCalled])
|
|
15
17
|
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {dig, digg, digs} from "diggerize"
|
|
2
|
+
import {useCallback, useEffect, useMemo} from "react"
|
|
3
|
+
import idForComponent from "./inputs/id-for-component.mjs"
|
|
4
|
+
import nameForComponent from "./inputs/name-for-component.mjs"
|
|
5
|
+
import strftime from "strftime"
|
|
6
|
+
import useEventListener from "./use-event-listener.mjs"
|
|
7
|
+
import useShape from "set-state-compare/src/use-shape.js"
|
|
8
|
+
|
|
9
|
+
const useInput = ({props, wrapperOptions}) => {
|
|
10
|
+
const s = useShape(props)
|
|
11
|
+
|
|
12
|
+
s.useStates({
|
|
13
|
+
errors: [],
|
|
14
|
+
form: undefined
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
setForm()
|
|
19
|
+
}, [s.props.inputRef?.current])
|
|
20
|
+
|
|
21
|
+
const fakeComponent = useMemo(
|
|
22
|
+
() => ({
|
|
23
|
+
props
|
|
24
|
+
}),
|
|
25
|
+
[]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const formatValue = useCallback((value) => {
|
|
29
|
+
const {formatValue} = s.props
|
|
30
|
+
|
|
31
|
+
if (formatValue) {
|
|
32
|
+
return formatValue(value)
|
|
33
|
+
} else if (value instanceof Date && !isNaN(value.getTime())) {
|
|
34
|
+
// We need to use a certain format for datetime-local
|
|
35
|
+
if (inputType() == "datetime-local") {
|
|
36
|
+
return strftime("%Y-%m-%dT%H:%M:%S", value)
|
|
37
|
+
} else if (inputType() == "date") {
|
|
38
|
+
return strftime("%Y-%m-%d", value)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return value
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
const handleAsCheckbox = useCallback(() => {
|
|
46
|
+
if (s.props.type == "checkbox") return true
|
|
47
|
+
if (!("type" in s.props) && wrapperOptions?.type == "checkbox") return true
|
|
48
|
+
|
|
49
|
+
return false
|
|
50
|
+
}, [])
|
|
51
|
+
|
|
52
|
+
const handleAsSelect = useCallback(() => {
|
|
53
|
+
if (wrapperOptions?.type == "select") return true
|
|
54
|
+
|
|
55
|
+
return false
|
|
56
|
+
}, [])
|
|
57
|
+
|
|
58
|
+
const inputDefaultChecked = useCallback(() => {
|
|
59
|
+
if ("defaultChecked" in s.props) {
|
|
60
|
+
return s.props.defaultChecked
|
|
61
|
+
} else if (s.props.model) {
|
|
62
|
+
if (!s.props.model[s.props.attribute])
|
|
63
|
+
throw new Error(`No such attribute: ${s.props.attribute}`)
|
|
64
|
+
|
|
65
|
+
return s.props.model[s.props.attribute]()
|
|
66
|
+
}
|
|
67
|
+
}, [])
|
|
68
|
+
|
|
69
|
+
const inputDefaultValue = useCallback(() => {
|
|
70
|
+
if ("defaultValue" in s.props) {
|
|
71
|
+
return formatValue(s.props.defaultValue)
|
|
72
|
+
} else if (s.props.model) {
|
|
73
|
+
if (!s.props.model[s.props.attribute]) {
|
|
74
|
+
throw new Error(`No such attribute defined on resource: ${digg(s.props.model.modelClassData(), "name")}#${s.props.attribute}`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return formatValue(s.props.model[s.props.attribute]())
|
|
78
|
+
}
|
|
79
|
+
}, [])
|
|
80
|
+
|
|
81
|
+
const inputName = useCallback(() => {
|
|
82
|
+
if (s.state.blankInputName) return ""
|
|
83
|
+
|
|
84
|
+
return getName()
|
|
85
|
+
}, [])
|
|
86
|
+
|
|
87
|
+
const inputRefBackup = useCallback(() => {
|
|
88
|
+
if (!s.meta._inputRefBackup) s.meta._inputRefBackup = React.createRef()
|
|
89
|
+
|
|
90
|
+
return s.meta._inputRefBackup
|
|
91
|
+
}, [])
|
|
92
|
+
|
|
93
|
+
const inputRef = useCallback(() => s.props.inputRef || inputRefBackup())
|
|
94
|
+
|
|
95
|
+
const inputType = useCallback(() => {
|
|
96
|
+
if ("type" in s.props) {
|
|
97
|
+
return s.props.type
|
|
98
|
+
} else if (wrapperOptions?.type == "checkbox") {
|
|
99
|
+
return "checkbox"
|
|
100
|
+
} else {
|
|
101
|
+
return "text"
|
|
102
|
+
}
|
|
103
|
+
}, [])
|
|
104
|
+
|
|
105
|
+
const label = useCallback(() => {
|
|
106
|
+
if ("label" in s.props) {
|
|
107
|
+
return s.props.label
|
|
108
|
+
} else if (s.props.attribute && s.props.model) {
|
|
109
|
+
return s.props.model.modelClass().humanAttributeName(s.props.attribute)
|
|
110
|
+
}
|
|
111
|
+
}, [])
|
|
112
|
+
|
|
113
|
+
const onValidationErrors = useCallback((event) => {
|
|
114
|
+
const errors = event.detail.getValidationErrorsForInput({
|
|
115
|
+
attribute: s.props.attribute,
|
|
116
|
+
inputName: inputName(),
|
|
117
|
+
onMatchValidationError: s.props.onMatchValidationError
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
s.set({errors})
|
|
121
|
+
}, [])
|
|
122
|
+
|
|
123
|
+
const setForm = useCallback(() => {
|
|
124
|
+
const inputElement = inputRef().current
|
|
125
|
+
|
|
126
|
+
let form
|
|
127
|
+
|
|
128
|
+
if (inputElement) form = dig(inputElement, "form")
|
|
129
|
+
if (form && form != s.s.form) s.set({form})
|
|
130
|
+
}, [])
|
|
131
|
+
|
|
132
|
+
const getId = useCallback(() => idForComponent(fakeComponent), [])
|
|
133
|
+
const getName = useCallback(() => nameForComponent(fakeComponent), [])
|
|
134
|
+
|
|
135
|
+
const getInputProps = useCallback(() => {
|
|
136
|
+
const givenInputProps = s.props.inputProps || {}
|
|
137
|
+
const inputProps = Object.assign(
|
|
138
|
+
{
|
|
139
|
+
id: getId(),
|
|
140
|
+
name: getName(),
|
|
141
|
+
ref: inputRef()
|
|
142
|
+
},
|
|
143
|
+
givenInputProps
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if (handleAsCheckbox()) {
|
|
147
|
+
if ("checked" in s.props) {
|
|
148
|
+
inputProps.checked = s.props.checked
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if ("defaultChecked" in s.props || (s.props.attribute && s.props.model)) {
|
|
152
|
+
inputProps.defaultChecked = inputDefaultChecked()
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
inputProps.defaultValue = inputDefaultValue()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return inputProps
|
|
159
|
+
}, [])
|
|
160
|
+
|
|
161
|
+
const {inputProps: oldInputProps, ...restProps} = props
|
|
162
|
+
const type = inputType()
|
|
163
|
+
const inputProps = getInputProps()
|
|
164
|
+
|
|
165
|
+
if (!inputProps.ref) throw new Error("No input ref?")
|
|
166
|
+
if (!handleAsSelect()) inputProps.type = type
|
|
167
|
+
|
|
168
|
+
const wrapperOpts = {
|
|
169
|
+
errors: s.s.errors,
|
|
170
|
+
form: s.s.form,
|
|
171
|
+
label: label()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
useEventListener(s.s.form, "validation-errors", onValidationErrors)
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
inputProps,
|
|
178
|
+
wrapperOpts,
|
|
179
|
+
restProps
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export default useInput
|