Skip to content

Commit

Permalink
feat: add textarea height and scroll with tags
Browse files Browse the repository at this point in the history
  • Loading branch information
saurabhdaware committed Apr 8, 2024
1 parent d85b9b7 commit b3baecd
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 25 deletions.
1 change: 1 addition & 0 deletions packages/blade/src/components/Box/BaseBox/baseBoxStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ const getAllProps = (
breakpoint,
),
borderStyle: hasBorder ? 'solid' : undefined,
cursor: getResponsiveValue(props.cursor, breakpoint),
// Since we only allow 'solid', we can use the same value for all borders if hasBorder is true
// If hasBorder is false, we need to check each border individually
...(!hasBorder && {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ type BaseBoxVisualProps = MakeObjectResponsive<
| 'borderBottom'
| 'opacity'
| 'pointerEvents'
| 'cursor'
>
>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { baseInputHeight, baseInputWrapperMaxHeight } from './baseInputTokens';
import BaseBox from '~components/Box/BaseBox';
import { motion } from '~tokens/global';
import { castWebType, makeMotionTime, makeSize } from '~utils';
import { castWebType, makeMotionTime, makeSize, makeSpace } from '~utils';
import type { BladeElementRef } from '~utils/types';

const StyledBaseInputWrapper = styled(BaseBox)<
Expand Down Expand Up @@ -39,6 +39,7 @@ const StyledBaseInputWrapper = styled(BaseBox)<
isDisabled: props.isDisabled,
validationState: props.validationState,
isDropdownTrigger: props.isDropdownTrigger,
isTextArea: props.isTextArea,
}),
transitionProperty: 'background-color',
transitionDuration: castWebType(makeMotionTime(props.theme.motion.duration.xquick)),
Expand All @@ -51,6 +52,7 @@ const StyledBaseInputWrapper = styled(BaseBox)<
isDisabled: props.isDisabled,
validationState: props.validationState,
isDropdownTrigger: props.isDropdownTrigger,
isTextArea: props.isTextArea,
}),
},
}));
Expand Down Expand Up @@ -130,6 +132,12 @@ to {
? expandTransition
: collapseTransition
}
height={
rest.isTextArea && isDropdownTrigger
? makeSpace((rest.numberOfLines ?? 0) * baseInputHeight[rest.size])
: undefined
}
cursor={rest.isTextArea && isDropdownTrigger ? 'text' : undefined}
isDropdownTrigger={isDropdownTrigger}
showAllTags={showAllTags}
maxTagRows={maxTagRows}
Expand Down
11 changes: 10 additions & 1 deletion packages/blade/src/components/Input/BaseInput/BaseInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { assignWithoutSideEffects } from '~utils/assignWithoutSideEffects';
import type { LinkProps } from '~components/Link';
import { getFocusRingStyles } from '~utils/getFocusRingStyles';
import getIn from '~utils/lodashButBetter/get';
import { useMergeRefs } from '~utils/useMergeRefs';

type CommonAutoCompleteSuggestionTypes =
| 'none'
Expand Down Expand Up @@ -811,6 +812,8 @@ const _BaseInput: React.ForwardRefRenderFunction<BladeElementRef, BaseInputProps
ref,
) => {
const { theme } = useTheme();
const inputRef = React.useRef<HTMLInputElement | HTMLButtonElement>(null);
const mergedInputRef = useMergeRefs(ref, inputRef);
const inputWrapperRef: InputWrapperRef = React.useRef(null);
const { onInputKeydownTagHandler, visibleTagsCountRef } = useTags(
tags,
Expand Down Expand Up @@ -942,6 +945,10 @@ const _BaseInput: React.ForwardRefRenderFunction<BladeElementRef, BaseInputProps
}}
maxTagRows={maxTagRows}
size={size}
numberOfLines={numberOfLines}
onClick={() => {
inputRef.current?.focus();
}}
>
<BaseInputVisuals
size={size}
Expand Down Expand Up @@ -970,11 +977,13 @@ const _BaseInput: React.ForwardRefRenderFunction<BladeElementRef, BaseInputProps
maxTagRows={maxTagRows}
inputWrapperRef={inputWrapperRef}
size={size}
numberOfLines={numberOfLines}
isTextArea={isTextArea}
>
<StyledBaseInput
as={as}
id={inputId}
ref={ref as any}
ref={mergedInputRef as any}
name={name}
type={type}
defaultValue={defaultValue}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ const BaseInputTagSlot = ({
visibleTagsCountRef,
labelPrefix,
isDisabled,
numberOfLines,
size,
}: BaseInputTagSlotProps): React.ReactElement => {
const hasTags = tags && tags.length > 0;
Expand Down Expand Up @@ -189,6 +190,7 @@ const BaseInputTagSlot = ({
overflowX="auto"
overflowY={showAllTags || maxTagRows === 'multiple' ? 'auto' : 'hidden'}
minHeight={makeSize(baseInputHeight[size])}
maxHeight={makeSize(baseInputHeight[size] * (numberOfLines ?? 1))}
onMouseDown={() => {
setShouldIgnoreBlurAnimation?.(true);
}}
Expand Down
23 changes: 3 additions & 20 deletions packages/blade/src/components/Input/BaseInput/BaseInputWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,8 @@
import type { ReactElement, ReactNode } from 'react';
import React from 'react';
import type { BaseInputProps } from './BaseInput';
import { AnimatedBaseInputWrapper } from './AnimatedBaseInputWrapper';
import type { BaseInputWrapperProps } from './types';
import type { ContainerElementType } from '~utils/types';
import type { ActionStates } from '~utils/useInteraction';

type BaseInputWrapperProps = Pick<
BaseInputProps,
| 'isDisabled'
| 'validationState'
| 'showAllTags'
| 'maxTagRows'
| 'setInputWrapperRef'
| 'isDropdownTrigger'
> & {
isFocused?: boolean;
isLabelLeftPositioned?: boolean;
currentInteraction: ActionStates;
isTextArea?: boolean;
setShowAllTagsWithAnimation: (showAllTagsWithAnimation: boolean) => void;
children: React.ReactNode;
size: NonNullable<BaseInputProps['size']>;
};

const _BaseInputWrapper: React.ForwardRefRenderFunction<
ContainerElementType,
Expand All @@ -38,6 +19,7 @@ const _BaseInputWrapper: React.ForwardRefRenderFunction<
showAllTags,
setShowAllTagsWithAnimation,
maxTagRows,
numberOfLines,
...props
},
ref,
Expand All @@ -52,6 +34,7 @@ const _BaseInputWrapper: React.ForwardRefRenderFunction<
showAllTags={showAllTags}
maxTagRows={maxTagRows}
setShowAllTagsWithAnimation={setShowAllTagsWithAnimation}
numberOfLines={numberOfLines}
{...props}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ const _StyledBaseInput: React.ForwardRefRenderFunction<
type={type === 'telephone' ? 'tel' : type}
required={isRequired}
maxLength={maxCharacters}
rows={numberOfLines}
// In Tagged TextArea, tags take up their own space so we need to define height instead of relying on HTML rows
rows={props.isTextArea && props.isDropdownTrigger ? 1 : numberOfLines}
numberOfLines={numberOfLines}
inputMode={keyboardType === 'telephone' ? 'tel' : keyboardType}
onChange={(event: React.ChangeEvent<HTMLInputElement>): void =>
handleOnChange?.({ name, value: event })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const getInputBackgroundAndBorderStyles = ({
width: '100%',
alignItems: isTextArea ? 'flex-start' : undefined,
position: 'relative',
height: isDropdownTrigger ? 'auto' : undefined,
height: isDropdownTrigger && !isTextArea ? 'auto' : undefined,
border: 'none',
...getBaseInputBorderStyles({ theme, borderColor, borderWidth, isFocused }),
};
Expand Down Expand Up @@ -227,7 +227,7 @@ export const getBaseInputStyles = ({
textAlign,
width: '100%',
height: isTextArea || isDropdownWithTags ? undefined : makeSpace(baseInputHeight[size]),
minHeight: isDropdownWithTags ? undefined : makeSpace(baseInputHeight[size]),
minHeight: isTextArea || isDropdownWithTags ? undefined : makeSpace(baseInputHeight[size]),
...(isReactNative ? {} : { resize: 'none' }),
};
};
Expand Down
4 changes: 4 additions & 0 deletions packages/blade/src/components/Input/BaseInput/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export type BaseInputTagSlotProps = {
inputWrapperRef: InputWrapperRef;
labelPrefix?: string;
size: NonNullable<BaseInputProps['size']>;
isTextArea?: boolean;
numberOfLines: BaseInputProps['numberOfLines'];
};

export type BaseInputWrapperProps = Pick<
Expand All @@ -40,6 +42,8 @@ export type BaseInputWrapperProps = Pick<
setShowAllTagsWithAnimation?: (showAllTagsWithAnimation: boolean) => void;
children: React.ReactNode;
size: NonNullable<BaseInputProps['size']>;
numberOfLines: BaseInputProps['numberOfLines'];
onClick?: () => void;
};

export type StyledBaseInputProps = {
Expand Down

0 comments on commit b3baecd

Please sign in to comment.