Refactor input arch (#1982)
This commit is contained in:
@ -6,7 +6,7 @@ import { motion } from 'framer-motion';
|
||||
|
||||
import { MainButton } from '@/ui/button/components/MainButton';
|
||||
import { IconBrandGoogle } from '@/ui/icon';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn';
|
||||
|
||||
import { Logo } from '../../components/Logo';
|
||||
@ -132,7 +132,7 @@ export const SignInUpForm = () => {
|
||||
fieldState: { error },
|
||||
}) => (
|
||||
<StyledInputContainer>
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
autoFocus
|
||||
value={value}
|
||||
placeholder="Email"
|
||||
@ -170,7 +170,7 @@ export const SignInUpForm = () => {
|
||||
fieldState: { error },
|
||||
}) => (
|
||||
<StyledInputContainer>
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
autoFocus
|
||||
value={value}
|
||||
type="password"
|
||||
|
||||
@ -10,9 +10,9 @@ import {
|
||||
} from '@/people/components/PeoplePicker';
|
||||
import { GET_PEOPLE } from '@/people/graphql/queries/getPeople';
|
||||
import { LightIconButton } from '@/ui/button/components/LightIconButton';
|
||||
import { DoubleTextInput } from '@/ui/field/meta-types/input/components/internal/DoubleTextInput';
|
||||
import { FieldDoubleText } from '@/ui/field/types/FieldDoubleText';
|
||||
import { IconPlus } from '@/ui/icon';
|
||||
import { DoubleTextInput } from '@/ui/input/components/DoubleTextInput';
|
||||
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
|
||||
export const EmailField = () => {
|
||||
const currentUser = useRecoilValue(currentUserState);
|
||||
|
||||
return (
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
value={currentUser?.email}
|
||||
disabled
|
||||
fullWidth
|
||||
|
||||
@ -5,7 +5,7 @@ import debounce from 'lodash.debounce';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import { useUpdateUserMutation } from '~/generated/graphql';
|
||||
import { logError } from '~/utils/logError';
|
||||
@ -87,14 +87,14 @@ export const NameFields = ({
|
||||
|
||||
return (
|
||||
<StyledComboInputContainer>
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
label="First Name"
|
||||
value={firstName}
|
||||
onChange={setFirstName}
|
||||
placeholder="Tim"
|
||||
fullWidth
|
||||
/>
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
label="Last Name"
|
||||
value={lastName}
|
||||
onChange={setLastName}
|
||||
|
||||
@ -3,7 +3,7 @@ import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { ImageInput } from '@/ui/input/image/components/ImageInput';
|
||||
import { ImageInput } from '@/ui/input/components/ImageInput';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI';
|
||||
import {
|
||||
|
||||
@ -5,7 +5,7 @@ import debounce from 'lodash.debounce';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import { useUpdateWorkspaceMutation } from '~/generated/graphql';
|
||||
import { logError } from '~/utils/logError';
|
||||
@ -72,7 +72,7 @@ export const NameField = ({
|
||||
|
||||
return (
|
||||
<StyledComboInputContainer>
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
label="Name"
|
||||
value={displayName}
|
||||
onChange={setDisplayName}
|
||||
|
||||
@ -2,7 +2,7 @@ import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { ImageInput } from '@/ui/input/image/components/ImageInput';
|
||||
import { ImageInput } from '@/ui/input/components/ImageInput';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI';
|
||||
import {
|
||||
|
||||
@ -5,8 +5,8 @@ import styled from '@emotion/styled';
|
||||
import { MatchColumnSelect } from '@/spreadsheet-import/components/MatchColumnSelect';
|
||||
import { Data, Fields } from '@/spreadsheet-import/types';
|
||||
import { Checkbox, CheckboxVariant } from '@/ui/input/components/Checkbox';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { Toggle } from '@/ui/input/components/Toggle';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { AppTooltip } from '@/ui/tooltip/AppTooltip';
|
||||
|
||||
import { Meta } from '../types';
|
||||
@ -146,7 +146,7 @@ export const generateColumns = <T extends string>(
|
||||
}
|
||||
default:
|
||||
component = (
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
value={row[columnKey] as string}
|
||||
onChange={(value: string) => {
|
||||
onRowChange({ ...row, [columnKey]: value });
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { BooleanInput } from '@/ui/input/components/BooleanInput';
|
||||
import { BooleanInput } from '@/ui/field/meta-types/input/components/internal/BooleanInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useBooleanField } from '../../hooks/useBooleanField';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { TextInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useChipField } from '../../hooks/useChipField';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { DateInput } from '@/ui/input/components/DateInput';
|
||||
import { DateInput } from '@/ui/field/meta-types/input/components/internal/DateInput';
|
||||
import { Nullable } from '~/types/Nullable';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { DoubleTextInput } from '@/ui/field/meta-types/input/components/internal/DoubleTextInput';
|
||||
import { FieldDoubleText } from '@/ui/field/types/FieldDoubleText';
|
||||
import { DoubleTextInput } from '@/ui/input/components/DoubleTextInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useDoubleTextChipField } from '../../hooks/useDoubleTextChipField';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { DoubleTextInput } from '@/ui/field/meta-types/input/components/internal/DoubleTextInput';
|
||||
import { FieldDoubleText } from '@/ui/field/types/FieldDoubleText';
|
||||
import { DoubleTextInput } from '@/ui/input/components/DoubleTextInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useDoubleTextField } from '../../hooks/useDoubleTextField';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { TextInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useEmailField } from '../../hooks/useEmailField';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { TextInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
|
||||
import { useMoneyField } from '../../hooks/useMoneyField';
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { TextInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
|
||||
import { useNumberField } from '../../hooks/useNumberField';
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PhoneInput } from '@/ui/input/components/PhoneInput';
|
||||
import { PhoneInput } from '@/ui/field/meta-types/input/components/internal/PhoneInput';
|
||||
|
||||
import { usePhoneField } from '../../hooks/usePhoneField';
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ProbabilityInput } from '@/ui/input/components/ProbabilityInput';
|
||||
import { ProbabilityInput } from '@/ui/field/meta-types/input/components/internal/ProbabilityInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useProbabilityField } from '../../hooks/useProbabilityField';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { TextInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useTextField } from '../../hooks/useTextField';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { TextInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
|
||||
import { useURLField } from '../../hooks/useURLField';
|
||||
|
||||
|
||||
@ -4,11 +4,10 @@ import styled from '@emotion/styled';
|
||||
import { flip, offset, useFloating } from '@floating-ui/react';
|
||||
|
||||
import { DateDisplay } from '@/ui/field/meta-types/display/content-display/components/DateDisplay';
|
||||
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { Nullable } from '~/types/Nullable';
|
||||
|
||||
import { useRegisterInputEvents } from '../hooks/useRegisterInputEvents';
|
||||
|
||||
import { DatePicker } from './DatePicker';
|
||||
import { useRegisterInputEvents } from '../../hooks/useRegisterInputEvents';
|
||||
|
||||
const StyledCalendarContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
@ -89,7 +88,7 @@ export const DateInput = ({
|
||||
</div>
|
||||
<div ref={refs.setFloating} style={floatingStyles}>
|
||||
<StyledCalendarContainer>
|
||||
<DatePicker
|
||||
<InternalDatePicker
|
||||
date={internalValue ?? new Date()}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={(newDate: Date) => {
|
||||
@ -2,9 +2,9 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import ReactPhoneNumberInput from 'react-phone-number-input';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useRegisterInputEvents } from '../hooks/useRegisterInputEvents';
|
||||
import { CountryPickerDropdownButton } from '@/ui/input/components/internal/phone/components/CountryPickerDropdownButton';
|
||||
|
||||
import { CountryPickerDropdownButton } from './CountryPickerDropdownButton';
|
||||
import { useRegisterInputEvents } from '../../hooks/useRegisterInputEvents';
|
||||
|
||||
import 'react-phone-number-input/style.css';
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { textInputStyle } from '@/ui/theme/constants/effects';
|
||||
|
||||
import { useRegisterInputEvents } from '../../hooks/useRegisterInputEvents';
|
||||
|
||||
export const StyledInput = styled.input`
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
${textInputStyle}
|
||||
`;
|
||||
|
||||
type TextInputProps = {
|
||||
placeholder?: string;
|
||||
autoFocus?: boolean;
|
||||
value: string;
|
||||
onEnter: (newText: string) => void;
|
||||
onEscape: (newText: string) => void;
|
||||
onTab?: (newText: string) => void;
|
||||
onShiftTab?: (newText: string) => void;
|
||||
onClickOutside: (event: MouseEvent | TouchEvent, inputValue: string) => void;
|
||||
hotkeyScope: string;
|
||||
};
|
||||
|
||||
export const TextInput = ({
|
||||
placeholder,
|
||||
autoFocus,
|
||||
value,
|
||||
hotkeyScope,
|
||||
onEnter,
|
||||
onEscape,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
onClickOutside,
|
||||
}: TextInputProps) => {
|
||||
const [internalText, setInternalText] = useState(value);
|
||||
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setInternalText(event.target.value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setInternalText(value);
|
||||
}, [value]);
|
||||
|
||||
useRegisterInputEvents({
|
||||
inputRef: wrapperRef,
|
||||
inputValue: internalText,
|
||||
onEnter,
|
||||
onEscape,
|
||||
onClickOutside,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
hotkeyScope,
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledInput
|
||||
autoComplete="off"
|
||||
ref={wrapperRef}
|
||||
placeholder={placeholder}
|
||||
onChange={handleChange}
|
||||
autoFocus={autoFocus}
|
||||
value={internalText}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -8,7 +8,7 @@ import { RoundedIconButton } from '@/ui/button/components/RoundedIconButton';
|
||||
import { IconArrowRight } from '@/ui/icon/index';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
|
||||
import { InputHotkeyScope } from '../text/types/InputHotkeyScope';
|
||||
import { InputHotkeyScope } from '../types/InputHotkeyScope';
|
||||
|
||||
const MAX_ROWS = 5;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeEvent } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { StyledInput } from '@/ui/input/components/TextInput';
|
||||
import { StyledInput } from '@/ui/field/meta-types/input/components/internal/TextInput';
|
||||
import { ComputeNodeDimensions } from '@/ui/utilities/dimensions/components/ComputeNodeDimensions';
|
||||
|
||||
export type EntityTitleDoubleTextInputProps = {
|
||||
|
||||
@ -1,70 +1,203 @@
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
ChangeEvent,
|
||||
FocusEventHandler,
|
||||
ForwardedRef,
|
||||
forwardRef,
|
||||
InputHTMLAttributes,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { textInputStyle } from '@/ui/theme/constants/effects';
|
||||
import { IconAlertCircle } from '@/ui/icon';
|
||||
import { IconEye, IconEyeOff } from '@/ui/icon/index';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
|
||||
|
||||
import { useRegisterInputEvents } from '../hooks/useRegisterInputEvents';
|
||||
import { InputHotkeyScope } from '../types/InputHotkeyScope';
|
||||
|
||||
export const StyledInput = styled.input`
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
${textInputStyle}
|
||||
type TextInputComponentProps = Omit<
|
||||
InputHTMLAttributes<HTMLInputElement>,
|
||||
'onChange'
|
||||
> & {
|
||||
label?: string;
|
||||
onChange?: (text: string) => void;
|
||||
fullWidth?: boolean;
|
||||
disableHotkeys?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div<Pick<TextInputComponentProps, 'fullWidth'>>`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: ${({ fullWidth }) => (fullWidth ? `100%` : 'auto')};
|
||||
`;
|
||||
|
||||
type TextInputProps = {
|
||||
placeholder?: string;
|
||||
autoFocus?: boolean;
|
||||
value: string;
|
||||
onEnter: (newText: string) => void;
|
||||
onEscape: (newText: string) => void;
|
||||
onTab?: (newText: string) => void;
|
||||
onShiftTab?: (newText: string) => void;
|
||||
onClickOutside: (event: MouseEvent | TouchEvent, inputValue: string) => void;
|
||||
hotkeyScope: string;
|
||||
};
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin-bottom: ${({ theme }) => theme.spacing(1)};
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
export const TextInput = ({
|
||||
placeholder,
|
||||
autoFocus,
|
||||
value,
|
||||
hotkeyScope,
|
||||
onEnter,
|
||||
onEscape,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
onClickOutside,
|
||||
}: TextInputProps) => {
|
||||
const [internalText, setInternalText] = useState(value);
|
||||
const StyledInputContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
const wrapperRef = useRef(null);
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setInternalText(event.target.value);
|
||||
const StyledInput = styled.input<Pick<TextInputComponentProps, 'fullWidth'>>`
|
||||
background-color: ${({ theme }) => theme.background.tertiary};
|
||||
border: none;
|
||||
border-bottom-left-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-top-left-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
font-family: ${({ theme }) => theme.font.family};
|
||||
|
||||
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||
outline: none;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
width: 100%;
|
||||
|
||||
&::placeholder,
|
||||
&::-webkit-input-placeholder {
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-family: ${({ theme }) => theme.font.family};
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledErrorHelper = styled.div`
|
||||
color: ${({ theme }) => theme.color.red};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTrailingIconContainer = styled.div`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.background.tertiary};
|
||||
border-bottom-right-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-top-right-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTrailingIcon = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const INPUT_TYPE_PASSWORD = 'password';
|
||||
|
||||
const TextInputComponent = (
|
||||
{
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
onFocus,
|
||||
onBlur,
|
||||
fullWidth,
|
||||
error,
|
||||
required,
|
||||
type,
|
||||
disableHotkeys = false,
|
||||
autoFocus,
|
||||
placeholder,
|
||||
disabled,
|
||||
tabIndex,
|
||||
}: TextInputComponentProps,
|
||||
// eslint-disable-next-line twenty/component-props-naming
|
||||
ref: ForwardedRef<HTMLInputElement>,
|
||||
): JSX.Element => {
|
||||
const theme = useTheme();
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const combinedRef = useCombinedRefs(ref, inputRef);
|
||||
|
||||
const {
|
||||
goBackToPreviousHotkeyScope,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const handleFocus: FocusEventHandler<HTMLInputElement> = (e) => {
|
||||
onFocus?.(e);
|
||||
if (!disableHotkeys) {
|
||||
setHotkeyScopeAndMemorizePreviousScope(InputHotkeyScope.TextInput);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setInternalText(value);
|
||||
}, [value]);
|
||||
const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {
|
||||
onBlur?.(e);
|
||||
if (!disableHotkeys) {
|
||||
goBackToPreviousHotkeyScope();
|
||||
}
|
||||
};
|
||||
|
||||
useRegisterInputEvents({
|
||||
inputRef: wrapperRef,
|
||||
inputValue: internalText,
|
||||
onEnter,
|
||||
onEscape,
|
||||
onClickOutside,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
hotkeyScope,
|
||||
});
|
||||
useScopedHotkeys(
|
||||
[Key.Escape, Key.Enter],
|
||||
() => {
|
||||
inputRef.current?.blur();
|
||||
},
|
||||
InputHotkeyScope.TextInput,
|
||||
);
|
||||
|
||||
const [passwordVisible, setPasswordVisible] = useState(false);
|
||||
|
||||
const handleTogglePasswordVisibility = () => {
|
||||
setPasswordVisible(!passwordVisible);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledInput
|
||||
autoComplete="off"
|
||||
ref={wrapperRef}
|
||||
placeholder={placeholder}
|
||||
onChange={handleChange}
|
||||
autoFocus={autoFocus}
|
||||
value={internalText}
|
||||
/>
|
||||
<StyledContainer fullWidth={fullWidth ?? false}>
|
||||
{label && <StyledLabel>{label + (required ? '*' : '')}</StyledLabel>}
|
||||
<StyledInputContainer>
|
||||
<StyledInput
|
||||
autoComplete="off"
|
||||
ref={combinedRef}
|
||||
tabIndex={tabIndex ?? 0}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
type={passwordVisible ? 'text' : type}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
onChange?.(event.target.value);
|
||||
}}
|
||||
{...{ autoFocus, disabled, placeholder, required, value }}
|
||||
/>
|
||||
<StyledTrailingIconContainer>
|
||||
{error && (
|
||||
<StyledTrailingIcon>
|
||||
<IconAlertCircle size={16} color={theme.color.red} />
|
||||
</StyledTrailingIcon>
|
||||
)}
|
||||
{!error && type === INPUT_TYPE_PASSWORD && (
|
||||
<StyledTrailingIcon
|
||||
onClick={handleTogglePasswordVisibility}
|
||||
data-testid="reveal-password-button"
|
||||
>
|
||||
{passwordVisible ? (
|
||||
<IconEyeOff size={theme.icon.size.md} />
|
||||
) : (
|
||||
<IconEye size={theme.icon.size.md} />
|
||||
)}
|
||||
</StyledTrailingIcon>
|
||||
)}
|
||||
</StyledTrailingIconContainer>
|
||||
</StyledInputContainer>
|
||||
{error && <StyledErrorHelper>{error}</StyledErrorHelper>}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const TextInput = forwardRef(TextInputComponent);
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
|
||||
|
||||
import { EmailDisplay } from '../../../field/meta-types/display/content-display/components/EmailDisplay';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'UI/Input/EmailInputDisplay',
|
||||
component: EmailDisplay,
|
||||
decorators: [ComponentWithRouterDecorator],
|
||||
args: {
|
||||
value: 'mustajab.ikram@google.com',
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof EmailDisplay>;
|
||||
|
||||
export const Default: Story = {};
|
||||
@ -220,17 +220,17 @@ const StyledContainer = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
export type DatePickerProps = {
|
||||
export type InternalDatePickerProps = {
|
||||
date: Date;
|
||||
onMouseSelect?: (date: Date) => void;
|
||||
onChange?: (date: Date) => void;
|
||||
};
|
||||
|
||||
export const DatePicker = ({
|
||||
export const InternalDatePicker = ({
|
||||
date,
|
||||
onChange,
|
||||
onMouseSelect,
|
||||
}: DatePickerProps) => (
|
||||
}: InternalDatePickerProps) => (
|
||||
<StyledContainer>
|
||||
<ReactDatePicker
|
||||
open={true}
|
||||
@ -4,11 +4,11 @@ import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { DatePicker } from '../DatePicker';
|
||||
import { InternalDatePicker } from '../InternalDatePicker';
|
||||
|
||||
const meta: Meta<typeof DatePicker> = {
|
||||
title: 'UI/Input/DatePicker',
|
||||
component: DatePicker,
|
||||
const meta: Meta<typeof InternalDatePicker> = {
|
||||
title: 'UI/Input/InternalDatePicker',
|
||||
component: InternalDatePicker,
|
||||
decorators: [ComponentDecorator],
|
||||
argTypes: {
|
||||
date: { control: 'date' },
|
||||
@ -17,7 +17,7 @@ const meta: Meta<typeof DatePicker> = {
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof DatePicker>;
|
||||
type Story = StoryObj<typeof InternalDatePicker>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
@ -10,9 +10,9 @@ import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
||||
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope';
|
||||
import { IconChevronDown } from '@/ui/icon';
|
||||
import { IconWorld } from '@/ui/input/constants/icons';
|
||||
|
||||
import { IconWorld } from '../constants/icons';
|
||||
import { CountryPickerHotkeyScope } from '../Types/CountryPickerHotkeyScope';
|
||||
import { CountryPickerHotkeyScope } from '../types/CountryPickerHotkeyScope';
|
||||
|
||||
import { CountryPickerDropdownSelect } from './CountryPickerDropdownSelect';
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { textInputStyle } from '@/ui/theme/constants/effects';
|
||||
import { overlayBackground } from '@/ui/theme/constants/effects';
|
||||
|
||||
const StyledInplaceInputTextInput = styled.input`
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
${textInputStyle}
|
||||
`;
|
||||
|
||||
const StyledTextInputContainer = styled.div`
|
||||
align-items: center;
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
margin-left: -1px;
|
||||
min-height: 32px;
|
||||
width: inherit;
|
||||
|
||||
${overlayBackground}
|
||||
|
||||
z-index: 10;
|
||||
`;
|
||||
|
||||
export type TextInputEditProps = {
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
onChange?: (newValue: string) => void;
|
||||
autoFocus?: boolean;
|
||||
};
|
||||
|
||||
export const TextInputEdit = ({
|
||||
placeholder,
|
||||
value,
|
||||
onChange,
|
||||
autoFocus,
|
||||
}: TextInputEditProps) => (
|
||||
<StyledTextInputContainer>
|
||||
<StyledInplaceInputTextInput
|
||||
autoComplete="off"
|
||||
autoFocus={autoFocus}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={(e) => onChange?.(e.target.value)}
|
||||
/>
|
||||
</StyledTextInputContainer>
|
||||
);
|
||||
@ -1,203 +0,0 @@
|
||||
import {
|
||||
ChangeEvent,
|
||||
FocusEventHandler,
|
||||
ForwardedRef,
|
||||
forwardRef,
|
||||
InputHTMLAttributes,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { IconAlertCircle } from '@/ui/icon';
|
||||
import { IconEye, IconEyeOff } from '@/ui/icon/index';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
|
||||
|
||||
import { InputHotkeyScope } from '../types/InputHotkeyScope';
|
||||
|
||||
type TextInputComponentProps = Omit<
|
||||
InputHTMLAttributes<HTMLInputElement>,
|
||||
'onChange'
|
||||
> & {
|
||||
label?: string;
|
||||
onChange?: (text: string) => void;
|
||||
fullWidth?: boolean;
|
||||
disableHotkeys?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div<Pick<TextInputComponentProps, 'fullWidth'>>`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: ${({ fullWidth }) => (fullWidth ? `100%` : 'auto')};
|
||||
`;
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin-bottom: ${({ theme }) => theme.spacing(1)};
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
const StyledInputContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledInput = styled.input<Pick<TextInputComponentProps, 'fullWidth'>>`
|
||||
background-color: ${({ theme }) => theme.background.tertiary};
|
||||
border: none;
|
||||
border-bottom-left-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-top-left-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
font-family: ${({ theme }) => theme.font.family};
|
||||
|
||||
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||
outline: none;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
width: 100%;
|
||||
|
||||
&::placeholder,
|
||||
&::-webkit-input-placeholder {
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-family: ${({ theme }) => theme.font.family};
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledErrorHelper = styled.div`
|
||||
color: ${({ theme }) => theme.color.red};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTrailingIconContainer = styled.div`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.background.tertiary};
|
||||
border-bottom-right-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-top-right-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTrailingIcon = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const INPUT_TYPE_PASSWORD = 'password';
|
||||
|
||||
const TextInputComponent = (
|
||||
{
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
onFocus,
|
||||
onBlur,
|
||||
fullWidth,
|
||||
error,
|
||||
required,
|
||||
type,
|
||||
disableHotkeys = false,
|
||||
autoFocus,
|
||||
placeholder,
|
||||
disabled,
|
||||
tabIndex,
|
||||
}: TextInputComponentProps,
|
||||
// eslint-disable-next-line twenty/component-props-naming
|
||||
ref: ForwardedRef<HTMLInputElement>,
|
||||
): JSX.Element => {
|
||||
const theme = useTheme();
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const combinedRef = useCombinedRefs(ref, inputRef);
|
||||
|
||||
const {
|
||||
goBackToPreviousHotkeyScope,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const handleFocus: FocusEventHandler<HTMLInputElement> = (e) => {
|
||||
onFocus?.(e);
|
||||
if (!disableHotkeys) {
|
||||
setHotkeyScopeAndMemorizePreviousScope(InputHotkeyScope.TextInput);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {
|
||||
onBlur?.(e);
|
||||
if (!disableHotkeys) {
|
||||
goBackToPreviousHotkeyScope();
|
||||
}
|
||||
};
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape, Key.Enter],
|
||||
() => {
|
||||
inputRef.current?.blur();
|
||||
},
|
||||
InputHotkeyScope.TextInput,
|
||||
);
|
||||
|
||||
const [passwordVisible, setPasswordVisible] = useState(false);
|
||||
|
||||
const handleTogglePasswordVisibility = () => {
|
||||
setPasswordVisible(!passwordVisible);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer fullWidth={fullWidth ?? false}>
|
||||
{label && <StyledLabel>{label + (required ? '*' : '')}</StyledLabel>}
|
||||
<StyledInputContainer>
|
||||
<StyledInput
|
||||
autoComplete="off"
|
||||
ref={combinedRef}
|
||||
tabIndex={tabIndex ?? 0}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
type={passwordVisible ? 'text' : type}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
onChange?.(event.target.value);
|
||||
}}
|
||||
{...{ autoFocus, disabled, placeholder, required, value }}
|
||||
/>
|
||||
<StyledTrailingIconContainer>
|
||||
{error && (
|
||||
<StyledTrailingIcon>
|
||||
<IconAlertCircle size={16} color={theme.color.red} />
|
||||
</StyledTrailingIcon>
|
||||
)}
|
||||
{!error && type === INPUT_TYPE_PASSWORD && (
|
||||
<StyledTrailingIcon
|
||||
onClick={handleTogglePasswordVisibility}
|
||||
data-testid="reveal-password-button"
|
||||
>
|
||||
{passwordVisible ? (
|
||||
<IconEyeOff size={theme.icon.size.md} />
|
||||
) : (
|
||||
<IconEye size={theme.icon.size.md} />
|
||||
)}
|
||||
</StyledTrailingIcon>
|
||||
)}
|
||||
</StyledTrailingIconContainer>
|
||||
</StyledInputContainer>
|
||||
{error && <StyledErrorHelper>{error}</StyledErrorHelper>}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const TextInputSettings = forwardRef(TextInputComponent);
|
||||
@ -1,142 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { expect } from '@storybook/jest';
|
||||
import { jest } from '@storybook/jest';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { TextInputSettings } from '../TextInputSettings';
|
||||
|
||||
const changeJestFn = jest.fn();
|
||||
|
||||
const meta: Meta<typeof TextInputSettings> = {
|
||||
title: 'UI/Input/TextInput',
|
||||
component: TextInputSettings,
|
||||
decorators: [ComponentDecorator],
|
||||
args: { value: '', onChange: changeJestFn, placeholder: 'Placeholder' },
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof TextInputSettings>;
|
||||
|
||||
const FakeTextInput = ({
|
||||
autoFocus,
|
||||
disableHotkeys = false,
|
||||
disabled,
|
||||
error,
|
||||
fullWidth,
|
||||
label,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
placeholder,
|
||||
required,
|
||||
tabIndex,
|
||||
type,
|
||||
value: initialValue,
|
||||
}: React.ComponentProps<typeof TextInputSettings>) => {
|
||||
const [value, setValue] = useState(initialValue);
|
||||
return (
|
||||
<TextInputSettings
|
||||
{...{
|
||||
autoFocus,
|
||||
disableHotkeys,
|
||||
disabled,
|
||||
error,
|
||||
fullWidth,
|
||||
label,
|
||||
onBlur,
|
||||
onFocus,
|
||||
placeholder,
|
||||
required,
|
||||
tabIndex,
|
||||
type,
|
||||
}}
|
||||
value={value}
|
||||
onChange={(text) => {
|
||||
setValue(text);
|
||||
onChange?.(text);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default: Story = {
|
||||
argTypes: { value: { control: false } },
|
||||
args: { value: 'A good value ' },
|
||||
render: ({
|
||||
autoFocus,
|
||||
disableHotkeys,
|
||||
disabled,
|
||||
error,
|
||||
fullWidth,
|
||||
label,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
placeholder,
|
||||
required,
|
||||
tabIndex,
|
||||
type,
|
||||
value,
|
||||
}) => (
|
||||
<FakeTextInput
|
||||
{...{
|
||||
autoFocus,
|
||||
disableHotkeys,
|
||||
disabled,
|
||||
error,
|
||||
fullWidth,
|
||||
label,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
placeholder,
|
||||
required,
|
||||
tabIndex,
|
||||
type,
|
||||
value,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = canvas.getByRole('textbox');
|
||||
await userEvent.type(input, 'cou', { delay: 100 });
|
||||
|
||||
expect(changeJestFn).toHaveBeenNthCalledWith(1, 'A good value c');
|
||||
expect(changeJestFn).toHaveBeenNthCalledWith(2, 'A good value co');
|
||||
expect(changeJestFn).toHaveBeenNthCalledWith(3, 'A good value cou');
|
||||
},
|
||||
};
|
||||
|
||||
export const Placeholder: Story = {};
|
||||
|
||||
export const FullWidth: Story = {
|
||||
args: { value: 'A good value', fullWidth: true },
|
||||
};
|
||||
|
||||
export const WithLabel: Story = {
|
||||
args: { label: 'Lorem ipsum' },
|
||||
};
|
||||
|
||||
export const WithError: Story = {
|
||||
args: { error: 'Lorem ipsum' },
|
||||
};
|
||||
|
||||
export const PasswordInput: Story = {
|
||||
args: { type: 'password', placeholder: 'Password' },
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = canvas.getByPlaceholderText('Password');
|
||||
await userEvent.type(input, 'pa$$w0rd');
|
||||
|
||||
const revealButton = canvas.getByTestId('reveal-password-button');
|
||||
await userEvent.click(revealButton);
|
||||
|
||||
expect(input).toHaveAttribute('type', 'text');
|
||||
},
|
||||
};
|
||||
@ -4,7 +4,7 @@ import { AnimatePresence, LayoutGroup } from 'framer-motion';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
import { Button } from '@/ui/button/components/Button';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { Modal } from '@/ui/modal/components/Modal';
|
||||
import {
|
||||
Section,
|
||||
@ -99,7 +99,7 @@ export const ConfirmationModal = ({
|
||||
</Section>
|
||||
{confirmationValue && (
|
||||
<Section>
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
value={inputConfirmationValue}
|
||||
onChange={handleInputConfimrationValueChange}
|
||||
placeholder={confirmationPlaceholder}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { DatePicker } from '@/ui/input/components/DatePicker';
|
||||
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useUpsertFilter } from '@/ui/view-bar/hooks/useUpsertFilter';
|
||||
import { filterDefinitionUsedInDropdownScopedState } from '@/ui/view-bar/states/filterDefinitionUsedInDropdownScopedState';
|
||||
@ -42,7 +42,7 @@ export const FilterDropdownDateSearchInput = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
<InternalDatePicker
|
||||
date={new Date()}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={handleChange}
|
||||
|
||||
@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { Button } from '@/ui/button/components/Button';
|
||||
import { IconCopy, IconLink } from '@/ui/icon';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -31,7 +31,7 @@ export const WorkspaceInviteLink = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledLinkContainer>
|
||||
<TextInputSettings value={inviteLink} disabled fullWidth />
|
||||
<TextInput value={inviteLink} disabled fullWidth />
|
||||
</StyledLinkContainer>
|
||||
<Button
|
||||
Icon={IconLink}
|
||||
|
||||
@ -14,7 +14,7 @@ import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { MainButton } from '@/ui/button/components/MainButton';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
|
||||
import { H2Title } from '@/ui/typography/components/H2Title';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
@ -145,7 +145,7 @@ export const CreateProfile = () => {
|
||||
field: { onChange, onBlur, value },
|
||||
fieldState: { error },
|
||||
}) => (
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
autoFocus
|
||||
label="First Name"
|
||||
value={value}
|
||||
@ -165,7 +165,7 @@ export const CreateProfile = () => {
|
||||
field: { onChange, onBlur, value },
|
||||
fieldState: { error },
|
||||
}) => (
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
label="Last Name"
|
||||
value={value}
|
||||
onBlur={onBlur}
|
||||
|
||||
@ -11,7 +11,7 @@ import { Title } from '@/auth/components/Title';
|
||||
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { MainButton } from '@/ui/button/components/MainButton';
|
||||
import { TextInputSettings } from '@/ui/input/text/components/TextInputSettings';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
|
||||
import { H2Title } from '@/ui/typography/components/H2Title';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
@ -122,7 +122,7 @@ export const CreateWorkspace = () => {
|
||||
field: { onChange, onBlur, value },
|
||||
fieldState: { error },
|
||||
}) => (
|
||||
<TextInputSettings
|
||||
<TextInput
|
||||
autoFocus
|
||||
value={value}
|
||||
placeholder="Apple"
|
||||
|
||||
Reference in New Issue
Block a user