@mpen/react-basic-inputs 0.2.5 → 0.2.7

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.
@@ -1,6 +1,7 @@
1
1
  import { ComponentPropsWithoutRef } from 'react';
2
2
  import { DetailedHTMLProps } from 'react';
3
3
  import { ElementType } from 'react';
4
+ import { FC } from 'react';
4
5
  import { ForwardRefExoticComponent } from 'react';
5
6
  import { InputHTMLAttributes } from 'react';
6
7
  import { JSX as JSX_2 } from 'react/jsx-runtime';
@@ -9,7 +10,11 @@ import { ReactNode } from 'react';
9
10
  import { RefAttributes } from 'react';
10
11
  import { TextareaHTMLAttributes } from 'react';
11
12
 
12
- export declare function DebouncedInput({ value: initialValue, onChange, debounce, ...props }: DebouncedInputProps): JSX_2.Element;
13
+ export declare function ActionButton({ onClick, ...props }: ActionButtonProps): JSX_2.Element;
14
+
15
+ export declare type ActionButtonProps = RequiredKeys<ComponentPropsWithoutRef<'button'>, 'onClick'>;
16
+
17
+ export declare const DebouncedInput: FC<DebouncedInputProps>;
13
18
 
14
19
  export declare type DebouncedInputChangeEvent = {
15
20
  value: string;
@@ -17,9 +22,16 @@ export declare type DebouncedInputChangeEvent = {
17
22
 
18
23
  export declare type DebouncedInputProps = OverrideProps<'input', {
19
24
  value: string;
25
+ /**
26
+ * Triggers after `debounce` milliseconds following an input change or immediately when the input loses focus.
27
+ */
20
28
  onChange: (ev: DebouncedInputChangeEvent) => void;
29
+ /**
30
+ * The delay in milliseconds before the `onChange` event is triggered. This delay is reset with each new input
31
+ * event.
32
+ */
21
33
  debounce?: number;
22
- }>;
34
+ }, 'defaultValue' | 'onInput' | 'onBlur'>;
23
35
 
24
36
  declare type EventCallback<T = never> = (ev: T) => void;
25
37
 
@@ -102,6 +114,8 @@ export declare type RadioMenuProps<T extends NonNil> = {
102
114
  name?: string;
103
115
  };
104
116
 
117
+ declare type RequiredKeys<Type, Key extends keyof Type> = Omit<Type, Key> & Required<Pick<Type, Key>>;
118
+
105
119
  declare type Resolvable<TValue = unknown, TArgs extends ReadonlyArray<unknown> = []> = TValue extends any ? TValue | ((...args: TArgs) => TValue) : never;
106
120
 
107
121
  export declare function Select<T extends NonNil>({ options, value, invalidValueOption, onChange, placeholder, ...selectAttrs }: SelectProps<T>): JSX_2.Element;
@@ -119,7 +133,7 @@ export declare type SelectChangeEventHandler<T> = EventCallback<SelectChangeEven
119
133
  export declare type SelectOption<T> = OverrideProps<'option', {
120
134
  value: T;
121
135
  text: ReactNode;
122
- key?: Resolvable<StrictKey, [SelectOption<T>, number]>;
136
+ uniqueKey?: Resolvable<string, [SelectOption<T>, number]>;
123
137
  }, 'children' | 'selected'>;
124
138
 
125
139
  export declare type SelectProps<T extends NonNil> = OverrideProps<'select', {
@@ -138,8 +152,6 @@ export declare type SelectProps<T extends NonNil> = OverrideProps<'select', {
138
152
  placeholder?: ReactNode;
139
153
  }, 'children' | 'defaultValue'>;
140
154
 
141
- declare type StrictKey = string | number;
142
-
143
155
  export declare const TextArea: ForwardRefExoticComponent<Omit<Omit<DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref">, "initialHeight"> & {
144
156
  /** Initial/minimum height. "0" or "auto" are good choices. Defaults to "auto" */
145
157
  initialHeight?: string | undefined;
@@ -162,3 +174,9 @@ export declare type TextInputProps = Omit<InputProps, 'text'>;
162
174
  declare type VoidFn = () => void;
163
175
 
164
176
  export { }
177
+
178
+
179
+ export declare namespace BasicOption {
180
+ var __is$option: boolean;
181
+ }
182
+
@@ -1,315 +1,266 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => {
4
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- return value;
6
- };
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
- import { useDebugValue, useRef, useInsertionEffect, useEffect, useMemo, useCallback, createElement, forwardRef, useState, useImperativeHandle, useLayoutEffect, useId } from "react";
9
- const NOOP = Object.freeze(() => {
1
+ var k = Object.defineProperty;
2
+ var M = (e, t, r) => t in e ? k(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
3
+ var O = (e, t, r) => (M(e, typeof t != "symbol" ? t + "" : t, r), r);
4
+ import { jsx as x, jsxs as V } from "react/jsx-runtime";
5
+ import { useDebugValue as D, useRef as v, useInsertionEffect as j, useEffect as q, useMemo as N, useCallback as w, createElement as H, forwardRef as R, useState as T, useImperativeHandle as L, useLayoutEffect as z, useId as F } from "react";
6
+ const $ = Object.freeze(() => {
10
7
  });
11
- function identity(x) {
12
- return x;
13
- }
14
- let useEventHandler;
15
- if (typeof window !== "undefined") {
16
- useEventHandler = (callback) => {
17
- useDebugValue(callback);
18
- const latestRef = useRef(useEvent_shouldNotBeInvokedBeforeMount);
19
- useInsertionEffect(() => {
20
- latestRef.current = callback;
21
- }, [callback]);
22
- const stableRef = 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;
8
+ function U(e) {
9
+ return e;
32
10
  }
33
- function useEvent(handler) {
34
- return useEventHandler(handler);
11
+ let b;
12
+ typeof window < "u" ? b = (e) => {
13
+ D(e);
14
+ const t = v(B);
15
+ j(() => {
16
+ t.current = e;
17
+ }, [e]);
18
+ const r = v(null);
19
+ return r.current || (r.current = function() {
20
+ return t.current.apply(this, arguments);
21
+ }), r.current;
22
+ } : b = $;
23
+ function Y(e) {
24
+ return b(e);
35
25
  }
36
- function useEvent_shouldNotBeInvokedBeforeMount() {
26
+ function B() {
37
27
  throw new Error("INVALID_USE_EVENT_INVOCATION: the callback from useEvent cannot be invoked before the component has mounted.");
38
28
  }
39
- function useFirstMountState() {
40
- var isFirst = useRef(true);
41
- if (isFirst.current) {
42
- isFirst.current = false;
43
- return true;
44
- }
45
- return isFirst.current;
29
+ function J() {
30
+ var e = v(!0);
31
+ return e.current ? (e.current = !1, !0) : e.current;
46
32
  }
47
- var useUpdateEffect = function(effect, deps) {
48
- var isFirstMount = useFirstMountState();
49
- useEffect(function() {
50
- if (!isFirstMount) {
51
- return effect();
52
- }
53
- }, deps);
33
+ var E = function(e, t) {
34
+ var r = J();
35
+ q(function() {
36
+ if (!r)
37
+ return e();
38
+ }, t);
54
39
  };
55
- function resolveValue(val, ...args) {
56
- return typeof val === "function" ? val(...args) : val;
40
+ function P(e, ...t) {
41
+ return typeof e == "function" ? e(...t) : e;
57
42
  }
58
- function defaultMakeKey(opt, idx) {
59
- if (opt.key != null) {
60
- return resolveValue(opt.key, opt, idx);
61
- } else if (typeof opt.value === "string" || typeof opt.value === "number") {
62
- return opt.value;
43
+ function W(e, t) {
44
+ if (e.uniqueKey != null)
45
+ return P(e.uniqueKey, e, t);
46
+ if (typeof e.value == "string")
47
+ return e.value;
48
+ if (typeof e.value == "number")
49
+ return String(e.value);
50
+ try {
51
+ const r = JSON.stringify(e.value);
52
+ if (r !== void 0)
53
+ return r;
54
+ } catch {
63
55
  }
64
- return idx;
56
+ return String(t);
65
57
  }
66
- class KeyFixer {
58
+ class _ {
67
59
  constructor() {
68
- __publicField(this, "usedKeys", /* @__PURE__ */ new Map());
60
+ O(this, "usedKeys", /* @__PURE__ */ new Map());
69
61
  }
70
- fix(opt, idx) {
71
- let fixedKey = defaultMakeKey(opt, idx);
62
+ fix(t, r) {
63
+ let s = W(t, r);
72
64
  for (; ; ) {
73
- let suffix = this.usedKeys.get(fixedKey);
74
- if (suffix === void 0) {
75
- this.usedKeys.set(fixedKey, 1);
65
+ let u = this.usedKeys.get(s);
66
+ if (u === void 0) {
67
+ this.usedKeys.set(s, 1);
76
68
  break;
77
69
  }
78
- this.usedKeys.set(fixedKey, ++suffix);
79
- fixedKey = `${fixedKey}(${suffix})`;
70
+ this.usedKeys.set(s, ++u), s = `${s}(${u})`;
80
71
  }
81
- return fixedKey;
72
+ return s;
82
73
  }
83
74
  }
84
- const defaultMakeInvalidValueOption = (value) => ({
85
- value,
86
- text: String(value),
87
- disabled: true,
88
- key: INVALID_OPTION_KEY
89
- });
90
- const PLACEHOLDER_KEY = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb";
91
- const INVALID_OPTION_KEY = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
92
- function Select({
93
- options,
94
- value,
95
- invalidValueOption = defaultMakeInvalidValueOption,
96
- onChange,
97
- placeholder,
98
- ...selectAttrs
75
+ const C = (e) => ({
76
+ value: e,
77
+ text: String(e),
78
+ disabled: !0,
79
+ key: Q
80
+ }), G = "3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb", Q = "1a53f789-77f5-4ce6-a829-b00e563f1ee8";
81
+ function se({
82
+ options: e,
83
+ value: t,
84
+ invalidValueOption: r = C,
85
+ onChange: s,
86
+ placeholder: u,
87
+ ...f
99
88
  }) {
100
- const isNotSelected = value == null;
101
- const isValid = useMemo(() => value != null && options.some((o) => o.value == value), [options, value]);
102
- const extraOption = useMemo(() => {
103
- if (value == null || !invalidValueOption)
104
- return null;
105
- return invalidValueOption(value);
106
- }, [invalidValueOption, value]);
107
- const fixedOptions = useMemo(() => {
108
- if (isValid)
109
- return options;
110
- const fixedOptions2 = [...options];
111
- if (isNotSelected) {
112
- if (placeholder != null) {
113
- fixedOptions2.unshift({ text: placeholder, hidden: true, value: null, key: PLACEHOLDER_KEY });
114
- }
115
- } else if (extraOption) {
116
- fixedOptions2.push(extraOption);
117
- }
118
- return fixedOptions2;
119
- }, [isValid, options, isNotSelected, extraOption, placeholder]);
120
- const handleChange = useEvent((ev) => {
121
- const idx = ev.target.selectedIndex;
122
- const opt = fixedOptions[idx];
123
- onChange == null ? void 0 : onChange({
124
- value: opt.value,
89
+ const l = t == null, o = N(() => t != null && e.some((n) => n.value == t), [e, t]), d = N(() => t == null || !r ? null : r(t), [r, t]), i = N(() => {
90
+ if (o)
91
+ return e;
92
+ const n = [...e];
93
+ return l ? u != null && n.unshift({ text: u, hidden: !0, value: null, key: G }) : d && n.push(d), n;
94
+ }, [o, e, l, d, u]), y = Y((n) => {
95
+ const p = n.target.selectedIndex, g = i[p];
96
+ s == null || s({
97
+ value: g.value,
125
98
  // option: opt,
126
99
  // event: ev,
127
- index: idx,
100
+ index: p,
128
101
  type: "change",
129
- timeStamp: ev.timeStamp,
130
- target: ev.target
102
+ timeStamp: n.timeStamp,
103
+ target: n.target
131
104
  });
132
- });
133
- const ref = useRef(null);
134
- const refreshSelectedIndex = useCallback(() => {
135
- if (!ref.current)
136
- return;
137
- if (ref.current.selectedIndex < 0 || fixedOptions[ref.current.selectedIndex].value != value) {
138
- ref.current.selectedIndex = fixedOptions.findIndex((opt) => opt.value == value);
139
- }
140
- }, [fixedOptions, value]);
141
- const setRef = (el) => {
142
- ref.current = el;
143
- refreshSelectedIndex();
105
+ }), c = v(null), a = w(() => {
106
+ c.current && (c.current.selectedIndex < 0 || i[c.current.selectedIndex].value != t) && (c.current.selectedIndex = i.findIndex((n) => n.value == t));
107
+ }, [i, t]), h = (n) => {
108
+ c.current = n, a();
144
109
  };
145
- useUpdateEffect(() => {
146
- refreshSelectedIndex();
147
- }, [refreshSelectedIndex]);
148
- const fixer = new KeyFixer();
149
- return /* @__PURE__ */ jsx("select", { ...selectAttrs, onChange: handleChange, ref: setRef, children: fixedOptions.map((opt, idx) => {
150
- const { value: value2, text, key, ...optAttrs } = opt;
151
- const fixedKey = fixer.fix(opt, idx);
152
- return /* @__PURE__ */ createElement("option", { ...optAttrs, key: fixedKey, value: fixedKey }, opt.text);
110
+ E(() => {
111
+ a();
112
+ }, [a]);
113
+ const m = new _();
114
+ return /* @__PURE__ */ x("select", { ...f, onChange: y, ref: h, children: i.map((n, p) => {
115
+ const { value: g, text: ee, uniqueKey: te, ...A } = n, S = m.fix(n, p);
116
+ return /* @__PURE__ */ H("option", { ...A, key: S, value: S }, n.text);
153
117
  }) });
154
118
  }
155
- function collapseWhitespace(str) {
156
- if (!str)
157
- return "";
158
- return String(str).replace(/\s+/gu, " ").trim();
119
+ function X(e) {
120
+ return e ? String(e).replace(/\s+/gu, " ").trim() : "";
159
121
  }
160
- const Input = forwardRef(function Input2({ value = "", onChange, onInput, onBlur, formatOnChange = identity, ...otherProps }, ref) {
161
- const [currentValue, setCurrentValue] = useState(value);
162
- const lastValue = useRef(value);
163
- const modified = useRef(false);
164
- useUpdateEffect(() => {
165
- setCurrentValue(value);
166
- modified.current = false;
167
- lastValue.current = value;
168
- }, [value]);
169
- const props = {
122
+ const Z = R(function({ value: t = "", onPaste: r, onChange: s, onInput: u, onBlur: f, formatOnChange: l = U, ...o }, d) {
123
+ const [i, y] = T(t), c = v(t), a = v(!1);
124
+ E(() => {
125
+ y(t), a.current = !1, c.current = t;
126
+ }, [t]);
127
+ const h = {
170
128
  type: "text",
171
- ...otherProps,
172
- value: currentValue,
173
- onChange: (ev) => {
174
- setCurrentValue(ev.target.value);
129
+ ...o,
130
+ ref: d,
131
+ value: i,
132
+ onChange: (m) => {
133
+ y(m.target.value);
175
134
  },
176
135
  // TODO: fire a change event onPaste ?
177
136
  // formatOnPaste?
178
- onInput: (ev) => {
179
- modified.current = true;
180
- onInput == null ? void 0 : onInput(ev);
137
+ // onPaste: ev => {
138
+ // ev.preventDefault()
139
+ //
140
+ // const clipboard = formatOnChange(ev.clipboardData.getData('text/plain'))
141
+ // const selectionStart = ev.currentTarget.selectionStart ?? 0
142
+ // const newText = ev.currentTarget.selectionStart == null
143
+ // ? clipboard : ev.currentTarget.value.slice(0,ev.currentTarget.selectionStart) + clipboard + ev.currentTarget.value.slice(ev.currentTarget.selectionEnd ?? ev.currentTarget.selectionStart)
144
+ // setCurrentValue(newText)
145
+ // ev.currentTarget.value = newText
146
+ // ev.currentTarget.setSelectionRange(selectionStart+clipboard.length, selectionStart+clipboard.length)
147
+ // onPaste?.(ev)
148
+ // // ev.preventDefault()
149
+ // // setCurrentValue(formatOnChange(ev.clipboardData.getData('text/plain')))
150
+ // },
151
+ onInput: (m) => {
152
+ a.current = !0, u == null || u(m);
181
153
  },
182
- onBlur: (ev) => {
183
- const formattedValue = formatOnChange(currentValue);
184
- if (modified.current) {
185
- if (formattedValue !== lastValue.current) {
186
- onChange == null ? void 0 : onChange({
187
- type: "change",
188
- value: formattedValue,
189
- timeStamp: ev.timeStamp,
190
- target: ev.target
191
- });
192
- lastValue.current = formattedValue;
193
- }
194
- if (formattedValue !== ev.target.value) {
195
- setCurrentValue(formattedValue);
196
- }
197
- }
198
- onBlur == null ? void 0 : onBlur(ev);
154
+ onBlur: (m) => {
155
+ const n = l(i);
156
+ a.current && (n !== c.current && (s == null || s({
157
+ type: "change",
158
+ value: n,
159
+ timeStamp: m.timeStamp,
160
+ target: m.target
161
+ }), c.current = n), n !== m.target.value && y(n)), f == null || f(m);
199
162
  }
200
163
  };
201
- return /* @__PURE__ */ jsx("input", { ...props, ref });
164
+ return /* @__PURE__ */ x("input", { ...h });
202
165
  });
203
- function TextInput({ formatOnChange = collapseWhitespace, ...otherProps }) {
204
- return /* @__PURE__ */ jsx(Input, { formatOnChange, ...otherProps, type: "text" });
166
+ function ce({ formatOnChange: e = X, ...t }) {
167
+ return /* @__PURE__ */ x(Z, { formatOnChange: e, ...t, type: "text" });
205
168
  }
206
- const TextArea = forwardRef(function TextArea2({
207
- onInput,
208
- style,
209
- initialHeight = "auto",
210
- ...rest
211
- }, fwdRef) {
212
- const ref = useRef(null);
213
- const [height, setHeight] = useState(initialHeight);
214
- const adjustHeight = useCallback(() => {
215
- const textarea = ref.current;
216
- if (!textarea)
169
+ const ie = R(function({
170
+ onInput: t,
171
+ style: r,
172
+ initialHeight: s = "auto",
173
+ ...u
174
+ }, f) {
175
+ const l = v(null), [o, d] = T(s), i = w(() => {
176
+ const c = l.current;
177
+ if (!c)
217
178
  return;
218
- textarea.style.height = initialHeight;
219
- const newHeight = `${textarea.scrollHeight}px`;
220
- setHeight(newHeight);
221
- textarea.style.height = newHeight;
222
- }, [initialHeight]);
223
- useImperativeHandle(fwdRef, () => ({
224
- element: ref.current,
225
- adjustHeight
226
- }), [adjustHeight]);
227
- const input = useEventHandler((ev) => {
228
- adjustHeight();
229
- onInput == null ? void 0 : onInput(ev);
179
+ c.style.height = s;
180
+ const a = `${c.scrollHeight}px`;
181
+ d(a), c.style.height = a;
182
+ }, [s]);
183
+ L(f, () => ({
184
+ element: l.current,
185
+ adjustHeight: i
186
+ }), [i]);
187
+ const y = b((c) => {
188
+ i(), t == null || t(c);
230
189
  });
231
- useLayoutEffect(() => {
232
- adjustHeight();
233
- const textarea = ref.current;
234
- if (!textarea)
190
+ return z(() => {
191
+ i();
192
+ const c = l.current;
193
+ if (!c)
235
194
  return;
236
- const resizeObserver = new ResizeObserver((_entries) => {
237
- adjustHeight();
195
+ const a = new ResizeObserver((h) => {
196
+ i();
238
197
  });
239
- resizeObserver.observe(textarea);
240
- return () => {
241
- resizeObserver.unobserve(textarea);
198
+ return a.observe(c), () => {
199
+ a.unobserve(c);
242
200
  };
243
- }, [adjustHeight]);
244
- return /* @__PURE__ */ jsx("textarea", { ...rest, style: {
201
+ }, [i]), /* @__PURE__ */ x("textarea", { ...u, style: {
245
202
  overflow: "hidden",
246
203
  // these 2 styles aren't needed if the caller sets them in CSS.
247
204
  resize: "none",
248
- ...style,
249
- height
250
- }, onInput: input, ref });
205
+ ...r,
206
+ height: o
207
+ }, onInput: y, ref: l });
251
208
  });
252
- function RadioMenu(menu) {
253
- const defaultId = useId();
254
- const name = menu.name ?? defaultId;
255
- const eq = menu.valueEquals ?? Object.is;
256
- const fixedOptions = menu.options ?? [];
257
- const fixer = new KeyFixer();
258
- const onChange = useEventHandler((ev) => {
259
- const selectedIndex = Number(ev.target.value);
260
- const selectedOption = fixedOptions[selectedIndex];
261
- if (selectedOption != null && menu.onChange != null) {
262
- menu.onChange({
263
- value: selectedOption.value,
264
- index: selectedIndex,
265
- type: "change",
266
- timeStamp: ev.timeStamp,
267
- target: ev.target
268
- });
269
- }
209
+ function ae(e) {
210
+ const t = F(), r = e.name ?? t, s = e.valueEquals ?? Object.is, u = e.options ?? [], f = new _(), l = b((o) => {
211
+ const d = Number(o.target.value), i = u[d];
212
+ i != null && e.onChange != null && e.onChange({
213
+ value: i.value,
214
+ index: d,
215
+ type: "change",
216
+ timeStamp: o.timeStamp,
217
+ target: o.target
218
+ });
270
219
  });
271
- return /* @__PURE__ */ jsx("ul", { className: menu.className, children: fixedOptions.map((opt, idx) => {
272
- const { value, text, key, itemClassName, labelClassName, inputClassName, textClassName, ...rest } = opt;
273
- const fixedKey = fixer.fix(opt, idx);
274
- if (menu.value !== void 0) {
275
- rest.checked = eq(value, menu.value);
276
- }
277
- return /* @__PURE__ */ jsx("li", { className: itemClassName, "aria-disabled": rest.disabled, children: /* @__PURE__ */ jsxs("label", { className: labelClassName, children: [
278
- /* @__PURE__ */ jsx("input", { ...rest, className: inputClassName, value: idx, onChange, name, type: "radio" }),
279
- /* @__PURE__ */ jsx("span", { className: textClassName, children: text })
280
- ] }) }, fixedKey);
220
+ return /* @__PURE__ */ x("ul", { className: e.className, children: u.map((o, d) => {
221
+ const { value: i, text: y, key: c, itemClassName: a, labelClassName: h, inputClassName: m, textClassName: n, ...p } = o, g = f.fix(o, d);
222
+ return e.value !== void 0 && (p.checked = s(i, e.value)), /* @__PURE__ */ x("li", { className: a, "aria-disabled": p.disabled, children: /* @__PURE__ */ V("label", { className: h, children: [
223
+ /* @__PURE__ */ x("input", { ...p, className: m, value: d, onChange: l, name: r, type: "radio" }),
224
+ /* @__PURE__ */ x("span", { className: n, children: y })
225
+ ] }) }, g);
281
226
  }) });
282
227
  }
283
- function useBox(value) {
284
- const ref = useRef(value);
285
- ref.current = value;
286
- return ref;
228
+ function K() {
229
+ return v(null);
287
230
  }
288
- function DebouncedInput({
289
- value: initialValue,
290
- onChange,
291
- debounce = 500,
292
- ...props
293
- }) {
294
- const [value, setValue] = useState(initialValue);
295
- const onChangeRef = useBox(onChange);
296
- const debounceRef = useBox(debounce);
297
- useEffect(() => {
298
- setValue(initialValue);
299
- }, [initialValue]);
300
- useEffect(() => {
301
- const timeout = setTimeout(() => {
302
- onChangeRef.current({ value });
303
- }, debounceRef.current);
304
- return () => clearTimeout(timeout);
305
- }, [debounceRef, onChangeRef, value]);
306
- return /* @__PURE__ */ jsx("input", { ...props, value, onChange: (e) => setValue(e.target.value) });
231
+ function I(e) {
232
+ e.current != null && (clearTimeout(e.current), e.current = null);
233
+ }
234
+ const fe = ({
235
+ value: e,
236
+ onChange: t,
237
+ debounce: r = 500,
238
+ ...s
239
+ }) => {
240
+ const u = K(), f = K();
241
+ E(() => {
242
+ I(f), u.current != null && (u.current.value = e);
243
+ }, [e]);
244
+ const l = () => {
245
+ u.current != null && u.current.value !== e && (t == null || t({ value: u.current.value }));
246
+ };
247
+ return /* @__PURE__ */ x("input", { ...s, ref: u, defaultValue: e, onInput: () => {
248
+ I(f), f.current = setTimeout(l, r);
249
+ }, onBlur: () => {
250
+ I(f), l();
251
+ } });
252
+ };
253
+ function le({ onClick: e, ...t }) {
254
+ return t.onClick = (r) => {
255
+ r.preventDefault(), e == null || e(r);
256
+ }, /* @__PURE__ */ x("button", { type: "button", ...t });
307
257
  }
308
258
  export {
309
- DebouncedInput,
310
- Input,
311
- RadioMenu,
312
- Select,
313
- TextArea,
314
- TextInput
259
+ le as ActionButton,
260
+ fe as DebouncedInput,
261
+ Z as Input,
262
+ ae as RadioMenu,
263
+ se as Select,
264
+ ie as TextArea,
265
+ ce as TextInput
315
266
  };
@@ -1,317 +1 @@
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
- function useBox(value) {
286
- const ref = React.useRef(value);
287
- ref.current = value;
288
- return ref;
289
- }
290
- function DebouncedInput({
291
- value: initialValue,
292
- onChange,
293
- debounce = 500,
294
- ...props
295
- }) {
296
- const [value, setValue] = React.useState(initialValue);
297
- const onChangeRef = useBox(onChange);
298
- const debounceRef = useBox(debounce);
299
- React.useEffect(() => {
300
- setValue(initialValue);
301
- }, [initialValue]);
302
- React.useEffect(() => {
303
- const timeout = setTimeout(() => {
304
- onChangeRef.current({ value });
305
- }, debounceRef.current);
306
- return () => clearTimeout(timeout);
307
- }, [debounceRef, onChangeRef, value]);
308
- return /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, value, onChange: (e) => setValue(e.target.value) });
309
- }
310
- exports2.DebouncedInput = DebouncedInput;
311
- exports2.Input = Input;
312
- exports2.RadioMenu = RadioMenu;
313
- exports2.Select = Select;
314
- exports2.TextArea = TextArea;
315
- exports2.TextInput = TextInput;
316
- Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
317
- });
1
+ (function(l,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],s):(l=typeof globalThis<"u"?globalThis:l||self,s(l["@mpen/react-basic-inputs"]={},l.jsxRuntime,l.React))})(this,function(l,s,n){"use strict";var J=Object.defineProperty;var W=(l,s,n)=>s in l?J(l,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):l[s]=n;var w=(l,s,n)=>(W(l,typeof s!="symbol"?s+"":s,n),n);const M=Object.freeze(()=>{});function A(e){return e}let g;typeof window<"u"?g=e=>{n.useDebugValue(e);const t=n.useRef(_);n.useInsertionEffect(()=>{t.current=e},[e]);const r=n.useRef(null);return r.current||(r.current=function(){return t.current.apply(this,arguments)}),r.current}:g=M;function j(e){return g(e)}function _(){throw new Error("INVALID_USE_EVENT_INVOCATION: the callback from useEvent cannot be invoked before the component has mounted.")}function k(){var e=n.useRef(!0);return e.current?(e.current=!1,!0):e.current}var N=function(e,t){var r=k();n.useEffect(function(){if(!r)return e()},t)};function q(e,...t){return typeof e=="function"?e(...t):e}function D(e,t){if(e.uniqueKey!=null)return q(e.uniqueKey,e,t);if(typeof e.value=="string")return e.value;if(typeof e.value=="number")return String(e.value);try{const r=JSON.stringify(e.value);if(r!==void 0)return r}catch{}return String(t)}class E{constructor(){w(this,"usedKeys",new Map)}fix(t,r){let f=D(t,r);for(;;){let c=this.usedKeys.get(f);if(c===void 0){this.usedKeys.set(f,1);break}this.usedKeys.set(f,++c),f=`${f}(${c})`}return f}}const V=e=>({value:e,text:String(e),disabled:!0,key:L}),H="3c9369b7-0a5e-46ea-93c2-e8b9fec67fdb",L="1a53f789-77f5-4ce6-a829-b00e563f1ee8";function z({options:e,value:t,invalidValueOption:r=V,onChange:f,placeholder:c,...d}){const x=t==null,y=n.useMemo(()=>t!=null&&e.some(u=>u.value==t),[e,t]),m=n.useMemo(()=>t==null||!r?null:r(t),[r,t]),a=n.useMemo(()=>{if(y)return e;const u=[...e];return x?c!=null&&u.unshift({text:c,hidden:!0,value:null,key:H}):m&&u.push(m),u},[y,e,x,m,c]),h=j(u=>{const b=u.target.selectedIndex,I=a[b];f==null||f({value:I.value,index:b,type:"change",timeStamp:u.timeStamp,target:u.target})}),i=n.useRef(null),o=n.useCallback(()=>{i.current&&(i.current.selectedIndex<0||a[i.current.selectedIndex].value!=t)&&(i.current.selectedIndex=a.findIndex(u=>u.value==t))},[a,t]),v=u=>{i.current=u,o()};N(()=>{o()},[o]);const p=new E;return s.jsx("select",{...d,onChange:h,ref:v,children:a.map((u,b)=>{const{value:I,text:G,uniqueKey:Q,...C}=u,T=p.fix(u,b);return n.createElement("option",{...C,key:T,value:T},u.text)})})}function F(e){return e?String(e).replace(/\s+/gu," ").trim():""}const O=n.forwardRef(function({value:t="",onPaste:r,onChange:f,onInput:c,onBlur:d,formatOnChange:x=A,...y},m){const[a,h]=n.useState(t),i=n.useRef(t),o=n.useRef(!1);N(()=>{h(t),o.current=!1,i.current=t},[t]);const v={type:"text",...y,ref:m,value:a,onChange:p=>{h(p.target.value)},onInput:p=>{o.current=!0,c==null||c(p)},onBlur:p=>{const u=x(a);o.current&&(u!==i.current&&(f==null||f({type:"change",value:u,timeStamp:p.timeStamp,target:p.target}),i.current=u),u!==p.target.value&&h(u)),d==null||d(p)}};return s.jsx("input",{...v})});function $({formatOnChange:e=F,...t}){return s.jsx(O,{formatOnChange:e,...t,type:"text"})}const B=n.forwardRef(function({onInput:t,style:r,initialHeight:f="auto",...c},d){const x=n.useRef(null),[y,m]=n.useState(f),a=n.useCallback(()=>{const i=x.current;if(!i)return;i.style.height=f;const o=`${i.scrollHeight}px`;m(o),i.style.height=o},[f]);n.useImperativeHandle(d,()=>({element:x.current,adjustHeight:a}),[a]);const h=g(i=>{a(),t==null||t(i)});return n.useLayoutEffect(()=>{a();const i=x.current;if(!i)return;const o=new ResizeObserver(v=>{a()});return o.observe(i),()=>{o.unobserve(i)}},[a]),s.jsx("textarea",{...c,style:{overflow:"hidden",resize:"none",...r,height:y},onInput:h,ref:x})});function P(e){const t=n.useId(),r=e.name??t,f=e.valueEquals??Object.is,c=e.options??[],d=new E,x=g(y=>{const m=Number(y.target.value),a=c[m];a!=null&&e.onChange!=null&&e.onChange({value:a.value,index:m,type:"change",timeStamp:y.timeStamp,target:y.target})});return s.jsx("ul",{className:e.className,children:c.map((y,m)=>{const{value:a,text:h,key:i,itemClassName:o,labelClassName:v,inputClassName:p,textClassName:u,...b}=y,I=d.fix(y,m);return e.value!==void 0&&(b.checked=f(a,e.value)),s.jsx("li",{className:o,"aria-disabled":b.disabled,children:s.jsxs("label",{className:v,children:[s.jsx("input",{...b,className:p,value:m,onChange:x,name:r,type:"radio"}),s.jsx("span",{className:u,children:h})]})},I)})})}function K(){return n.useRef(null)}function S(e){e.current!=null&&(clearTimeout(e.current),e.current=null)}const U=({value:e,onChange:t,debounce:r=500,...f})=>{const c=K(),d=K();N(()=>{S(d),c.current!=null&&(c.current.value=e)},[e]);const x=()=>{c.current!=null&&c.current.value!==e&&(t==null||t({value:c.current.value}))};return s.jsx("input",{...f,ref:c,defaultValue:e,onInput:()=>{S(d),d.current=setTimeout(x,r)},onBlur:()=>{S(d),x()}})};function Y({onClick:e,...t}){return t.onClick=r=>{r.preventDefault(),e==null||e(r)},s.jsx("button",{type:"button",...t})}l.ActionButton=Y,l.DebouncedInput=U,l.Input=O,l.RadioMenu=P,l.Select=z,l.TextArea=B,l.TextInput=$,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mpen/react-basic-inputs",
3
3
  "private": false,
4
- "version": "0.2.5",
4
+ "version": "0.2.7",
5
5
  "type": "module",
6
6
  "files": ["dist"],
7
7
  "main": "./dist/react-basic-inputs.umd.cjs",
@@ -24,10 +24,10 @@
24
24
  "_publish": "npm publish --access=public"
25
25
  },
26
26
  "peerDependencies": {
27
- "react": "^18.2.0",
28
- "react-dom": "^18.2.0"
27
+ "react": "^18.2.0"
29
28
  },
30
29
  "devDependencies": {
30
+ "@mpen/is-type": "^0.1.11",
31
31
  "@types/bun": "^1.1.2",
32
32
  "@types/react": "^18.2.66",
33
33
  "@types/react-dom": "^18.2.22",
@@ -38,11 +38,11 @@
38
38
  "eslint-plugin-react-hooks": "^4.6.0",
39
39
  "eslint-plugin-react-refresh": "^0.4.6",
40
40
  "npm-run-all": "^4.1.5",
41
- "react": "^18.2.0",
42
- "react-dom": "^18.2.0",
41
+ "react": "^18.3.1",
42
+ "react-dom": "^18.3.1",
43
43
  "react-use": "^17.5.0",
44
44
  "sass": "^1.77.2",
45
- "typescript": "^5.2.2",
45
+ "typescript": "^5.4.5",
46
46
  "vite": "^5.2.0",
47
47
  "vite-plugin-dts": "^3.9.1"
48
48
  }