typescript src/input (#487)
		
	This commit is contained in:
		
					parent
					
						
							
								5474693711
							
						
					
				
			
			
				commit
				
					
						f554afd6b1
					
				
			
		
					 8 changed files with 120 additions and 41 deletions
				
			
		| 
						 | 
				
			
			@ -23,10 +23,10 @@ import classNames from "classnames";
 | 
			
		|||
import styles from "./ListBox.module.css";
 | 
			
		||||
 | 
			
		||||
interface ListBoxProps<T> extends AriaListBoxOptions<T> {
 | 
			
		||||
  className: string;
 | 
			
		||||
  optionClassName: string;
 | 
			
		||||
  listBoxRef: React.MutableRefObject<HTMLUListElement>;
 | 
			
		||||
  state: ListState<T>;
 | 
			
		||||
  className?: string;
 | 
			
		||||
  listBoxRef?: React.MutableRefObject<HTMLUListElement>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ListBox<T>({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ limitations under the License.
 | 
			
		|||
*/
 | 
			
		||||
 | 
			
		||||
import React, {
 | 
			
		||||
  ChangeEvent,
 | 
			
		||||
  FC,
 | 
			
		||||
  FormEvent,
 | 
			
		||||
  useCallback,
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +167,9 @@ export const RegisterPage: FC = () => {
 | 
			
		|||
                  required
 | 
			
		||||
                  name="password"
 | 
			
		||||
                  type="password"
 | 
			
		||||
                  onChange={(e) => setPassword(e.target.value)}
 | 
			
		||||
                  onChange={(e: ChangeEvent<HTMLInputElement>) =>
 | 
			
		||||
                    setPassword(e.target.value)
 | 
			
		||||
                  }
 | 
			
		||||
                  value={password}
 | 
			
		||||
                  placeholder="Password"
 | 
			
		||||
                  label="Password"
 | 
			
		||||
| 
						 | 
				
			
			@ -177,7 +180,9 @@ export const RegisterPage: FC = () => {
 | 
			
		|||
                  required
 | 
			
		||||
                  type="password"
 | 
			
		||||
                  name="passwordConfirmation"
 | 
			
		||||
                  onChange={(e) => setPasswordConfirmation(e.target.value)}
 | 
			
		||||
                  onChange={(e: ChangeEvent<HTMLInputElement>) =>
 | 
			
		||||
                    setPasswordConfirmation(e.target.value)
 | 
			
		||||
                  }
 | 
			
		||||
                  value={passwordConfirmation}
 | 
			
		||||
                  placeholder="Confirm Password"
 | 
			
		||||
                  label="Confirm Password"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,42 +15,52 @@ limitations under the License.
 | 
			
		|||
*/
 | 
			
		||||
 | 
			
		||||
import { useObjectRef } from "@react-aria/utils";
 | 
			
		||||
import React, { useEffect } from "react";
 | 
			
		||||
import React, { AllHTMLAttributes, useEffect } from "react";
 | 
			
		||||
import { useCallback } from "react";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { forwardRef } from "react";
 | 
			
		||||
import { Avatar } from "../Avatar";
 | 
			
		||||
import { Button } from "../button";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
 | 
			
		||||
import { Avatar, Size } from "../Avatar";
 | 
			
		||||
import { Button } from "../button";
 | 
			
		||||
import { ReactComponent as EditIcon } from "../icons/Edit.svg";
 | 
			
		||||
import styles from "./AvatarInputField.module.css";
 | 
			
		||||
 | 
			
		||||
export const AvatarInputField = forwardRef(
 | 
			
		||||
interface Props extends AllHTMLAttributes<HTMLInputElement> {
 | 
			
		||||
  id: string;
 | 
			
		||||
  label: string;
 | 
			
		||||
  avatarUrl: string;
 | 
			
		||||
  displayName: string;
 | 
			
		||||
  onRemoveAvatar: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const AvatarInputField = forwardRef<HTMLInputElement, Props>(
 | 
			
		||||
  (
 | 
			
		||||
    { id, label, className, avatarUrl, displayName, onRemoveAvatar, ...rest },
 | 
			
		||||
    ref
 | 
			
		||||
  ) => {
 | 
			
		||||
    const [removed, setRemoved] = useState(false);
 | 
			
		||||
    const [objUrl, setObjUrl] = useState(null);
 | 
			
		||||
    const [objUrl, setObjUrl] = useState<string>(null);
 | 
			
		||||
 | 
			
		||||
    const fileInputRef = useObjectRef(ref);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
      const onChange = (e) => {
 | 
			
		||||
        if (e.target.files.length > 0) {
 | 
			
		||||
          setObjUrl(URL.createObjectURL(e.target.files[0]));
 | 
			
		||||
      const currentInput = fileInputRef.current;
 | 
			
		||||
 | 
			
		||||
      const onChange = (e: Event) => {
 | 
			
		||||
        const inputEvent = e as unknown as React.ChangeEvent<HTMLInputElement>;
 | 
			
		||||
        if (inputEvent.target.files.length > 0) {
 | 
			
		||||
          setObjUrl(URL.createObjectURL(inputEvent.target.files[0]));
 | 
			
		||||
          setRemoved(false);
 | 
			
		||||
        } else {
 | 
			
		||||
          setObjUrl(null);
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      fileInputRef.current.addEventListener("change", onChange);
 | 
			
		||||
      currentInput.addEventListener("change", onChange);
 | 
			
		||||
 | 
			
		||||
      return () => {
 | 
			
		||||
        if (fileInputRef.current) {
 | 
			
		||||
          fileInputRef.current.removeEventListener("change", onChange);
 | 
			
		||||
        }
 | 
			
		||||
        currentInput?.removeEventListener("change", onChange);
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +73,7 @@ export const AvatarInputField = forwardRef(
 | 
			
		|||
      <div className={classNames(styles.avatarInputField, className)}>
 | 
			
		||||
        <div className={styles.avatarContainer}>
 | 
			
		||||
          <Avatar
 | 
			
		||||
            size="xl"
 | 
			
		||||
            size={Size.XL}
 | 
			
		||||
            src={removed ? null : objUrl || avatarUrl}
 | 
			
		||||
            fallback={displayName.slice(0, 1).toUpperCase()}
 | 
			
		||||
          />
 | 
			
		||||
| 
						 | 
				
			
			@ -14,12 +14,23 @@ See the License for the specific language governing permissions and
 | 
			
		|||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React, { forwardRef } from "react";
 | 
			
		||||
import React, { ChangeEvent, forwardRef, ReactNode } from "react";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
 | 
			
		||||
import styles from "./Input.module.css";
 | 
			
		||||
import { ReactComponent as CheckIcon } from "../icons/Check.svg";
 | 
			
		||||
 | 
			
		||||
export function FieldRow({ children, rightAlign, className, ...rest }) {
 | 
			
		||||
interface FieldRowProps {
 | 
			
		||||
  children: ReactNode;
 | 
			
		||||
  rightAlign?: boolean;
 | 
			
		||||
  className?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function FieldRow({
 | 
			
		||||
  children,
 | 
			
		||||
  rightAlign,
 | 
			
		||||
  className,
 | 
			
		||||
}: FieldRowProps): JSX.Element {
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      className={classNames(
 | 
			
		||||
| 
						 | 
				
			
			@ -33,11 +44,42 @@ export function FieldRow({ children, rightAlign, className, ...rest }) {
 | 
			
		|||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Field({ children, className, ...rest }) {
 | 
			
		||||
interface FieldProps {
 | 
			
		||||
  children: ReactNode;
 | 
			
		||||
  className?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Field({ children, className }: FieldProps): JSX.Element {
 | 
			
		||||
  return <div className={classNames(styles.field, className)}>{children}</div>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const InputField = forwardRef(
 | 
			
		||||
interface InputFieldProps {
 | 
			
		||||
  label: string;
 | 
			
		||||
  type: string;
 | 
			
		||||
  prefix?: string;
 | 
			
		||||
  suffix?: string;
 | 
			
		||||
  id?: string;
 | 
			
		||||
  checked?: boolean;
 | 
			
		||||
  className?: string;
 | 
			
		||||
  description?: string;
 | 
			
		||||
  disabled?: boolean;
 | 
			
		||||
  required?: boolean;
 | 
			
		||||
  // this is a hack. Those variables should be part of `HTMLAttributes<HTMLInputElement> | HTMLAttributes<HTMLTextAreaElement>`
 | 
			
		||||
  // but extending from this union type does not work
 | 
			
		||||
  name?: string;
 | 
			
		||||
  autoComplete?: string;
 | 
			
		||||
  autoCorrect?: string;
 | 
			
		||||
  autoCapitalize?: string;
 | 
			
		||||
  value?: string;
 | 
			
		||||
  placeholder?: string;
 | 
			
		||||
  defaultChecked?: boolean;
 | 
			
		||||
  onChange?: (event: ChangeEvent) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const InputField = forwardRef<
 | 
			
		||||
  HTMLInputElement | HTMLTextAreaElement,
 | 
			
		||||
  InputFieldProps
 | 
			
		||||
>(
 | 
			
		||||
  (
 | 
			
		||||
    {
 | 
			
		||||
      id,
 | 
			
		||||
| 
						 | 
				
			
			@ -68,19 +110,18 @@ export const InputField = forwardRef(
 | 
			
		|||
        {type === "textarea" ? (
 | 
			
		||||
          <textarea
 | 
			
		||||
            id={id}
 | 
			
		||||
            {...rest}
 | 
			
		||||
            ref={ref}
 | 
			
		||||
            type={type}
 | 
			
		||||
            ref={ref as React.ForwardedRef<HTMLTextAreaElement>}
 | 
			
		||||
            disabled={disabled}
 | 
			
		||||
            {...rest}
 | 
			
		||||
          />
 | 
			
		||||
        ) : (
 | 
			
		||||
          <input
 | 
			
		||||
            id={id}
 | 
			
		||||
            {...rest}
 | 
			
		||||
            ref={ref}
 | 
			
		||||
            ref={ref as React.ForwardedRef<HTMLInputElement>}
 | 
			
		||||
            type={type}
 | 
			
		||||
            checked={checked}
 | 
			
		||||
            disabled={disabled}
 | 
			
		||||
            {...rest}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,6 +140,10 @@ export const InputField = forwardRef(
 | 
			
		|||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export function ErrorMessage({ children }) {
 | 
			
		||||
export function ErrorMessage({
 | 
			
		||||
  children,
 | 
			
		||||
}: {
 | 
			
		||||
  children: ReactNode;
 | 
			
		||||
}): JSX.Element {
 | 
			
		||||
  return <p className={styles.errorMessage}>{children}</p>;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -15,16 +15,21 @@ limitations under the License.
 | 
			
		|||
*/
 | 
			
		||||
 | 
			
		||||
import React, { useRef } from "react";
 | 
			
		||||
import { HiddenSelect, useSelect } from "@react-aria/select";
 | 
			
		||||
import { AriaSelectOptions, HiddenSelect, useSelect } from "@react-aria/select";
 | 
			
		||||
import { useButton } from "@react-aria/button";
 | 
			
		||||
import { useSelectState } from "@react-stately/select";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
 | 
			
		||||
import { Popover } from "../popover/Popover";
 | 
			
		||||
import { ListBox } from "../ListBox";
 | 
			
		||||
import styles from "./SelectInput.module.css";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
import { ReactComponent as ArrowDownIcon } from "../icons/ArrowDown.svg";
 | 
			
		||||
 | 
			
		||||
export function SelectInput(props) {
 | 
			
		||||
interface Props extends AriaSelectOptions<object> {
 | 
			
		||||
  className?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function SelectInput(props: Props): JSX.Element {
 | 
			
		||||
  const state = useSelectState(props);
 | 
			
		||||
 | 
			
		||||
  const ref = useRef();
 | 
			
		||||
| 
						 | 
				
			
			@ -15,22 +15,37 @@ limitations under the License.
 | 
			
		|||
*/
 | 
			
		||||
 | 
			
		||||
import React, { useCallback, useRef } from "react";
 | 
			
		||||
import styles from "./Toggle.module.css";
 | 
			
		||||
import { useToggleButton } from "@react-aria/button";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
 | 
			
		||||
import styles from "./Toggle.module.css";
 | 
			
		||||
import { Field } from "./Input";
 | 
			
		||||
 | 
			
		||||
export function Toggle({ id, label, className, onChange, isSelected }) {
 | 
			
		||||
  const buttonRef = useRef();
 | 
			
		||||
interface Props {
 | 
			
		||||
  id: string;
 | 
			
		||||
  label: string;
 | 
			
		||||
  onChange: (selected: boolean) => void;
 | 
			
		||||
  isSelected: boolean;
 | 
			
		||||
  className?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Toggle({
 | 
			
		||||
  id,
 | 
			
		||||
  label,
 | 
			
		||||
  className,
 | 
			
		||||
  onChange,
 | 
			
		||||
  isSelected,
 | 
			
		||||
}: Props): JSX.Element {
 | 
			
		||||
  const buttonRef = useRef<HTMLButtonElement>();
 | 
			
		||||
  const toggle = useCallback(() => {
 | 
			
		||||
    onChange(!isSelected);
 | 
			
		||||
  });
 | 
			
		||||
  const { buttonProps } = useToggleButton(
 | 
			
		||||
  }, [isSelected, onChange]);
 | 
			
		||||
 | 
			
		||||
  const buttonProps = useToggleButton(
 | 
			
		||||
    { isSelected },
 | 
			
		||||
    { toggle },
 | 
			
		||||
    { isSelected: isSelected, setSelected: undefined, toggle },
 | 
			
		||||
    buttonRef
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Field
 | 
			
		||||
      className={classNames(
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		|||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React, { useCallback, useEffect, useState } from "react";
 | 
			
		||||
import React, { ChangeEvent, useCallback, useEffect, useState } from "react";
 | 
			
		||||
import { MatrixClient } from "matrix-js-sdk";
 | 
			
		||||
 | 
			
		||||
import { Button } from "../button";
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ export function ProfileModal({ client, ...rest }: Props) {
 | 
			
		|||
  }, []);
 | 
			
		||||
 | 
			
		||||
  const onChangeDisplayName = useCallback(
 | 
			
		||||
    (e) => {
 | 
			
		||||
    (e: ChangeEvent<HTMLInputElement>) => {
 | 
			
		||||
      setDisplayName(e.target.value);
 | 
			
		||||
    },
 | 
			
		||||
    [setDisplayName]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ import React, {
 | 
			
		|||
  useRef,
 | 
			
		||||
  createContext,
 | 
			
		||||
  useContext,
 | 
			
		||||
  Dispatch,
 | 
			
		||||
} from "react";
 | 
			
		||||
import ReactJson, { CollapsedFieldProps } from "react-json-view";
 | 
			
		||||
import mermaid from "mermaid";
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +155,7 @@ interface SequenceDiagramViewerProps {
 | 
			
		|||
  localUserId: string;
 | 
			
		||||
  remoteUserIds: string[];
 | 
			
		||||
  selectedUserId: string;
 | 
			
		||||
  onSelectUserId: Dispatch<(prevState: undefined) => undefined>;
 | 
			
		||||
  onSelectUserId: (userId: string) => void;
 | 
			
		||||
  events: SequenceDiagramMatrixEvent[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue