@mpen/react-basic-inputs 0.1.7 → 0.1.8
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/dist/bundle.cjs +73 -18
- package/dist/bundle.d.ts +1 -0
- package/dist/bundle.mjs +74 -21
- package/dist/components/RadioMenu.d.ts +30 -0
- package/dist/util/assert.d.ts +1 -0
- package/dist/util/key-fixer.d.ts +8 -0
- package/package.json +4 -1
package/dist/bundle.cjs
CHANGED
|
@@ -63,13 +63,6 @@ var useUpdateEffect = function(effect, deps) {
|
|
|
63
63
|
|
|
64
64
|
var useUpdateEffect$1 = useUpdateEffect;
|
|
65
65
|
|
|
66
|
-
const defaultMakeInvalidValueOption = value => ({
|
|
67
|
-
value,
|
|
68
|
-
text: String(value),
|
|
69
|
-
disabled: true,
|
|
70
|
-
key: INVALID_OPTION_KEY
|
|
71
|
-
});
|
|
72
|
-
|
|
73
66
|
function defaultMakeKey(opt, idx) {
|
|
74
67
|
if (opt.key != null) {
|
|
75
68
|
return resolveValue(opt.key, opt, idx);
|
|
@@ -79,6 +72,30 @@ function defaultMakeKey(opt, idx) {
|
|
|
79
72
|
return idx;
|
|
80
73
|
}
|
|
81
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
|
+
|
|
82
99
|
const PLACEHOLDER_KEY = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb";
|
|
83
100
|
|
|
84
101
|
const INVALID_OPTION_KEY = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
|
|
@@ -132,23 +149,14 @@ function Select({options, value, invalidValueOption = defaultMakeInvalidValueOpt
|
|
|
132
149
|
useUpdateEffect$1((() => {
|
|
133
150
|
refreshSelectedIndex();
|
|
134
151
|
}), [ refreshSelectedIndex ]);
|
|
135
|
-
const
|
|
152
|
+
const fixer = new KeyFixer;
|
|
136
153
|
return jsxRuntime.jsx("select", {
|
|
137
154
|
...selectAttrs,
|
|
138
155
|
onChange: handleChange,
|
|
139
156
|
ref: setRef,
|
|
140
157
|
children: fixedOptions.map(((opt, idx) => {
|
|
141
158
|
const {value, text, key, ...optAttrs} = opt;
|
|
142
|
-
|
|
143
|
-
for (;;) {
|
|
144
|
-
let suffix = usedKeys.get(fixedKey);
|
|
145
|
-
if (suffix === undefined) {
|
|
146
|
-
usedKeys.set(fixedKey, 1);
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
usedKeys.set(fixedKey, ++suffix);
|
|
150
|
-
fixedKey = `${fixedKey}(${suffix})`;
|
|
151
|
-
}
|
|
159
|
+
const fixedKey = fixer.fix(opt, idx);
|
|
152
160
|
return React.createElement("option", {
|
|
153
161
|
...optAttrs,
|
|
154
162
|
key: fixedKey
|
|
@@ -259,8 +267,55 @@ const TextArea = React.forwardRef((function TextArea({onInput, style, initialHei
|
|
|
259
267
|
});
|
|
260
268
|
}));
|
|
261
269
|
|
|
270
|
+
function RadioMenu(menu) {
|
|
271
|
+
const defaultId = React.useId();
|
|
272
|
+
const name = menu.name ?? defaultId;
|
|
273
|
+
const eq = menu.valueEquals ?? Object.is;
|
|
274
|
+
const fixedOptions = menu.options ?? [];
|
|
275
|
+
const fixer = new KeyFixer;
|
|
276
|
+
const onChange = useEventHandler((ev => {
|
|
277
|
+
const selectedIndex = Number(ev.target.value);
|
|
278
|
+
const selectedOption = fixedOptions[selectedIndex];
|
|
279
|
+
if (selectedOption != null && menu.onChange != null) {
|
|
280
|
+
menu.onChange({
|
|
281
|
+
value: selectedOption.value,
|
|
282
|
+
index: selectedIndex,
|
|
283
|
+
type: "change",
|
|
284
|
+
timeStamp: ev.timeStamp,
|
|
285
|
+
target: ev.target
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}));
|
|
289
|
+
return jsxRuntime.jsx("ul", {
|
|
290
|
+
className: menu.className,
|
|
291
|
+
children: fixedOptions.map(((opt, idx) => {
|
|
292
|
+
const {value, text, key, itemClassName, ...rest} = opt;
|
|
293
|
+
const fixedKey = fixer.fix(opt, idx);
|
|
294
|
+
if (menu.value !== undefined) {
|
|
295
|
+
rest.checked = eq(value, menu.value);
|
|
296
|
+
}
|
|
297
|
+
return jsxRuntime.jsx("li", {
|
|
298
|
+
className: itemClassName,
|
|
299
|
+
children: jsxRuntime.jsxs("label", {
|
|
300
|
+
children: [ jsxRuntime.jsx("input", {
|
|
301
|
+
...rest,
|
|
302
|
+
value: idx,
|
|
303
|
+
onChange,
|
|
304
|
+
name,
|
|
305
|
+
type: "radio"
|
|
306
|
+
}), jsxRuntime.jsx("span", {
|
|
307
|
+
children: text
|
|
308
|
+
}) ]
|
|
309
|
+
})
|
|
310
|
+
}, fixedKey);
|
|
311
|
+
}))
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
262
315
|
exports.Input = Input;
|
|
263
316
|
|
|
317
|
+
exports.RadioMenu = RadioMenu;
|
|
318
|
+
|
|
264
319
|
exports.Select = Select;
|
|
265
320
|
|
|
266
321
|
exports.TextArea = TextArea;
|
package/dist/bundle.d.ts
CHANGED
package/dist/bundle.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
|
|
3
|
-
import { useDebugValue, useRef, useInsertionEffect, useEffect, useMemo, useCallback, createElement, forwardRef, useState, useImperativeHandle, useLayoutEffect } from "react";
|
|
3
|
+
import { useDebugValue, useRef, useInsertionEffect, useEffect, useMemo, useCallback, createElement, forwardRef, useState, useImperativeHandle, useLayoutEffect, useId } from "react";
|
|
4
4
|
|
|
5
5
|
const NOOP = Object.freeze((() => {}));
|
|
6
6
|
|
|
@@ -61,13 +61,6 @@ var useUpdateEffect = function(effect, deps) {
|
|
|
61
61
|
|
|
62
62
|
var useUpdateEffect$1 = useUpdateEffect;
|
|
63
63
|
|
|
64
|
-
const defaultMakeInvalidValueOption = value => ({
|
|
65
|
-
value,
|
|
66
|
-
text: String(value),
|
|
67
|
-
disabled: true,
|
|
68
|
-
key: INVALID_OPTION_KEY
|
|
69
|
-
});
|
|
70
|
-
|
|
71
64
|
function defaultMakeKey(opt, idx) {
|
|
72
65
|
if (opt.key != null) {
|
|
73
66
|
return resolveValue(opt.key, opt, idx);
|
|
@@ -77,6 +70,30 @@ function defaultMakeKey(opt, idx) {
|
|
|
77
70
|
return idx;
|
|
78
71
|
}
|
|
79
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
|
+
|
|
80
97
|
const PLACEHOLDER_KEY = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb";
|
|
81
98
|
|
|
82
99
|
const INVALID_OPTION_KEY = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
|
|
@@ -130,23 +147,14 @@ function Select({options, value, invalidValueOption = defaultMakeInvalidValueOpt
|
|
|
130
147
|
useUpdateEffect$1((() => {
|
|
131
148
|
refreshSelectedIndex();
|
|
132
149
|
}), [ refreshSelectedIndex ]);
|
|
133
|
-
const
|
|
150
|
+
const fixer = new KeyFixer;
|
|
134
151
|
return jsx("select", {
|
|
135
152
|
...selectAttrs,
|
|
136
153
|
onChange: handleChange,
|
|
137
154
|
ref: setRef,
|
|
138
155
|
children: fixedOptions.map(((opt, idx) => {
|
|
139
156
|
const {value, text, key, ...optAttrs} = opt;
|
|
140
|
-
|
|
141
|
-
for (;;) {
|
|
142
|
-
let suffix = usedKeys.get(fixedKey);
|
|
143
|
-
if (suffix === undefined) {
|
|
144
|
-
usedKeys.set(fixedKey, 1);
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
usedKeys.set(fixedKey, ++suffix);
|
|
148
|
-
fixedKey = `${fixedKey}(${suffix})`;
|
|
149
|
-
}
|
|
157
|
+
const fixedKey = fixer.fix(opt, idx);
|
|
150
158
|
return createElement("option", {
|
|
151
159
|
...optAttrs,
|
|
152
160
|
key: fixedKey
|
|
@@ -257,4 +265,49 @@ const TextArea = forwardRef((function TextArea({onInput, style, initialHeight =
|
|
|
257
265
|
});
|
|
258
266
|
}));
|
|
259
267
|
|
|
260
|
-
|
|
268
|
+
function RadioMenu(menu) {
|
|
269
|
+
const defaultId = useId();
|
|
270
|
+
const name = menu.name ?? defaultId;
|
|
271
|
+
const eq = menu.valueEquals ?? Object.is;
|
|
272
|
+
const fixedOptions = menu.options ?? [];
|
|
273
|
+
const fixer = new KeyFixer;
|
|
274
|
+
const onChange = useEventHandler((ev => {
|
|
275
|
+
const selectedIndex = Number(ev.target.value);
|
|
276
|
+
const selectedOption = fixedOptions[selectedIndex];
|
|
277
|
+
if (selectedOption != null && menu.onChange != null) {
|
|
278
|
+
menu.onChange({
|
|
279
|
+
value: selectedOption.value,
|
|
280
|
+
index: selectedIndex,
|
|
281
|
+
type: "change",
|
|
282
|
+
timeStamp: ev.timeStamp,
|
|
283
|
+
target: ev.target
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}));
|
|
287
|
+
return jsx("ul", {
|
|
288
|
+
className: menu.className,
|
|
289
|
+
children: fixedOptions.map(((opt, idx) => {
|
|
290
|
+
const {value, text, key, itemClassName, ...rest} = opt;
|
|
291
|
+
const fixedKey = fixer.fix(opt, idx);
|
|
292
|
+
if (menu.value !== undefined) {
|
|
293
|
+
rest.checked = eq(value, menu.value);
|
|
294
|
+
}
|
|
295
|
+
return jsx("li", {
|
|
296
|
+
className: itemClassName,
|
|
297
|
+
children: jsxs("label", {
|
|
298
|
+
children: [ jsx("input", {
|
|
299
|
+
...rest,
|
|
300
|
+
value: idx,
|
|
301
|
+
onChange,
|
|
302
|
+
name,
|
|
303
|
+
type: "radio"
|
|
304
|
+
}), jsx("span", {
|
|
305
|
+
children: text
|
|
306
|
+
}) ]
|
|
307
|
+
})
|
|
308
|
+
}, fixedKey);
|
|
309
|
+
}))
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export { Input, RadioMenu, Select, TextArea, TextInput };
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
}, 'type' | 'children' | 'checked' | 'name'>;
|
|
11
|
+
export type RadioMenuChangeEvent<T> = {
|
|
12
|
+
value: T;
|
|
13
|
+
index: number;
|
|
14
|
+
type: 'change';
|
|
15
|
+
timeStamp: number;
|
|
16
|
+
target: HtmlInputElement;
|
|
17
|
+
};
|
|
18
|
+
export type RadioMenuChangeEventHandler<T> = EventCallback<RadioMenuChangeEvent<T>>;
|
|
19
|
+
export type RadioMenuProps<T extends NonNil> = {
|
|
20
|
+
options: RadioMenuOption<T>[];
|
|
21
|
+
value?: T | null;
|
|
22
|
+
className?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Value comparison function. Defaults to {@linkcode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is|Object.is}
|
|
25
|
+
*/
|
|
26
|
+
valueEquals?: (a: T, b: T) => boolean;
|
|
27
|
+
onChange?: RadioMenuChangeEventHandler<T>;
|
|
28
|
+
name?: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function RadioMenu<T extends NonNil>(menu: RadioMenuProps<T>): JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cast<T>(val: any): asserts val is T;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpen/react-basic-inputs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"packageManager": "yarn@3.5.0",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -54,5 +54,8 @@
|
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"react": ">=17 <19",
|
|
56
56
|
"react-dom": ">=17 <19"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"classcat": "^5.0.4"
|
|
57
60
|
}
|
|
58
61
|
}
|