Skip to content

Commit

Permalink
refactor: remove form field wrapping textarea
Browse files Browse the repository at this point in the history
  • Loading branch information
abelflopes committed Jul 3, 2024
1 parent b66a5b5 commit 07ce4e0
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 20 deletions.
53 changes: 39 additions & 14 deletions packages/components/textarea/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import React from "react";
import React, { useEffect, useMemo } from "react";
import styles from "./styles/index.module.scss";
import classNames from "classnames";
import { FormField, type FormFieldProps } from "@react-ck/form-field";
import { useFormFieldContext, type FormFieldProps } from "@react-ck/form-field";

export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
label?: FormFieldProps["label"];
skin?: FormFieldProps["skin"];
description?: FormFieldProps["description"];
validationMessage?: FormFieldProps["validationMessage"];
}

/**
Expand All @@ -17,14 +14,42 @@ export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextArea
*/

export const Textarea = ({
skin = "default",
label,
description,
validationMessage,
skin,
id,
className,
...props
}: Readonly<TextareaProps>): React.ReactElement => (
<FormField {...{ skin, label, description, validationMessage }}>
<textarea {...props} className={classNames(className, styles.root)} />
</FormField>
);
}: Readonly<TextareaProps>): React.ReactElement => {
const formFieldContext = useFormFieldContext();

const computedSkin = useMemo(
() => formFieldContext?.skin ?? skin ?? "default",
[formFieldContext?.skin, skin],
);

const computedId = useMemo(() => formFieldContext?.id ?? id, [formFieldContext?.id, id]);

// Validate usage inside form field
useEffect(() => {
// Is not inside form field, skip
if (formFieldContext === undefined) return;

// Is inside form field
if (skin)
throw new Error("When using textarea inside form field, define skin on the form field");
else if (id)
throw new Error("When using textarea inside form field, define id on the form field");
}, [formFieldContext, id, skin]);

return (
<textarea
{...props}
id={computedId}
className={classNames(
styles.root,
formFieldContext === undefined && styles.standalone,
className,
styles[`skin_${computedSkin}`],
)}
/>
);
};
20 changes: 18 additions & 2 deletions packages/components/textarea/src/styles/index.module.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
@import "@react-ck/form-field";
@use "@react-ck/theme";
@use "@react-ck/form-field";

// TODO: fix height offset between standalone and non-standalone (border)

.root {
@include form-field-input;
@include form-field.form-field-input;
}

// When not inside form field, has own border, etc
.standalone {
@include form-field.form-field-container;

@each $key, $props in form-field.$form-field-styles {
&.skin_#{$key} {
@each $propKey, $propValue in $props {
@include theme.define-css-var(form-field, $propKey, $propValue);
}
}
}
}
25 changes: 21 additions & 4 deletions packages/docs/stories/src/textarea.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { faker } from "@faker-js/faker";
import { sentenceCase } from "change-case";
import { configureStory } from "@react-ck/story-config";
import { Textarea } from "@react-ck/textarea/src";
import { Normal as FormFieldNormal, Validation as FormFieldValidation } from "./form-field.stories";
import { objectExclude } from "../utils/object-exclude";
import { FormField } from "@react-ck/form-field/src";

type Story = StoryObj<typeof Textarea>;

Expand All @@ -27,7 +26,6 @@ export default meta;

export const Normal: Story = {
args: {
...objectExclude(FormFieldNormal.args ?? {}, ["children"]),
rows: 5,
required: true,
placeholder: sentenceCase(faker.lorem.words({ min: 10, max: 20 })),
Expand All @@ -36,7 +34,26 @@ export const Normal: Story = {

export const Validation: Story = {
args: {
...objectExclude(FormFieldValidation.args ?? {}, ["children"]),
skin: "negative",
rows: 5,
required: true,
placeholder: sentenceCase(faker.lorem.words({ min: 10, max: 20 })),
},
};

export const WithFormField: Story = {
decorators: [
(Story: () => React.ReactElement): React.ReactElement => (
<FormField
skin="negative"
label="Your address"
description="Insert your primary address"
validationMessage="Required field">
<Story />
</FormField>
),
],
args: {
rows: 5,
required: true,
placeholder: sentenceCase(faker.lorem.words({ min: 10, max: 20 })),
Expand Down

0 comments on commit 07ce4e0

Please sign in to comment.