@mpen/react-basic-inputs 0.1.3 → 0.1.5

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 CHANGED
@@ -10,24 +10,34 @@ function identity(x) {
10
10
  return x;
11
11
  }
12
12
 
13
- let useEvent;
13
+ let useEventHandler;
14
14
 
15
15
  if (typeof window !== "undefined") {
16
- useEvent = handler => {
17
- React.useDebugValue(handler);
18
- const handlerRef = React.useRef(handler);
19
- React.useLayoutEffect((() => {
20
- handlerRef.current = handler;
21
- }), [ handler ]);
22
- return React.useCallback((ev => {
23
- handlerRef.current(ev);
24
- }), []);
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;
25
29
  };
26
30
  } else {
27
- useEvent = NOOP;
31
+ useEventHandler = NOOP;
32
+ }
33
+
34
+ function useEvent(handler) {
35
+ return useEventHandler(handler);
28
36
  }
29
37
 
30
- var useEvent$1 = useEvent;
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
+ }
31
41
 
32
42
  function resolveValue(val, ...args) {
33
43
  return typeof val === "function" ? val(...args) : val;
@@ -97,7 +107,7 @@ function Select({options, value, invalidValueOption = defaultMakeInvalidValueOpt
97
107
  }
98
108
  return fixedOptions;
99
109
  }), [ isValid, options, isNotSelected, extraOption, placeholder ]);
