@mpen/react-basic-inputs 0.1.11 → 0.2.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.
- package/README.md +0 -0
- package/dist/react-basic-inputs.d.ts +150 -0
- package/dist/react-basic-inputs.js +289 -0
- package/dist/react-basic-inputs.umd.cjs +291 -0
- package/package.json +33 -48
- package/dist/bundle.cjs +0 -328
- package/dist/bundle.d.ts +0 -5
- package/dist/bundle.mjs +0 -318
- package/dist/components/Input.d.ts +0 -25
- package/dist/components/RadioMenu.d.ts +0 -33
- package/dist/components/Select.d.ts +0 -33
- package/dist/components/TextArea.d.ts +0 -14
- package/dist/components/TextInput.d.ts +0 -3
- package/dist/hooks/useEvent.d.ts +0 -6
- package/dist/types/utility.d.ts +0 -31
- package/dist/util/assert.d.ts +0 -1
- package/dist/util/constants.d.ts +0 -5
- package/dist/util/format.d.ts +0 -9
- package/dist/util/key-fixer.d.ts +0 -8
- package/dist/util/resolvable.d.ts +0 -4
package/dist/bundle.cjs
DELETED
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var jsxRuntime = require("react/jsx-runtime");
|
|
4
|
-
|
|
5
|
-
var React = require("react");
|
|
6
|
-
|
|
7
|
-
const NOOP = Object.freeze((() => {}));
|
|
8
|
-
|
|
9
|
-
function identity(x) {
|
|
10
|
-
return x;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
let useEventHandler;
|
|
14
|
-
|
|
15
|
-
if (typeof window !== "undefined") {
|
|
16
|
-
useEventHandler = callback => {
|
|
17
|
-
React.useDebugValue(callback);
|
|
18
|
-
const latestRef = React.useRef(useEvent_shouldNotBeInvokedBeforeMount);
|
|
19
|
-
React.useInsertionEffect((() => {
|
|
20
|
-
latestRef.current = callback;
|
|
21
|
-
}), [ callback ]);
|
|
22
|
-
const stableRef = React.useRef(null);
|
|
23
|
-
if (!stableRef.current) {
|
|
24
|
-
stableRef.current = function() {
|
|
25
|
-
return latestRef.current.apply(this, arguments);
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
return stableRef.current;
|
|
29
|
-
};
|
|
30
|
-
} else {
|
|
31
|
-
useEventHandler = NOOP;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function useEvent(handler) {
|
|
35
|
-
return useEventHandler(handler);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function useEvent_shouldNotBeInvokedBeforeMount() {
|
|
39
|
-
throw new Error("INVALID_USE_EVENT_INVOCATION: the callback from useEvent cannot be invoked before the component has mounted.");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function resolveValue(val, ...args) {
|
|
43
|
-
return typeof val === "function" ? val(...args) : val;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function useFirstMountState() {
|
|
47
|
-
var isFirst = React.useRef(true);
|
|
48
|
-
if (isFirst.current) {
|
|
49
|
-
isFirst.current = false;
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
return isFirst.current;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
var useUpdateEffect = function(effect, deps) {
|
|
56
|
-
var isFirstMount = useFirstMountState();
|
|
57
|
-
React.useEffect((function() {
|
|
58
|
-
if (!isFirstMount) {
|
|
59
|
-
return effect();
|
|
60
|
-
}
|
|
61
|
-
}), deps);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
var useUpdateEffect$1 = useUpdateEffect;
|
|
65
|
-
|
|
66
|
-
function defaultMakeKey(opt, idx) {
|
|
67
|
-
if (opt.key != null) {
|
|
68
|
-
return resolveValue(opt.key, opt, idx);
|
|
69
|
-
} else if (typeof opt.value === "string" || typeof opt.value === "number") {
|
|
70
|
-
return opt.value;
|
|
71
|
-
}
|
|
72
|
-
return idx;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
class KeyFixer {
|
|
76
|
-
usedKeys=new Map;
|
|
77
|
-
fix(opt, idx) {
|
|
78
|
-
let fixedKey = defaultMakeKey(opt, idx);
|
|
79
|
-
for (;;) {
|
|
80
|
-
let suffix = this.usedKeys.get(fixedKey);
|
|
81
|
-
if (suffix === undefined) {
|
|
82
|
-
this.usedKeys.set(fixedKey, 1);
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
this.usedKeys.set(fixedKey, ++suffix);
|
|
86
|
-
fixedKey = `${fixedKey}(${suffix})`;
|
|
87
|
-
}
|
|
88
|
-
return fixedKey;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const defaultMakeInvalidValueOption = value => ({
|
|
93
|
-
value,
|
|
94
|
-
text: String(value),
|
|
95
|
-
disabled: true,
|
|
96
|
-
key: INVALID_OPTION_KEY
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const PLACEHOLDER_KEY = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb";
|
|
100
|
-
|
|
101
|
-
const INVALID_OPTION_KEY = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
|
|
102
|
-
|
|
103
|
-
function Select({options, value, invalidValueOption = defaultMakeInvalidValueOption, onChange, placeholder, ...selectAttrs}) {
|
|
104
|
-
const isNotSelected = value == null;
|
|
105
|
-
const isValid = React.useMemo((() => value != null && options.some((o => o.value == value))), [ options, value ]);
|
|
106
|
-
const extraOption = React.useMemo((() => {
|
|
107
|
-
if (value == null || !invalidValueOption) return null;
|
|
108
|
-
return invalidValueOption(value);
|
|
109
|
-
}), [ invalidValueOption, value ]);
|
|
110
|
-
const fixedOptions = React.useMemo((() => {
|
|
111
|
-
if (isValid) return options;
|
|
112
|
-
const fixedOptions = [ ...options ];
|
|
113
|
-
if (isNotSelected) {
|
|
114
|
-
if (placeholder != null) {
|
|
115
|
-
fixedOptions.unshift({
|
|
116
|
-
text: placeholder,
|
|
117
|
-
hidden: true,
|
|
118
|
-
value: null,
|
|
119
|
-
key: PLACEHOLDER_KEY
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
} else if (extraOption) {
|
|
123
|
-
fixedOptions.push(extraOption);
|
|
124
|
-
}
|
|
125
|
-
return fixedOptions;
|
|
126
|
-
}), [ isValid, options, isNotSelected, extraOption, placeholder ]);
|
|
127
|
-
const handleChange = useEvent((ev => {
|
|
128
|
-
const idx = ev.target.selectedIndex;
|
|
129
|
-
const opt = fixedOptions[idx];
|
|
130
|
-
onChange?.({
|
|
131
|
-
value: opt.value,
|
|
132
|
-
index: idx,
|
|
133
|
-
type: "change",
|
|
134
|
-
timeStamp: ev.timeStamp,
|
|
135
|
-
target: ev.target
|
|
136
|
-
});
|
|
137
|
-
}));
|
|
138
|
-
const ref = React.useRef(null);
|
|
139
|
-
const refreshSelectedIndex = React.useCallback((() => {
|
|
140
|
-
if (!ref.current) return;
|
|
141
|
-
if (ref.current.selectedIndex < 0 || fixedOptions[ref.current.selectedIndex].value != value) {
|
|
142
|
-
ref.current.selectedIndex = fixedOptions.findIndex((opt => opt.value == value));
|
|
143
|
-
}
|
|
144
|
-
}), [ fixedOptions, value ]);
|
|
145
|
-
const setRef = el => {
|
|
146
|
-
ref.current = el;
|
|
147
|
-
refreshSelectedIndex();
|
|
148
|
-
};
|
|
149
|
-
useUpdateEffect$1((() => {
|
|
150
|
-
refreshSelectedIndex();
|
|
151
|
-
}), [ refreshSelectedIndex ]);
|
|
152
|
-
const fixer = new KeyFixer;
|
|
153
|
-
return jsxRuntime.jsx("select", {
|
|
154
|
-
...selectAttrs,
|
|
155
|
-
onChange: handleChange,
|
|
156
|
-
ref: setRef,
|
|
157
|
-
children: fixedOptions.map(((opt, idx) => {
|
|
158
|
-
const {value, text, key, ...optAttrs} = opt;
|
|
159
|
-
const fixedKey = fixer.fix(opt, idx);
|
|
160
|
-
return React.createElement("option", {
|
|
161
|
-
...optAttrs,
|
|
162
|
-
key: fixedKey,
|
|
163
|
-
value: fixedKey
|
|
164
|
-
}, opt.text);
|
|
165
|
-
}))
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function collapseWhitespace(str) {
|
|
170
|
-
if (!str) return "";
|
|
171
|
-
return String(str).replace(/\s+/gu, " ").trim();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const Input = React.forwardRef((function Input({value = "", onChange, onInput, onBlur, formatOnChange = identity, ...otherProps}, ref) {
|
|
175
|
-
const [currentValue, setCurrentValue] = React.useState(value);
|
|
176
|
-
const lastValue = React.useRef(value);
|
|
177
|
-
const modified = React.useRef(false);
|
|
178
|
-
useUpdateEffect$1((() => {
|
|
179
|
-
setCurrentValue(value);
|
|
180
|
-
modified.current = false;
|
|
181
|
-
lastValue.current = value;
|
|
182
|
-
}), [ value ]);
|
|
183
|
-
const props = {
|
|
184
|
-
type: "text",
|
|
185
|
-
...otherProps,
|
|
186
|
-
value: currentValue,
|
|
187
|
-
onChange: ev => {
|
|
188
|
-
setCurrentValue(ev.target.value);
|
|
189
|
-
},
|
|
190
|
-
onInput: ev => {
|
|
191
|
-
modified.current = true;
|
|
192
|
-
onInput?.(ev);
|
|
193
|
-
},
|
|
194
|
-
onBlur: ev => {
|
|
195
|
-
const formattedValue = formatOnChange(currentValue);
|
|
196
|
-
if (modified.current) {
|
|
197
|
-
if (formattedValue !== lastValue.current) {
|
|
198
|
-
onChange?.({
|
|
199
|
-
type: "change",
|
|
200
|
-
value: formattedValue,
|
|
201
|
-
timeStamp: ev.timeStamp,
|
|
202
|
-
target: ev.target
|
|
203
|
-
});
|
|
204
|
-
lastValue.current = formattedValue;
|
|
205
|
-
}
|
|
206
|
-
if (formattedValue !== ev.target.value) {
|
|
207
|
-
setCurrentValue(formattedValue);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
onBlur?.(ev);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
return jsxRuntime.jsx("input", {
|
|
214
|
-
...props,
|
|
215
|
-
ref
|
|
216
|
-
});
|
|
217
|
-
}));
|
|
218
|
-
|
|
219
|
-
function TextInput({formatOnChange = collapseWhitespace, ...otherProps}) {
|
|
220
|
-
return jsxRuntime.jsx(Input, {
|
|
221
|
-
formatOnChange,
|
|
222
|
-
...otherProps,
|
|
223
|
-
type: "text"
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const TextArea = React.forwardRef((function TextArea({onInput, style, initialHeight = "auto", ...rest}, fwdRef) {
|
|
228
|
-
const ref = React.useRef(null);
|
|
229
|
-
const [height, setHeight] = React.useState(initialHeight);
|
|
230
|
-
const adjustHeight = React.useCallback((() => {
|
|
231
|
-
const textarea = ref.current;
|
|
232
|
-
if (!textarea) return;
|
|
233
|
-
textarea.style.height = initialHeight;
|
|
234
|
-
const newHeight = `${textarea.scrollHeight}px`;
|
|
235
|
-
setHeight(newHeight);
|
|
236
|
-
textarea.style.height = newHeight;
|
|
237
|
-
}), [ initialHeight ]);
|
|
238
|
-
React.useImperativeHandle(fwdRef, (() => ({
|
|
239
|
-
element: ref.current,
|
|
240
|
-
adjustHeight
|
|
241
|
-
})), [ adjustHeight ]);
|
|
242
|
-
const input = useEventHandler((ev => {
|
|
243
|
-
adjustHeight();
|
|
244
|
-
onInput?.(ev);
|
|
245
|
-
}));
|
|
246
|
-
React.useLayoutEffect((() => {
|
|
247
|
-
adjustHeight();
|
|
248
|
-
const textarea = ref.current;
|
|
249
|
-
if (!textarea) return;
|
|
250
|
-
const resizeObserver = new ResizeObserver((entries => {
|
|
251
|
-
adjustHeight();
|
|
252
|
-
}));
|
|
253
|
-
resizeObserver.observe(textarea);
|
|
254
|
-
return () => {
|
|
255
|
-
resizeObserver.unobserve(textarea);
|
|
256
|
-
};
|
|
257
|
-
}), [ adjustHeight ]);
|
|
258
|
-
return jsxRuntime.jsx("textarea", {
|
|
259
|
-
...rest,
|
|
260
|
-
style: {
|
|
261
|
-
overflow: "hidden",
|
|
262
|
-
resize: "none",
|
|
263
|
-
...style,
|
|
264
|
-
height
|
|
265
|
-
},
|
|
266
|
-
onInput: input,
|
|
267
|
-
ref
|
|
268
|
-
});
|
|
269
|
-
}));
|
|
270
|
-
|
|
271
|
-
function RadioMenu(menu) {
|
|
272
|
-
const defaultId = React.useId();
|
|
273
|
-
const name = menu.name ?? defaultId;
|
|
274
|
-
const eq = menu.valueEquals ?? Object.is;
|
|
275
|
-
const fixedOptions = menu.options ?? [];
|
|
276
|
-
const fixer = new KeyFixer;
|
|
277
|
-
const onChange = useEventHandler((ev => {
|
|
278
|
-
const selectedIndex = Number(ev.target.value);
|
|
279
|
-
const selectedOption = fixedOptions[selectedIndex];
|
|
280
|
-
if (selectedOption != null && menu.onChange != null) {
|
|
281
|
-
menu.onChange({
|
|
282
|
-
value: selectedOption.value,
|
|
283
|
-
index: selectedIndex,
|
|
284
|
-
type: "change",
|
|
285
|
-
timeStamp: ev.timeStamp,
|
|
286
|
-
target: ev.target
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}));
|
|
290
|
-
return jsxRuntime.jsx("ul", {
|
|
291
|
-
className: menu.className,
|
|
292
|
-
children: fixedOptions.map(((opt, idx) => {
|
|
293
|
-
const {value, text, key, itemClassName, labelClassName, inputClassName, textClassName, ...rest} = opt;
|
|
294
|
-
const fixedKey = fixer.fix(opt, idx);
|
|
295
|
-
if (menu.value !== undefined) {
|
|
296
|
-
rest.checked = eq(value, menu.value);
|
|
297
|
-
}
|
|
298
|
-
return jsxRuntime.jsx("li", {
|
|
299
|
-
className: itemClassName,
|
|
300
|
-
"aria-disabled": rest.disabled,
|
|
301
|
-
children: jsxRuntime.jsxs("label", {
|
|
302
|
-
className: labelClassName,
|
|
303
|
-
children: [ jsxRuntime.jsx("input", {
|
|
304
|
-
...rest,
|
|
305
|
-
className: inputClassName,
|
|
306
|
-
value: idx,
|
|
307
|
-
onChange,
|
|
308
|
-
name,
|
|
309
|
-
type: "radio"
|
|
310
|
-
}), jsxRuntime.jsx("span", {
|
|
311
|
-
className: textClassName,
|
|
312
|
-
children: text
|
|
313
|
-
}) ]
|
|
314
|
-
})
|
|
315
|
-
}, fixedKey);
|
|
316
|
-
}))
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
exports.Input = Input;
|
|
321
|
-
|
|
322
|
-
exports.RadioMenu = RadioMenu;
|
|
323
|
-
|
|
324
|
-
exports.Select = Select;
|
|
325
|
-
|
|
326
|
-
exports.TextArea = TextArea;
|
|
327
|
-
|
|
328
|
-
exports.TextInput = TextInput;
|
package/dist/bundle.d.ts
DELETED
package/dist/bundle.mjs
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
import { useDebugValue, useRef, useInsertionEffect, useEffect, useMemo, useCallback, createElement, forwardRef, useState, useImperativeHandle, useLayoutEffect, useId } from "react";
|
|
4
|
-
|
|
5
|
-
const NOOP = Object.freeze((() => {}));
|
|
6
|
-
|
|
7
|
-
function identity(x) {
|
|
8
|
-
return x;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
let useEventHandler;
|
|
12
|
-
|
|
13
|
-
if (typeof window !== "undefined") {
|
|
14
|
-
useEventHandler = callback => {
|
|
15
|
-
useDebugValue(callback);
|
|
16
|
-
const latestRef = useRef(useEvent_shouldNotBeInvokedBeforeMount);
|
|
17
|
-
useInsertionEffect((() => {
|
|
18
|
-
latestRef.current = callback;
|
|
19
|
-
}), [ callback ]);
|
|
20
|
-
const stableRef = useRef(null);
|
|
21
|
-
if (!stableRef.current) {
|
|
22
|
-
stableRef.current = function() {
|
|
23
|
-
return latestRef.current.apply(this, arguments);
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
return stableRef.current;
|
|
27
|
-
};
|
|
28
|
-
} else {
|
|
29
|
-
useEventHandler = NOOP;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function useEvent(handler) {
|
|
33
|
-
return useEventHandler(handler);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function useEvent_shouldNotBeInvokedBeforeMount() {
|
|
37
|
-
throw new Error("INVALID_USE_EVENT_INVOCATION: the callback from useEvent cannot be invoked before the component has mounted.");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function resolveValue(val, ...args) {
|
|
41
|
-
return typeof val === "function" ? val(...args) : val;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function useFirstMountState() {
|
|
45
|
-
var isFirst = useRef(true);
|
|
46
|
-
if (isFirst.current) {
|
|
47
|
-
isFirst.current = false;
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return isFirst.current;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
var useUpdateEffect = function(effect, deps) {
|
|
54
|
-
var isFirstMount = useFirstMountState();
|
|
55
|
-
useEffect((function() {
|
|
56
|
-
if (!isFirstMount) {
|
|
57
|
-
return effect();
|
|
58
|
-
}
|
|
59
|
-
}), deps);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
var useUpdateEffect$1 = useUpdateEffect;
|
|
63
|
-
|
|
64
|
-
function defaultMakeKey(opt, idx) {
|
|
65
|
-
if (opt.key != null) {
|
|
66
|
-
return resolveValue(opt.key, opt, idx);
|
|
67
|
-
} else if (typeof opt.value === "string" || typeof opt.value === "number") {
|
|
68
|
-
return opt.value;
|
|
69
|
-
}
|
|
70
|
-
return idx;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
class KeyFixer {
|
|
74
|
-
usedKeys=new Map;
|
|
75
|
-
fix(opt, idx) {
|
|
76
|
-
let fixedKey = defaultMakeKey(opt, idx);
|
|
77
|
-
for (;;) {
|
|
78
|
-
let suffix = this.usedKeys.get(fixedKey);
|
|
79
|
-
if (suffix === undefined) {
|
|
80
|
-
this.usedKeys.set(fixedKey, 1);
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
this.usedKeys.set(fixedKey, ++suffix);
|
|
84
|
-
fixedKey = `${fixedKey}(${suffix})`;
|
|
85
|
-
}
|
|
86
|
-
return fixedKey;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const defaultMakeInvalidValueOption = value => ({
|
|
91
|
-
value,
|
|
92
|
-
text: String(value),
|
|
93
|
-
disabled: true,
|
|
94
|
-
key: INVALID_OPTION_KEY
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const PLACEHOLDER_KEY = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb";
|
|
98
|
-
|
|
99
|
-
const INVALID_OPTION_KEY = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
|
|
100
|
-
|
|
101
|
-
function Select({options, value, invalidValueOption = defaultMakeInvalidValueOption, onChange, placeholder, ...selectAttrs}) {
|
|
102
|
-
const isNotSelected = value == null;
|
|
103
|
-
const isValid = useMemo((() => value != null && options.some((o => o.value == value))), [ options, value ]);
|
|
104
|
-
const extraOption = useMemo((() => {
|
|
105
|
-
if (value == null || !invalidValueOption) return null;
|
|
106
|
-
return invalidValueOption(value);
|
|
107
|
-
}), [ invalidValueOption, value ]);
|
|
108
|
-
const fixedOptions = useMemo((() => {
|
|
109
|
-
if (isValid) return options;
|
|
110
|
-
const fixedOptions = [ ...options ];
|
|
111
|
-
if (isNotSelected) {
|
|
112
|
-
if (placeholder != null) {
|
|
113
|
-
fixedOptions.unshift({
|
|
114
|
-
text: placeholder,
|
|
115
|
-
hidden: true,
|
|
116
|
-
value: null,
|
|
117
|
-
key: PLACEHOLDER_KEY
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
} else if (extraOption) {
|
|
121
|
-
fixedOptions.push(extraOption);
|
|
122
|
-
}
|
|
123
|
-
return fixedOptions;
|
|
124
|
-
}), [ isValid, options, isNotSelected, extraOption, placeholder ]);
|
|
125
|
-
const handleChange = useEvent((ev => {
|
|
126
|
-
const idx = ev.target.selectedIndex;
|
|
127
|
-
const opt = fixedOptions[idx];
|
|
128
|
-
onChange?.({
|
|
129
|
-
value: opt.value,
|
|
130
|
-
index: idx,
|
|
131
|
-
type: "change",
|
|
132
|
-
timeStamp: ev.timeStamp,
|
|
133
|
-
target: ev.target
|
|
134
|
-
});
|
|
135
|
-
}));
|
|
136
|
-
const ref = useRef(null);
|
|
137
|
-
const refreshSelectedIndex = useCallback((() => {
|
|
138
|
-
if (!ref.current) return;
|
|
139
|
-
if (ref.current.selectedIndex < 0 || fixedOptions[ref.current.selectedIndex].value != value) {
|
|
140
|
-
ref.current.selectedIndex = fixedOptions.findIndex((opt => opt.value == value));
|
|
141
|
-
}
|
|
142
|
-
}), [ fixedOptions, value ]);
|
|
143
|
-
const setRef = el => {
|
|
144
|
-
ref.current = el;
|
|
145
|
-
refreshSelectedIndex();
|
|
146
|
-
};
|
|
147
|
-
useUpdateEffect$1((() => {
|
|
148
|
-
refreshSelectedIndex();
|
|
149
|
-
}), [ refreshSelectedIndex ]);
|
|
150
|
-
const fixer = new KeyFixer;
|
|
151
|
-
return jsx("select", {
|
|
152
|
-
...selectAttrs,
|
|
153
|
-
onChange: handleChange,
|
|
154
|
-
ref: setRef,
|
|
155
|
-
children: fixedOptions.map(((opt, idx) => {
|
|
156
|
-
const {value, text, key, ...optAttrs} = opt;
|
|
157
|
-
const fixedKey = fixer.fix(opt, idx);
|
|
158
|
-
return createElement("option", {
|
|
159
|
-
...optAttrs,
|
|
160
|
-
key: fixedKey,
|
|
161
|
-
value: fixedKey
|
|
162
|
-
}, opt.text);
|
|
163
|
-
}))
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function collapseWhitespace(str) {
|
|
168
|
-
if (!str) return "";
|
|
169
|
-
return String(str).replace(/\s+/gu, " ").trim();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const Input = forwardRef((function Input({value = "", onChange, onInput, onBlur, formatOnChange = identity, ...otherProps}, ref) {
|
|
173
|
-
const [currentValue, setCurrentValue] = useState(value);
|
|
174
|
-
const lastValue = useRef(value);
|
|
175
|
-
const modified = useRef(false);
|
|
176
|
-
useUpdateEffect$1((() => {
|
|
177
|
-
setCurrentValue(value);
|
|
178
|
-
modified.current = false;
|
|
179
|
-
lastValue.current = value;
|
|
180
|
-
}), [ value ]);
|
|
181
|
-
const props = {
|
|
182
|
-
type: "text",
|
|
183
|
-
...otherProps,
|
|
184
|
-
value: currentValue,
|
|
185
|
-
onChange: ev => {
|
|
186
|
-
setCurrentValue(ev.target.value);
|
|
187
|
-
},
|
|
188
|
-
onInput: ev => {
|
|
189
|
-
modified.current = true;
|
|
190
|
-
onInput?.(ev);
|
|
191
|
-
},
|
|
192
|
-
onBlur: ev => {
|
|
193
|
-
const formattedValue = formatOnChange(currentValue);
|
|
194
|
-
if (modified.current) {
|
|
195
|
-
if (formattedValue !== lastValue.current) {
|
|
196
|
-
onChange?.({
|
|
197
|
-
type: "change",
|
|
198
|
-
value: formattedValue,
|
|
199
|
-
timeStamp: ev.timeStamp,
|
|
200
|
-
target: ev.target
|
|
201
|
-
});
|
|
202
|
-
lastValue.current = formattedValue;
|
|
203
|
-
}
|
|
204
|
-
if (formattedValue !== ev.target.value) {
|
|
205
|
-
setCurrentValue(formattedValue);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
onBlur?.(ev);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
return jsx("input", {
|
|
212
|
-
...props,
|
|
213
|
-
ref
|
|
214
|
-
});
|
|
215
|
-
}));
|
|
216
|
-
|
|
217
|
-
function TextInput({formatOnChange = collapseWhitespace, ...otherProps}) {
|
|
218
|
-
return jsx(Input, {
|
|
219
|
-
formatOnChange,
|
|
220
|
-
...otherProps,
|
|
221
|
-
type: "text"
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const TextArea = forwardRef((function TextArea({onInput, style, initialHeight = "auto", ...rest}, fwdRef) {
|
|
226
|
-
const ref = useRef(null);
|
|
227
|
-
const [height, setHeight] = useState(initialHeight);
|
|
228
|
-
const adjustHeight = useCallback((() => {
|
|
229
|
-
const textarea = ref.current;
|
|
230
|
-
if (!textarea) return;
|
|
231
|
-
textarea.style.height = initialHeight;
|
|
232
|
-
const newHeight = `${textarea.scrollHeight}px`;
|
|
233
|
-
setHeight(newHeight);
|
|
234
|
-
textarea.style.height = newHeight;
|
|
235
|
-
}), [ initialHeight ]);
|
|
236
|
-
useImperativeHandle(fwdRef, (() => ({
|
|
237
|
-
element: ref.current,
|
|
238
|
-
adjustHeight
|
|
239
|
-
})), [ adjustHeight ]);
|
|
240
|
-
const input = useEventHandler((ev => {
|
|
241
|
-
adjustHeight();
|
|
242
|
-
onInput?.(ev);
|
|
243
|
-
}));
|
|
244
|
-
useLayoutEffect((() => {
|
|
245
|
-
adjustHeight();
|
|
246
|
-
const textarea = ref.current;
|
|
247
|
-
if (!textarea) return;
|
|
248
|
-
const resizeObserver = new ResizeObserver((entries => {
|
|
249
|
-
adjustHeight();
|
|
250
|
-
}));
|
|
251
|
-
resizeObserver.observe(textarea);
|
|
252
|
-
return () => {
|
|
253
|
-
resizeObserver.unobserve(textarea);
|
|
254
|
-
};
|
|
255
|
-
}), [ adjustHeight ]);
|
|
256
|
-
return jsx("textarea", {
|
|
257
|
-
...rest,
|
|
258
|
-
style: {
|
|
259
|
-
overflow: "hidden",
|
|
260
|
-
resize: "none",
|
|
261
|
-
...style,
|
|
262
|
-
height
|
|
263
|
-
},
|
|
264
|
-
onInput: input,
|
|
265
|
-
ref
|
|
266
|
-
});
|
|
267
|
-
}));
|
|
268
|
-
|
|
269
|
-
function RadioMenu(menu) {
|
|
270
|
-
const defaultId = useId();
|
|
271
|
-
const name = menu.name ?? defaultId;
|
|
272
|
-
const eq = menu.valueEquals ?? Object.is;
|
|
273
|
-
const fixedOptions = menu.options ?? [];
|
|
274
|
-
const fixer = new KeyFixer;
|
|
275
|
-
const onChange = useEventHandler((ev => {
|
|
276
|
-
const selectedIndex = Number(ev.target.value);
|
|
277
|
-
const selectedOption = fixedOptions[selectedIndex];
|
|
278
|
-
if (selectedOption != null && menu.onChange != null) {
|
|
279
|
-
menu.onChange({
|
|
280
|
-
value: selectedOption.value,
|
|
281
|
-
index: selectedIndex,
|
|
282
|
-
type: "change",
|
|
283
|
-
timeStamp: ev.timeStamp,
|
|
284
|
-
target: ev.target
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
}));
|
|
288
|
-
return jsx("ul", {
|
|
289
|
-
className: menu.className,
|
|
290
|
-
children: fixedOptions.map(((opt, idx) => {
|
|
291
|
-
const {value, text, key, itemClassName, labelClassName, inputClassName, textClassName, ...rest} = opt;
|
|
292
|
-
const fixedKey = fixer.fix(opt, idx);
|
|
293
|
-
if (menu.value !== undefined) {
|
|
294
|
-
rest.checked = eq(value, menu.value);
|
|
295
|
-
}
|
|
296
|
-
return jsx("li", {
|
|
297
|
-
className: itemClassName,
|
|
298
|
-
"aria-disabled": rest.disabled,
|
|
299
|
-
children: jsxs("label", {
|
|
300
|
-
className: labelClassName,
|
|
301
|
-
children: [ jsx("input", {
|
|
302
|
-
...rest,
|
|
303
|
-
className: inputClassName,
|
|
304
|
-
value: idx,
|
|
305
|
-
onChange,
|
|
306
|
-
name,
|
|
307
|
-
type: "radio"
|
|
308
|
-
}), jsx("span", {
|
|
309
|
-
className: textClassName,
|
|
310
|
-
children: text
|
|
311
|
-
}) ]
|
|
312
|
-
})
|
|
313
|
-
}, fixedKey);
|
|
314
|
-
}))
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export { Input, RadioMenu, Select, TextArea, TextInput };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import { EventCallback, HtmlInputElement, OverrideProps } from "../types/utility";
|
|
3
|
-
export type InputChangeEvent = {
|
|
4
|
-
value: string;
|
|
5
|
-
type: 'change';
|
|
6
|
-
timeStamp: number;
|
|
7
|
-
target: HtmlInputElement;
|
|
8
|
-
};
|
|
9
|
-
export type InputChangeEventHandler = EventCallback<InputChangeEvent>;
|
|
10
|
-
export type InputProps = OverrideProps<'input', {
|
|
11
|
-
onChange?: InputChangeEventHandler;
|
|
12
|
-
value?: string;
|
|
13
|
-
/**
|
|
14
|
-
* Function used to format value on blur.
|
|
15
|
-
*/
|
|
16
|
-
formatOnChange?: (value: string) => string;
|
|
17
|
-
}>;
|
|
18
|
-
export declare const Input: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "value" | "onChange" | "formatOnChange"> & {
|
|
19
|
-
onChange?: InputChangeEventHandler;
|
|
20
|
-
value?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Function used to format value on blur.
|
|
23
|
-
*/
|
|
24
|
-
formatOnChange?: (value: string) => string;
|
|
25
|
-
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { EventCallback, HtmlInputElement, NonNil, OverrideProps } from '../types/utility';
|
|
2
|
-
import { Key, ReactNode } from 'react';
|
|
3
|
-
import { Resolvable } from '../util/resolvable';
|
|
4
|
-
import { JSX } from 'react/jsx-runtime';
|
|
5
|
-
export type RadioMenuOption<T extends NonNil> = OverrideProps<'input', {
|
|
6
|
-
value: T;
|
|
7
|
-
text: ReactNode;
|
|
8
|
-
key?: Resolvable<Key, [RadioMenuOption<T>, number]>;
|
|
9
|
-
itemClassName?: string;
|
|
10
|
-
labelClassName?: string;
|
|
11
|
-
inputClassName?: string;
|
|
12
|
-
textClassName?: string;
|
|
13
|
-
}, 'type' | 'children' | 'checked' | 'name' | 'className'>;
|
|
14
|
-
export type RadioMenuChangeEvent<T> = {
|
|
15
|
-
value: T;
|
|
16
|
-
index: number;
|
|
17
|
-
type: 'change';
|
|
18
|
-
timeStamp: number;
|
|
19
|
-
target: HtmlInputElement;
|
|
20
|
-
};
|
|
21
|
-
export type RadioMenuChangeEventHandler<T> = EventCallback<RadioMenuChangeEvent<T>>;
|
|
22
|
-
export type RadioMenuProps<T extends NonNil> = {
|
|
23
|
-
options: RadioMenuOption<T>[];
|
|
24
|
-
value?: T | null;
|
|
25
|
-
className?: string;
|
|
26
|
-
/**
|
|
27
|
-
* Value comparison function. Defaults to {@linkcode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is|Object.is}
|
|
28
|
-
*/
|
|
29
|
-
valueEquals?: (a: T, b: T) => boolean;
|
|
30
|
-
onChange?: RadioMenuChangeEventHandler<T>;
|
|
31
|
-
name?: string;
|
|
32
|
-
};
|
|
33
|
-
export declare function RadioMenu<T extends NonNil>(menu: RadioMenuProps<T>): JSX.Element;
|