diff --git a/m3-react/src/components/text-field/M3TextField.tsx b/m3-react/src/components/text-field/M3TextField.tsx new file mode 100644 index 0000000..5db9045 --- /dev/null +++ b/m3-react/src/components/text-field/M3TextField.tsx @@ -0,0 +1,149 @@ +import React, { useState, useEffect, useRef, HTMLAttributes } from 'react'; +import makeId from '@/utils/id'; +import { toClassName } from '@/utils/styling'; + +export interface M3TextFieldProps extends HTMLAttributes { + id?: string; + type?: string; + value?: string | number; + label?: string; + placeholder?: string; + lazy?: boolean; + multiline?: boolean; + invalid?: boolean; + disabled?: boolean; + readonly?: boolean; + outlined?: boolean; + onUpdateValue?: (value: string | number) => void; +} + +const M3TextField: React.FC = ({ + id = makeId('m3-text-field'), + type = 'text', + value = '', + label = '', + placeholder = '', + lazy = false, + multiline = false, + invalid = false, + disabled = false, + readonly = false, + outlined = false, + className = '', + children, + onUpdateValue, + ...props + }) => { + const [focused, setFocused] = useState(false); + const inputElement = useRef(null); + + const onInput = (event: React.ChangeEvent) => { + const rawValue = event.target.value; + if (!lazy) { + onUpdateValue && onUpdateValue(rawValue); + } + }; + + const onChange = (event: React.ChangeEvent) => { + const rawValue = event.target.value; + if (lazy) { + onUpdateValue && onUpdateValue(rawValue); + } + }; + + const onFocus = () => { + setFocused(true); + }; + + const onBlur = () => { + setFocused(false); + }; + + useEffect(() => { + const input = inputElement.current; + if (input) { + const valueStr = String(value); + if (valueStr.length) { + input.value = valueStr; + } else if (input.value.length) { + onUpdateValue && onUpdateValue(input.value); + } + } + }, [value, onUpdateValue]); + + return ( +
inputElement.current?.focus()} + {...props} + > + {outlined &&
+
+
+ +
+
+
} + + {!outlined && } + +
+ {children} + + {multiline ? ( +