This commit is contained in:
2026-10-01 08:02:47 +01:00
parent 6392457ffb
commit 3dc9f12ad4
104 changed files with 6536 additions and 1037 deletions
+67 -19
View File
@@ -1,16 +1,16 @@
import React, {
ComponentProps,
DetailedHTMLProps,
InputHTMLAttributes,
LabelHTMLAttributes,
ReactNode,
RefObject,
TextareaHTMLAttributes,
type ComponentProps,
type DetailedHTMLProps,
type InputHTMLAttributes,
type LabelHTMLAttributes,
type ReactNode,
type RefObject,
type TextareaHTMLAttributes,
useRef,
} from "react";
import { twMerge } from "tailwind-merge";
import Span from "../../layout/Span";
import { Eye, EyeOff, Info, InfoIcon, X } from "lucide-react";
import { Copy, Eye, EyeOff, Info, InfoIcon, X } from "lucide-react";
import { AutocompleteOptions } from "../../types";
import twuiNumberfy from "../../utils/numberfy";
import Dropdown from "../../elements/Dropdown";
@@ -19,7 +19,7 @@ import NumberInputButtons from "./NumberInputButtons";
import twuiSlugToNormalText from "../../utils/slug-to-normal-text";
import Row from "../../layout/Row";
import Paper from "../../elements/Paper";
import { TWUISelectValidityObject } from "../Select";
import type { TWUISelectValidityObject } from "../Select";
export type InputProps<KeyType extends string> = Omit<
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
@@ -75,6 +75,7 @@ export type InputProps<KeyType extends string> = Omit<
HTMLDivElement
>;
// refreshDefaultValue?: number;
copy?: boolean;
};
let refreshes = 0;
@@ -117,6 +118,7 @@ export default function Input<KeyType extends string>(
clearInputProps,
rawNumber,
// refreshDefaultValue,
copy,
...props
} = inputProps;
@@ -163,7 +165,7 @@ export default function Input<KeyType extends string>(
numberText ? "text" : props.type,
);
const DEFAULT_DEBOUNCE = 500;
const DEFAULT_DEBOUNCE = 200;
const finalDebounce = debounce || DEFAULT_DEBOUNCE;
const finalLabel =
label ||
@@ -225,11 +227,12 @@ export default function Input<KeyType extends string>(
}
};
const isControlled = props.value !== undefined && props.value !== null;
React.useEffect(() => {
// if (!existingReady) return;
if (typeof props.value !== "string" || !props.value.match(/./)) return;
setValue(String(props.value));
}, [props.value]);
if (!isControlled) return;
setValue(String(props.value ?? ""));
}, [props.value, isControlled]);
// React.useEffect(() => {
// if (!refreshDefaultValue) return;
@@ -290,8 +293,8 @@ export default function Input<KeyType extends string>(
onChange={handleValueChange}
autoComplete={autoComplete}
rows={props.height ? Number(props.height) : props.rows || 2}
defaultValue={defaultInitialValue}
value={props.value ? getFinalValue(props.value) : undefined}
defaultValue={isControlled ? undefined : defaultInitialValue}
value={isControlled ? getFinalValue(props.value) : undefined}
/>
) : (
<input
@@ -318,9 +321,9 @@ export default function Input<KeyType extends string>(
}}
onChange={handleValueChange}
type={inputType}
defaultValue={defaultInitialValue}
defaultValue={isControlled ? undefined : defaultInitialValue}
autoComplete={autoComplete}
value={props.value ? getFinalValue(props.value) : undefined}
value={isControlled ? getFinalValue(props.value) : undefined}
/>
);
@@ -393,7 +396,29 @@ export default function Input<KeyType extends string>(
{targetComponent}
{props.type == "search" || props.readOnly ? null : (
{copy ? (
<>
<div
title="Copy value"
className="cursor-pointer opacity-50 hover:opacity-100"
onClick={() => {
const text =
inputRef.current.value ||
textAreaRef.current.value;
if (text) {
navigator.clipboard
.writeText(text)
.then(() => {
// window.alert(`Text Copied`);
});
}
}}
>
<Copy size={17} />
</div>
</>
) : props.type == "search" || props.readOnly ? null : (
<div
title="Clear Input Field"
{...clearInputProps}
@@ -502,3 +527,26 @@ export default function Input<KeyType extends string>(
</Stack>
);
}
const updateInput = ({
newValue,
inputRef,
}: {
newValue: string;
inputRef: RefObject<HTMLInputElement & HTMLTextAreaElement>;
}) => {
const input = inputRef.current;
if (!input) return;
// Get the native setter (React overrides the default one)
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value",
)?.set;
// Call it directly on the input
nativeInputValueSetter?.call(input, newValue);
// Dispatch the event - React listens for 'input', not 'change'
input.dispatchEvent(new Event("input", { bubbles: true }));
};