@mpen/react-basic-inputs 0.1.11 → 0.2.1

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.
@@ -0,0 +1,291 @@
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react/jsx-runtime"), require("react")) : typeof define === "function" && define.amd ? define(["exports", "react/jsx-runtime", "react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["@mpen/react-basic-inputs"] = {}, global.jsxRuntime, global.React));
3
+ })(this, function(exports2, jsxRuntime, React) {
4
+ "use strict";var __defProp = Object.defineProperty;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => {
7
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
+ return value;
9
+ };
10
+
11
+ const NOOP = Object.freeze(() => {
12
+ });
13
+ function identity(x) {
14
+ return x;
15
+ }
16
+ let useEventHandler;
17
+ if (typeof window !== "undefined") {
18
+ useEventHandler = (callback) => {
19
+ React.useDebugValue(callback);
20
+ const latestRef = React.useRef(useEvent_shouldNotBeInvokedBeforeMount);
21
+ React.useInsertionEffect(() => {
22
+ latestRef.current = callback;
23
+ }, [callback]);
24
+ const stableRef = React.useRef(null);
25
+ if (!stableRef.current) {
26
+ stableRef.current = function() {
27
+ return latestRef.current.apply(this, arguments);
28
+ };
29
+ }
30
+ return stableRef.current;
31
+ };
32
+ } else {
33
+ useEventHandler = NOOP;
34
+ }
35
+ function useEvent(handler) {
36
+ return useEventHandler(handler);
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
+ function useFirstMountState() {
42
+ var isFirst = React.useRef(true);
43
+ if (isFirst.current) {
44
+ isFirst.current = false;
45
+ return true;
46
+ }
47
+ return isFirst.current;
48
+ }
49
+ var useUpdateEffect = function(effect, deps) {
50
+ var isFirstMount = useFirstMountState();
51
+ React.useEffect(function() {
52
+ if (!isFirstMount) {
53
+ return effect();
54
+ }
55
+ }, deps);
56
+ };
57
+ function resolveValue(val, ...args) {
58
+ return typeof val === "function" ? val(...args) : val;
59
+ }
60
+ function defaultMakeKey(opt, idx) {
61
+ if (opt.key != null) {
62
+ return resolveValue(opt.key, opt, idx);
63
+ } else if (typeof opt.value === "string" || typeof opt.value === "number") {
64
+ return opt.value;
65
+ }
66
+ return idx;
67
+ }
68
+ class KeyFixer {
69
+ constructor() {
70
+ __publicField(this, "usedKeys", /* @__PURE__ */ new Map());
71
+ }
72
+ fix(opt, idx) {
73
+ let fixedKey = defaultMakeKey(opt, idx);
74
+ for (; ; ) {
75
+ let suffix = this.usedKeys.get(fixedKey);
76
+ if (suffix === void 0) {
77
+ this.usedKeys.set(fixedKey, 1);
78
+ break;
79
+ }
80
+ this.usedKeys.set(fixedKey, ++suffix);
81
+ fixedKey = `${fixedKey}(${suffix})`;
82
+ }
83
+ return fixedKey;
84
+ }
85
+ }
86
+ const defaultMakeInvalidValueOption = (value) => ({
87
+ value,
88
+ text: String(value),
89
+ disabled: true,
90
+ key: INVALID_OPTION_KEY
91
+ });
92
+ const PLACEHOLDER_KEY = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb";
93
+ const INVALID_OPTION_KEY = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
94
+ function Select({
95
+ options,
96
+ value,
97
+ invalidValueOption = defaultMakeInvalidValueOption,
98
+ onChange,
99
+ placeholder,
100
+ ...selectAttrs
101
+ }) {
102
+ const isNotSelected = value == null;
103
+ const isValid = React.useMemo(() => value != null && options.some((o) => o.value == value), [options, value]);
104
+ const extraOption = React.useMemo(() => {
105
+ if (value == null || !invalidValueOption)
106
+ return null;
107
+ return invalidValueOption(value);
108
+ }, [invalidValueOption, value]);
109
+ const fixedOptions = React.useMemo(() => {
110
+ if (isValid)
111
+ return options;
112
+ const fixedOptions2 = [...options];
113
+ if (isNotSelected) {
114
+ if (placeholder != null) {
115
+ fixedOptions2.unshift({ text: placeholder, hidden: true, value: null, key: PLACEHOLDER_KEY });
116
+ }
117
+ } else if (extraOption) {
118
+ fixedOptions2.push(extraOption);
119
+ }
120
+ return fixedOptions2;
121
+ }, [isValid, options, isNotSelected, extraOption, placeholder]);
122
+ const handleChange = useEvent((ev) => {
123
+ const idx = ev.target.selectedIndex;
124
+ const opt = fixedOptions[idx];
125
+ onChange == null ? void 0 : onChange({
126
+ value: opt.value,
127
+ // option: opt,
128
+ // event: ev,
129
+ index: idx,
130
+ type: "change",
131
+ timeStamp: ev.timeStamp,
132
+ target: ev.target
133
+ });
134
+ });
135
+ const ref = React.useRef(null);
136
+ const refreshSelectedIndex = React.useCallback(() => {
137
+ if (!ref.current)
138
+ 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(() => {
148
+ refreshSelectedIndex();
149
+ }, [refreshSelectedIndex]);
150
+ const fixer = new KeyFixer();
151
+ return /* @__PURE__ */ jsxRuntime.jsx("select", { ...selectAttrs, onChange: handleChange, ref: setRef, children: fixedOptions.map((opt, idx) => {
152
+ const { value: value2, text, key, ...optAttrs } = opt;
153
+ const fixedKey = fixer.fix(opt, idx);
154
+ return /* @__PURE__ */ React.createElement("option", { ...optAttrs, key: fixedKey, value: fixedKey }, opt.text);
155
+ }) });
156
+ }
157
+ function collapseWhitespace(str) {
158
+ if (!str)
159
+ return "";
160
+ return String(str).replace(/\s+/gu, " ").trim();
161
+ }
162
+ const Input = React.forwardRef(function Input2({ value = "", onChange, onInput, onBlur, formatOnChange = identity, ...otherProps }, ref) {
163
+ const [currentValue, setCurrentValue] = React.useState(value);
164
+ const lastValue = React.useRef(value);
165
+ const modified = React.useRef(false);
166
+ useUpdateEffect(() => {
167
+ setCurrentValue(value);
168
+ modified.current = false;
169
+ lastValue.current = value;
170
+ }, [value]);
171
+ const props = {
172
+ type: "text",
173
+ ...otherProps,
174
+ value: currentValue,
175
+ onChange: (ev) => {
176
+ setCurrentValue(ev.target.value);
177
+ },
178
+ // TODO: fire a change event onPaste ?
179
+ // formatOnPaste?
180
+ onInput: (ev) => {
181
+ modified.current = true;
182
+ onInput == null ? void 0 : onInput(ev);
183
+ },
184
+ onBlur: (ev) => {
185
+ const formattedValue = formatOnChange(currentValue);
186
+ if (modified.current) {
187
+ if (formattedValue !== lastValue.current) {
188
+ onChange == null ? void 0 : onChange({
189
+ type: "change",
190
+ value: formattedValue,
191
+ timeStamp: ev.timeStamp,
192
+ target: ev.target
193
+ });
194
+ lastValue.current = formattedValue;
195
+ }
196
+ if (formattedValue !== ev.target.value) {
197
+ setCurrentValue(formattedValue);
198
+ }
199
+ }
200
+ onBlur == null ? void 0 : onBlur(ev);
201
+ }
202
+ };
203
+ return /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, ref });
204
+ });
205
+ function TextInput({ formatOnChange = collapseWhitespace, ...otherProps }) {
206
+ return /* @__PURE__ */ jsxRuntime.jsx(Input, { formatOnChange, ...otherProps, type: "text" });
207
+ }
208
+ const TextArea = React.forwardRef(function TextArea2({
209
+ onInput,
210
+ style,
211
+ initialHeight = "auto",
212
+ ...rest
213
+ }, fwdRef) {
214
+ const ref = React.useRef(null);
215
+ const [height, setHeight] = React.useState(initialHeight);
216
+ const adjustHeight = React.useCallback(() => {
217
+ const textarea = ref.current;
218
+ if (!textarea)
219
+ return;
220
+ textarea.style.height = initialHeight;
221
+ const newHeight = `${textarea.scrollHeight}px`;
222
+ setHeight(newHeight);
223
+ textarea.style.height = newHeight;
224
+ }, [initialHeight]);
225
+ React.useImperativeHandle(fwdRef, () => ({
226
+ element: ref.current,
227
+ adjustHeight
228
+ }), [adjustHeight]);
229
+ const input = useEventHandler((ev) => {
230
+ adjustHeight();
231
+ onInput == null ? void 0 : onInput(ev);
232
+ });
233
+ React.useLayoutEffect(() => {
234
+ adjustHeight();
235
+ const textarea = ref.current;
236
+ if (!textarea)
237
+ return;
238
+ const resizeObserver = new ResizeObserver((_entries) => {
239
+ adjustHeight();
240
+ });
241
+ resizeObserver.observe(textarea);
242
+ return () => {
243
+ resizeObserver.unobserve(textarea);
244
+ };
245
+ }, [adjustHeight]);
246
+ return /* @__PURE__ */ jsxRuntime.jsx("textarea", { ...rest, style: {
247
+ overflow: "hidden",
248
+ // these 2 styles aren't needed if the caller sets them in CSS.
249
+ resize: "none",
250
+ ...style,
251
+ height
252
+ }, onInput: input, ref });
253
+ });
254
+ function RadioMenu(menu) {
255
+ const defaultId = React.useId();
256
+ const name = menu.name ?? defaultId;
257
+ const eq = menu.valueEquals ?? Object.is;
258
+ const fixedOptions = menu.options ?? [];
259
+ const fixer = new KeyFixer();
260
+ const onChange = useEventHandler((ev) => {
261
+ const selectedIndex = Number(ev.target.value);
262
+ const selectedOption = fixedOptions[selectedIndex];
263
+ if (selectedOption != null && menu.onChange != null) {
264
+ menu.onChange({
265
+ value: selectedOption.value,
266
+ index: selectedIndex,
267
+ type: "change",
268
+ timeStamp: ev.timeStamp,
269
+ target: ev.target
270
+ });
271
+ }
272
+ });
273
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: menu.className, children: fixedOptions.map((opt, idx) => {
274
+ const { value, text, key, itemClassName, labelClassName, inputClassName, textClassName, ...rest } = opt;
275
+ const fixedKey = fixer.fix(opt, idx);
276
+ if (menu.value !== void 0) {
277
+ rest.checked = eq(value, menu.value);
278
+ }
279
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: itemClassName, "aria-disabled": rest.disabled, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: labelClassName, children: [
280
+ /* @__PURE__ */ jsxRuntime.jsx("input", { ...rest, className: inputClassName, value: idx, onChange, name, type: "radio" }),
281
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: textClassName, children: text })
282
+ ] }) }, fixedKey);
283
+ }) });
284
+ }
285
+ exports2.Input = Input;
286
+ exports2.RadioMenu = RadioMenu;
287
+ exports2.Select = Select;
288
+ exports2.TextArea = TextArea;
289
+ exports2.TextInput = TextInput;
290
+ Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
291
+ });
package/package.json CHANGED
@@ -1,61 +1,46 @@
1
1
  {
2
2
  "name": "@mpen/react-basic-inputs",
3
- "version": "0.1.11",
4
- "packageManager": "yarn@3.5.0",
3
+ "private": false,
4
+ "version": "0.2.1",
5
+ "type": "module",
6
+ "files": ["dist"],
7
+ "main": "./dist/react-basic-inputs.umd.cjs",
8
+ "module": "./dist/react-basic-inputs.js",
5
9
  "exports": {
6
10
  ".": {
7
- "import": "./dist/bundle.mjs",
8
- "require": "./dist/bundle.cjs",
9
- "types": "./dist/bundle.d.ts"
11
+ "import": "./dist/react-basic-inputs.js",
12
+ "require": "./dist/react-basic-inputs.umd.cjs",
13
+ "types": "./dist/react-basic-inputs.d.ts"
10
14
  }
11
15
  },
12
- "type": "module",
13
- "files": [
14
- "./dist"
15
- ],
16
16
  "scripts": {
17
- "dev:build": "rollup -cw",
18
- "dev:serve": "serve -l tcp://0.0.0.0:8080",
19
- "dev": "run-p \"dev:**\"",
20
- "serve": "bun run --hot dev/serve.ts",
21
- "bundle:clean": "rimraf -g \"dist/*\"",
22
- "bundle:build": "rollup -c",
23
- "bundle": "run-s bundle:clean bundle:build",
24
- "patch": "npm version patch && VER=$(jq -r '.version' package.json) && hg ci -m \"Publish v$VER\" && hg tag \"v$VER\"",
25
- "release": "run-s bundle patch && npm publish --access=public && hg push"
17
+ "dev": "bun run --bun vite",
18
+ "build": "bun run --bun tsc && bun run --bun vite build",
19
+ "lint": "bun run --bun eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
20
+ "preview": "bun run --bun vite preview",
21
+ "_prepublishOnly": "bun run --bun build",
22
+ "publish": "npm publish --access=public"
23
+ },
24
+ "peerDependencies": {
25
+ "react": "^18.2.0",
26
+ "react-dom": "^18.2.0"
26
27
  },
27
28
  "devDependencies": {
28
- "@rollup/plugin-commonjs": "^25.0.4",
29
- "@rollup/plugin-node-resolve": "^15.2.1",
30
- "@rollup/plugin-replace": "^5.0.2",
31
- "@rollup/plugin-terser": "^0.4.3",
32
- "@rollup/plugin-typescript": "^11.1.3",
33
- "@types/eslint": "^8",
34
- "@types/jest": "^29.5.0",
35
- "@types/react": "^18.2.21",
36
- "@types/react-dom": "^18.2.7",
37
- "@typescript-eslint/eslint-plugin": "^5.57.1",
38
- "@typescript-eslint/parser": "^5.57.1",
39
- "eslint": "^8.38.0",
40
- "eslint-plugin-react": "^7.32.2",
29
+ "@types/bun": "^1.1.2",
30
+ "@types/react": "^18.2.66",
31
+ "@types/react-dom": "^18.2.22",
32
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
33
+ "@typescript-eslint/parser": "^7.2.0",
34
+ "@vitejs/plugin-react": "^4.2.1",
35
+ "eslint": "^8.57.0",
41
36
  "eslint-plugin-react-hooks": "^4.6.0",
42
- "jest": "^29.5.0",
37
+ "eslint-plugin-react-refresh": "^0.4.6",
43
38
  "npm-run-all": "^4.1.5",
44
- "react": ">=17 <19",
45
- "react-dom": ">=17 <19",
46
- "react-use": "^17.4.0",
47
- "rimraf": "^5.0.0",
48
- "rollup": "^3.20.2",
49
- "serve": "^14.2.0",
50
- "ts-jest": "^29.1.0",
51
- "tslib": "^2.5.0",
52
- "typescript": "^5.3.3"
53
- },
54
- "peerDependencies": {
55
- "react": ">=17 <19",
56
- "react-dom": ">=17 <19"
57
- },
58
- "dependencies": {
59
- "classcat": "^5.0.4"
39
+ "react": "^18.2.0",
40
+ "react-dom": "^18.2.0",
41
+ "react-use": "^17.5.0",
42
+ "typescript": "^5.2.2",
43
+ "vite": "^5.2.0",
44
+ "vite-plugin-dts": "^3.9.1"
60
45
  }
61
46
  }