Skip to content

Commit

Permalink
feat(Textarea): migrate to Tailwind
Browse files Browse the repository at this point in the history
  • Loading branch information
mvidalgarcia committed Nov 6, 2023
1 parent 5a3f3cc commit 14d6abc
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 527 deletions.
Expand Up @@ -76,7 +76,7 @@ describe("Textarea", () => {

await user.tab();
expect(screen.getByText("error")).toBeInTheDocument();
expect(textarea).toHaveStyle({ padding: "8px 12px" });
expect(textarea).toHaveStyle({ padding: "8px 12px 8px 12px" });
expect(textarea).toBeInvalid();
expect(textarea).toHaveAccessibleDescription("error");
// Needs to flush async `floating-ui` hooks
Expand Down
155 changes: 34 additions & 121 deletions packages/orbit-components/src/Textarea/index.tsx
@@ -1,128 +1,16 @@
"use client";

import * as React from "react";
import styled, { css } from "styled-components";
import cx from "clsx";

import type * as Common from "../common/types";
import type { Theme } from "../defaultTheme";
import defaultTheme from "../defaultTheme";
import ErrorFormTooltip from "../ErrorFormTooltip";
import FormLabel from "../FormLabel";
import { SIZE_OPTIONS, RESIZE_OPTIONS } from "./consts";
import { rtlSpacing } from "../utils/rtl";
import getSpacingToken from "../common/getSpacingToken";
import useErrorTooltip from "../ErrorFormTooltip/hooks/useErrorTooltip";
import getFieldDataState from "../common/getFieldDataState";
import mq from "../utils/mediaQuery";
import type { Props } from "./types";
import useRandomId from "../hooks/useRandomId";

const Field = styled.label<{ fullHeight?: boolean; spaceAfter?: Common.SpaceAfterSizes }>`
${({ theme, fullHeight }) => css`
font-family: ${theme.orbit.fontFamily};
display: flex;
width: 100%;
position: relative;
height: ${fullHeight && "100%"};
flex-direction: column;
flex: ${fullHeight && "1"};
margin-bottom: ${getSpacingToken};
`};
`;

Field.defaultProps = {
theme: defaultTheme,
};

const getFontSize = ({ theme, size }: { theme: Theme; size?: Props["size"] }) => {
const tokens = {
[SIZE_OPTIONS.SMALL]: theme.orbit.fontSizeInputSmall,
[SIZE_OPTIONS.NORMAL]: theme.orbit.fontSizeInputNormal,
};

if (!size) return null;

return tokens[size];
};

const getLineHeight = ({ theme, size }: { theme: Theme; size?: Props["size"] }) => {
const tokens = {
[SIZE_OPTIONS.SMALL]: theme.orbit.lineHeightTextSmall,
[SIZE_OPTIONS.NORMAL]: theme.orbit.lineHeightTextNormal,
};

if (!size) return null;

return tokens[size];
};

const getPadding = ({ theme, size }: { theme: Theme; size?: Props["size"] }) => {
const tokens = {
[SIZE_OPTIONS.SMALL]: theme.orbit.paddingTextareaSmall,
[SIZE_OPTIONS.NORMAL]: theme.orbit.paddingTextareaNormal,
};

if (!size) return null;

return rtlSpacing(tokens[size]);
};

// TODO: add token for height
// flex is used for Stack
interface StyledTextAreaProps extends Partial<Props> {
fullHeight?: boolean;
}

const StyledTextArea = styled.textarea<StyledTextAreaProps>`
${({ theme, resize, fullHeight, error, disabled, readOnly }) => css`
appearance: none;
box-sizing: border-box;
display: block;
width: 100%;
height: ${fullHeight && "100%"};
padding: ${getPadding};
box-shadow: inset 0 0 0 ${theme.orbit.borderWidthInput}
${error ? theme.orbit.borderColorInputError : theme.orbit.borderColorInput};
background-color: ${disabled || readOnly
? theme.orbit.backgroundInputDisabled
: theme.orbit.backgroundInput};
color: ${disabled || readOnly
? theme.orbit.colorTextInputDisabled
: theme.orbit.colorTextInput};
font-size: ${getFontSize};
line-height: ${getLineHeight};
cursor: ${disabled ? "not-allowed" : "text"};
font-family: ${theme.orbit.fontFamily};
resize: ${resize};
transition: box-shadow ${theme.orbit.durationFast} ease-in-out;
min-height: 44px;
/* for usage with Stack */
border-radius: ${theme.orbit.borderRadiusNormal};
${mq.tablet(css`
border-radius: ${theme.orbit.borderRadiusNormal};
`)};
flex: ${fullHeight && "1"};
border: 1px solid transparent;
overflow: auto;
&::placeholder {
color: ${theme.orbit.colorPlaceholderInput};
}
&:hover {
box-shadow: ${!(disabled || readOnly) &&
css`inset 0 0 0 ${theme.orbit.borderWidthInput} ${
error ? theme.orbit.borderColorInputErrorHover : theme.orbit.borderColorInputHover
}`};
}
`};
`;

StyledTextArea.defaultProps = {
theme: defaultTheme,
};
import { getSpaceAfterClasses } from "../common/tailwind";

const Textarea = React.forwardRef<HTMLTextAreaElement, Props>((props, ref) => {
const {
Expand Down Expand Up @@ -170,7 +58,14 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, Props>((props, ref) => {
const shown = tooltipShown || tooltipShownHover;

return (
<Field fullHeight={fullHeight} spaceAfter={spaceAfter} ref={labelRef}>
<label
className={cx(
"font-base relative flex w-full flex-col",
fullHeight && "h-full flex-1",
spaceAfter && getSpaceAfterClasses(spaceAfter),
)}
ref={labelRef}
>
{label && (
<FormLabel
filled={!!value}
Expand All @@ -186,25 +81,43 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, Props>((props, ref) => {
</FormLabel>
)}

<StyledTextArea
<textarea
className={cx(
"w-full appearance-none",
"font-base",
"rounded-normal relative box-border block overflow-auto",
"min-h-form-box-normal",
"duration-fast transition-shadow ease-in-out",
"border border-transparent",
// TODO: remove when will be migrated from tmp-folder
size === SIZE_OPTIONS.SMALL && "text-normal px-sm py-xs leading-normal",
resize === RESIZE_OPTIONS.VERTICAL ? "resize-y" : "resize-none",
size === SIZE_OPTIONS.NORMAL && "text-normal p-sm leading-normal",
error ? "shadow-form-element-error" : "shadow-form-element",
disabled ? "cursor-not-allowed" : "cursor-text",
fullHeight && "h-full flex-1",
disabled || readOnly
? "bg-form-element-disabled-background"
: [
"bg-form-element-background",
error ? "hover:shadow-form-element-error-hover" : "hover:bg-form-element-hover",
],
"[&::placeholder]:text-form-element-foreground",
)}
data-state={getFieldDataState(!!error)}
data-test={dataTest}
aria-required={!!required}
id={inputId}
name={name}
value={value}
defaultValue={defaultValue}
size={size}
fullHeight={fullHeight}
disabled={disabled}
error={error}
placeholder={String(placeholder)}
maxLength={maxLength}
onChange={onChange}
rows={rows}
onFocus={handleFocus}
onBlur={onBlur}
resize={resize}
tabIndex={tabIndex ? Number(tabIndex) : undefined}
readOnly={readOnly}
ref={ref}
Expand All @@ -224,7 +137,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, Props>((props, ref) => {
referenceElement={labelRef}
/>
)}
</Field>
</label>
);
});

Expand Down
1 change: 0 additions & 1 deletion packages/orbit-components/src/tmp-tailwind/.npmignore

This file was deleted.

This file was deleted.

0 comments on commit 14d6abc

Please sign in to comment.