Exam generation rework, batch user tables, fastapi endpoint switch
This commit is contained in:
62
src/components/Low/AutoExpandingTextInput.tsx
Normal file
62
src/components/Low/AutoExpandingTextInput.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import React, { useEffect, useRef, ChangeEvent } from 'react';
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
const AutoExpandingTextInput: React.FC<Props> = ({
|
||||
value,
|
||||
className,
|
||||
onChange,
|
||||
placeholder
|
||||
}) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const measureRef = useRef<HTMLSpanElement>(null);
|
||||
|
||||
const adjustWidth = () => {
|
||||
const input = inputRef.current;
|
||||
const measure = measureRef.current;
|
||||
if (input && measure) {
|
||||
measure.textContent = input.value || placeholder || '';
|
||||
input.style.width = `${measure.offsetWidth + 10}px`;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
adjustWidth();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value, placeholder]);
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
onChange(e.target.value);
|
||||
adjustWidth();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative inline-block">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
className={className}
|
||||
placeholder={placeholder}
|
||||
style={{ minWidth: '50px' }}
|
||||
/>
|
||||
<span
|
||||
ref={measureRef}
|
||||
className="absolute invisible whitespace-pre"
|
||||
style={{
|
||||
font: 'inherit',
|
||||
padding: '0 4px',
|
||||
border: '2px solid transparent',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutoExpandingTextInput;
|
||||
53
src/components/Low/AutoExpandingTextarea.tsx
Executable file
53
src/components/Low/AutoExpandingTextarea.tsx
Executable file
@@ -0,0 +1,53 @@
|
||||
import React, { useEffect, useRef, ChangeEvent } from 'react';
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
onBlur?: () => void;
|
||||
}
|
||||
|
||||
const AutoExpandingTextArea: React.FC<Props> = ({
|
||||
value,
|
||||
className = 'w-full cursor-text px-7 py-8 input border-2 border-mti-gray-platinum bg-white rounded-3xl',
|
||||
placeholder = "Enter text here...",
|
||||
onChange,
|
||||
onBlur,
|
||||
}) => {
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const adjustHeight = () => {
|
||||
const textarea = textareaRef.current;
|
||||
if (textarea) {
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
adjustHeight();
|
||||
const timer = setTimeout(adjustHeight, 100);
|
||||
return () => clearTimeout(timer);
|
||||
}, [value]);
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
onChange(e.target.value);
|
||||
adjustHeight();
|
||||
};
|
||||
|
||||
return (
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
className={className}
|
||||
placeholder={placeholder}
|
||||
style={{ overflow: 'hidden', resize: 'none' }}
|
||||
onBlur={onBlur}
|
||||
autoFocus
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutoExpandingTextArea;
|
||||
@@ -1,12 +1,7 @@
|
||||
import clsx from "clsx";
|
||||
import {ComponentProps, useEffect, useState} from "react";
|
||||
import ReactSelect, {GroupBase, StylesConfig} from "react-select";
|
||||
|
||||
interface Option {
|
||||
[key: string]: any;
|
||||
value: string | null;
|
||||
label: string;
|
||||
}
|
||||
import Option from "@/interfaces/option";
|
||||
|
||||
interface Props {
|
||||
defaultValue?: Option;
|
||||
|
||||
Reference in New Issue
Block a user