100
- const handleChange = useEvent$1((ev => {
110
+ const handleChange = useEvent((ev => {
101
111
  const idx = ev.target.selectedIndex;
102
112
  const opt = fixedOptions[idx];
103
113
  onChange?.({
@@ -205,8 +215,46 @@ function TextInput({formatOnChange = collapseWhitespace, ...otherProps}) {
205
215
  });
206
216
  }
207
217
 
218
+ const TextArea = React.forwardRef((function TextArea({onInput, style, ...rest}, fwdRef) {
219
+ const ref = React.useRef(null);
220
+ const [height, setHeight] = React.useState("auto");
221
+ const adjustHeight = () => {
222
+ const textarea = ref.current;
223
+ if (!textarea) return;
224
+ textarea.style.height = "auto";
225
+ const newHeight = `${textarea.scrollHeight}px`;
226
+ setHeight(newHeight);
227
+ textarea.style.height = newHeight;
228
+ };
229
+ React.useImperativeHandle(fwdRef, (() => ({
230
+ element: ref.current,
231
+ resize: adjustHeight
232
+ })), [ setHeight, ref.current ]);
233
+ const input = useEventHandler((ev => {
234
+ adjustHeight();
235
+ onInput?.(ev);
236
+ }));
237
+ React.useLayoutEffect((() => {
238
+ adjustHeight();
239
+ }), []);
240
+ return jsxRuntime.jsx("textarea", {
241
+ rows: 1,
242
+ ...rest,
243
+ style: {
244
+ ...style,
245
+ overflow: "hidden",
246
+ resize: "none",
247
+ height
248
+ },
249
+ onInput: input,
250
+ ref
251
+ });
252
+ }));
253
+
208
254
  exports.Input = Input;
209
255
 
210
256
  exports.Select = Select;
211
257
 
258
+ exports.TextArea = TextArea;
259
+
212
260
  exports.TextInput = TextInput;
package/dist/bundle.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './components/Select';
2
2
  export * from './components/TextInput';
3
3
  export * from './components/Input';
4
+ export * from './components/TextArea';
package/dist/bundle.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
 
3
- import { useDebugValue, useRef, useLayoutEffect, useCallback, useEffect, useMemo, createElement, forwardRef, useState } from "react";
3
+ import { useDebugValue, useRef, useInsertionEffect, useEffect, useMemo, useCallback, createElement, forwardRef, useState, useImperativeHandle, useLayoutEffect } from "react";
4
4
 
5
5
  const NOOP = Object.freeze((() => {}));
6
6
 
@@ -8,24 +8,34 @@ function identity(x) {
8
8
  return x;
9
9
  }
10
10
 
11
- let useEvent;
11
+ let useEventHandler;
12
12
 
13
13
  if (typeof window !== "undefined") {
14
- useEvent = handler => {
15
- useDebugValue(handler);
16
- const handlerRef = useRef(handler);
17
- useLayoutEffect((() => {
18
- handlerRef.current = handler;
19
- }), [ handler ]);
20
- return useCallback((ev => {
21
- handlerRef.current(ev);
22
- }), []);
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;
23
27
  };
24
28
  } else {
25
- useEvent = NOOP;
29
+ useEventHandler = NOOP;
30
+ }
31
+
32
+ function useEvent(handler) {
33
+ return useEventHandler(handler);
26
34
  }
27
35
 
28
- var useEvent$1 = useEvent;
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
+ }
29
39
 
30
40
  function resolveValue(val, ...args) {
31
41
  return typeof val === "function" ? val(...args) : val;
@@ -95,7 +105,7 @@ function Select({options, value, invalidValueOption = defaultMakeInvalidValueOpt
95
105
  }
96
106
  return fixedOptions;
97
107
  }), [ isValid, options, isNotSelected, extraOption, placeholder ]);
98
- const handleChange = useEvent$1((ev => {
108
+ const handleChange = useEvent((ev => {
99
109
  const idx = ev.target.selectedIndex;
100
110
  const opt = fixedOptions[idx];
101
111
  onChange?.({
@@ -203,4 +213,40 @@ function TextInput({formatOnChange = collapseWhitespace, ...otherProps}) {
203
213
  });
204
214
  }
205
215
 
206
- export { Input, Select, TextInput };
216
+ const TextArea = forwardRef((function TextArea({onInput, style, ...rest}, fwdRef) {
217
+ const ref = useRef(null);
218
+ const [height, setHeight] = useState("auto");
219
+ const adjustHeight = () => {
220
+ const textarea = ref.current;
221
+ if (!textarea) return;
222
+ textarea.style.height = "auto";
223
+ const newHeight = `${textarea.scrollHeight}px`;
224
+ setHeight(newHeight);
225
+ textarea.style.height = newHeight;
226
+ };
227
+ useImperativeHandle(fwdRef, (() => ({
228
+ element: ref.current,
229
+ resize: adjustHeight
230
+ })), [ setHeight, ref.current ]);
231
+ const input = useEventHandler((ev => {
232
+ adjustHeight();
233
+ onInput?.(ev);
234
+ }));
235
+ useLayoutEffect((() => {
236
+ adjustHeight();
237
+ }), []);
238
+ return jsx("textarea", {
239
+ rows: 1,
240
+ ...rest,
241
+ style: {
242
+ ...style,
243
+ overflow: "hidden",
244
+ resize: "none",
245
+ height
246
+ },
247
+ onInput: input,
248
+ ref
249
+ });
250
+ }));
251
+
252
+ export { Input, Select, TextArea, TextInput };
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import { HtmlTextAreaElement, OverrideProps, VoidFn } from '../types/utility';
3
+ export type TextAreaRef = {
4
+ element: HtmlTextAreaElement;
5
+ resize: VoidFn;
6
+ };
7
+ export type TextAreaProps = OverrideProps<'textarea', {}>;
8
+ export declare const TextArea: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref">, never> & import("react").RefAttributes<TextAreaRef>>;
@@ -1,6 +1,6 @@
1
- import { EventCallback } from "../types/utility";
1
+ import { AnyFn, EventCallback } from "../types/utility";
2
2
  /**
3
3
  * @see https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md
4
4
  */
5
- declare let useEvent: <T>(handler: EventCallback<T>) => (ev: T) => void;
6
- export default useEvent;
5
+ export declare let useEventHandler: <TCallback extends AnyFn>(callback: TCallback) => TCallback;
6
+ export default function useEvent<T>(handler: EventCallback<T>): EventCallback<T>;
@@ -20,6 +20,7 @@ export type OmitProps<Base extends import('react').ElementType, DeleteKeys exten
20
20
  export type MapKeyType<M> = M extends Map<infer K, any> ? K : never;
21
21
  export type MapValueType<M> = M extends Map<any, infer V> ? V : never;
22
22
  /** Hack to de-conflict React's HTMLInputElement vs the standard dom lib */
23
+ export type HtmlTextAreaElement = HTMLElementTagNameMap['textarea'];
23
24
  export type HtmlInputElement = HTMLElementTagNameMap['input'];
24
25
  export type HtmlSelectElement = HTMLElementTagNameMap['select'];
25
26
  export type HtmlInputChangeEvent = import('react').ChangeEvent<HtmlInputElement>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpen/react-basic-inputs",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "packageManager": "yarn@3.5.0",
5
5
  "exports": {
6
6
  ".": {
@@ -49,7 +49,7 @@
49
49
  "serve": "^14.2.0",
50
50
  "ts-jest": "^29.1.0",
51
51
  "tslib": "^2.5.0",
52
- "typescript": "^5.2.2"
52
+ "typescript": "^5.3.3"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "react": ">=17 <19",