Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(textarea): ✨ finish theming & stories #319

Merged
merged 1 commit into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
(props, ref) => {
const { wrapperProps, baseProps, iconProps, ghostProps, uiProps } =
useTextareaProps(props);
const { loading, invalid, spinner } = uiProps;
const { loading, icon, spinner } = uiProps;

return (
<TextareaWrapper {...wrapperProps}>
<TextareaBase ref={ref} {...baseProps} />
{loading ? (
runIfFn(spinner, uiProps)
) : invalid ? (
) : icon ? (
<TextareaIcon {...iconProps} />
) : null}
<TextareaGhost {...ghostProps} />
Expand Down
31 changes: 18 additions & 13 deletions src/textarea/TextareaBase.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ChangeEvent } from "react";
import { FocusableOptions, useFocusable } from "ariakit";
import { cx, useEvent, useForkRef } from "ariakit-utils";
import {
createComponent,
Expand All @@ -7,8 +8,8 @@ import {
} from "ariakit-utils/system";
import { As, Props } from "ariakit-utils/types";

import { BoxOptions, useBox } from "../box";
import { useTheme } from "../theme";
import { tcm } from "../utils";

import { TextareaUIProps } from "./TextareaProps";

Expand All @@ -31,18 +32,22 @@ export const useTextareaBase = createHook<TextareaBaseOptions>(
...props
}) => {
const theme = useTheme("textarea");
const className = cx(
theme.base.common,
size ? theme.base.size[size] : "",
variant ? theme.base.variant[variant].common : "",
props.disabled || invalid
const className = tcm(
theme.base.default,
resize ? theme.base.resize[resize] : "",
size ? theme.size[size]?.base : "",
props.disabled
? ""
: variant
? theme.base.variant[variant].interactions
? cx(
theme.variant[variant]?.default?.base,
theme.variant[variant]?.hover?.base,
theme.variant[variant]?.active?.base,
theme.variant[variant]?.focus?.base,
invalid ? theme.variant[variant]?.invalid?.base : "",
)
: "",
variant && props.disabled ? theme.base.variant[variant].disabled : "",
variant && invalid ? theme.base.variant[variant].invalid : "",
resize ? theme.base.resize[resize] : "",
variant && props.disabled ? theme.variant[variant]?.disabled?.base : "",
props.className,
);

Expand All @@ -64,7 +69,7 @@ export const useTextareaBase = createHook<TextareaBaseOptions>(
className,
style: { ...inputStyles, ...props.style },
};
props = useBox(props);
props = useFocusable(props);

return props;
},
Expand All @@ -76,8 +81,8 @@ export const TextareaBase = createComponent<TextareaBaseOptions>(props => {
return createElement("textarea", htmlProps);
});

export type TextareaBaseOptions<T extends As = "textarea"> = BoxOptions<T> &
Partial<TextareaUIProps> & {};
export type TextareaBaseOptions<T extends As = "textarea"> =
FocusableOptions<T> & Partial<TextareaUIProps> & {};

export type TextareaBaseProps<T extends As = "textarea"> = Props<
TextareaBaseOptions<T>
Expand Down
31 changes: 18 additions & 13 deletions src/textarea/TextareaGhost.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FocusableOptions, useFocusable } from "ariakit";
import { cx, useForkRef } from "ariakit-utils";
import {
createComponent,
Expand All @@ -6,8 +7,8 @@ import {
} from "ariakit-utils/system";
import { As, Props } from "ariakit-utils/types";

import { BoxOptions, useBox } from "../box";
import { useTheme } from "../theme";
import { tcm } from "../utils";

import { TextareaUIProps } from "./TextareaProps";

Expand All @@ -30,18 +31,22 @@ export const useTextareaGhost = createHook<TextareaGhostOptions>(
...props
}) => {
const theme = useTheme("textarea");
const className = cx(
theme.base.common,
size ? theme.base.size[size] : "",
variant ? theme.base.variant[variant].common : "",
props.disabled || invalid
const className = tcm(
theme.base.default,
resize ? theme.base.resize[resize] : "",
size ? theme.size[size]?.base : "",
props.disabled
? ""
: variant
? theme.base.variant[variant].interactions
? cx(
theme.variant[variant]?.default?.base,
theme.variant[variant]?.hover?.base,
theme.variant[variant]?.active?.base,
theme.variant[variant]?.focus?.base,
invalid ? theme.variant[variant]?.invalid?.base : "",
)
: "",
variant && props.disabled ? theme.base.variant[variant].disabled : "",
variant && invalid ? theme.base.variant[variant].invalid : "",
resize ? theme.base.resize[resize] : "",
variant && props.disabled ? theme.variant[variant]?.disabled?.base : "",
theme.ghost,
props.className,
);
Expand All @@ -52,7 +57,7 @@ export const useTextareaGhost = createHook<TextareaGhostOptions>(
className,
ref: useForkRef(ghostRef, props.ref),
};
props = useBox(props);
props = useFocusable(props);

return props;
},
Expand All @@ -64,8 +69,8 @@ export const TextareaGhost = createComponent<TextareaGhostOptions>(props => {
return createElement("textarea", htmlProps);
});

export type TextareaGhostOptions<T extends As = "textarea"> = BoxOptions<T> &
Partial<TextareaUIProps> & {};
export type TextareaGhostOptions<T extends As = "textarea"> =
FocusableOptions<T> & Partial<TextareaUIProps> & {};

export type TextareaGhostProps<T extends As = "textarea"> = Props<
TextareaGhostOptions<T>
Expand Down
24 changes: 19 additions & 5 deletions src/textarea/TextareaIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { BoxOptions, useBox } from "../box";
import { useTheme } from "../theme";
import { cx } from "../utils";

import { TextareaBaseProps } from "./TextareaBase";
import { TextareaUIProps } from "./TextareaProps";

export const useTextareaIcon = createHook<TextareaIconOptions>(
Expand All @@ -21,6 +22,7 @@ export const useTextareaIcon = createHook<TextareaIconOptions>(
rowsMin,
invalid,
loading,
disabled,
icon,
spinner,
autoSizeOnChange,
Expand All @@ -31,10 +33,21 @@ export const useTextareaIcon = createHook<TextareaIconOptions>(
}) => {
const theme = useTheme("textarea");
const className = cx(
theme.icon.common,
autoSize ? theme.icon.normal : "",
size ? theme.icon.size[size] : "",
invalid ? theme.icon.invalid : "",
theme.icon.base,
autoSize ? theme.icon.autoSize : "",
size ? theme.size[size]?.icon : "",
disabled
? ""
: variant
? cx(
theme.variant[variant]?.default?.icon,
theme.variant[variant]?.hover?.icon,
theme.variant[variant]?.active?.icon,
theme.variant[variant]?.focus?.icon,
invalid ? theme.variant[variant]?.invalid?.icon : "",
)
: "",
variant && disabled ? theme.variant[variant]?.disabled?.icon : "",
props.className,
);

Expand All @@ -52,7 +65,8 @@ export const TextareaIcon = createComponent<TextareaIconOptions>(props => {
});

export type TextareaIconOptions<T extends As = "div"> = BoxOptions<T> &
Partial<TextareaUIProps> & {};
Partial<TextareaUIProps> &
Pick<TextareaBaseProps, "disabled"> & {};

export type TextareaIconProps<T extends As = "div"> = Props<
TextareaIconOptions<T>
Expand Down
16 changes: 10 additions & 6 deletions src/textarea/TextareaProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const useTextareaProps = ({
className,
style,
children,
disabled,
...restProps
}: TextareaProps): TextareaPropsReturn => {
const uiState = useTextareaUIState({
Expand Down Expand Up @@ -69,22 +70,25 @@ export const useTextareaProps = ({
...uiProps,
placeholder,
value,
disabled,
...restProps,
...componentProps.baseProps,
};

const iconProps: TextareaIconProps = {
...uiProps,
...componentProps.iconProps,
children: withIconA11y(runIfFn(uiProps.icon, uiProps)),
};

const ghostProps: TextareaGhostProps = {
...uiProps,
disabled,
...restProps,
...componentProps.ghostProps,
};

const iconProps: TextareaIconProps = {
...uiProps,
disabled,
...componentProps.iconProps,
children: withIconA11y(runIfFn(uiProps.icon, uiProps)),
};

return {
uiProps,
wrapperProps,
Expand Down
6 changes: 3 additions & 3 deletions src/textarea/TextareaUIState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function useTextareaUIState(
rowsMin = 1,
invalid = false,
loading = false,
icon = <SlotIcon />,
icon = invalid ? <SlotIcon /> : null,
spinner = DefaultTextareaSpinner,
} = props;

Expand All @@ -44,14 +44,14 @@ export type TextareaUIState = {
*
* @default md
*/
size: keyof AdaptUI.GetThemeValue<"textarea", "base", "size">;
size: keyof AdaptUI.GetThemeValue<"textarea", "size">;

/**
* How the textarea should look?
*
* @default outline
*/
variant: keyof AdaptUI.GetThemeValue<"textarea", "base", "variant">;
variant: keyof AdaptUI.GetThemeValue<"textarea", "variant">;

/**
* Minimum number of rows to be displayed.
Expand Down
2 changes: 1 addition & 1 deletion src/textarea/__utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const DefaultTextareaSpinner = (props: TextareaUIProps) => {

return (
<Spinner
className={tcm(theme.icon.common, autoSize ? theme.icon.normal : "")}
className={tcm(theme.icon.base, autoSize ? theme.icon.autoSize : "")}
size={size !== "xl" ? "xs" : "md"}
/>
);
Expand Down
28 changes: 15 additions & 13 deletions src/textarea/stories/TextareaBasic.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@ export default {
title: "Forms/Textarea/Basic",
component: TextareaBasic,
argTypes: {
label: { control: { type: "text" } },
description: { control: { type: "text" } },
...createControls(undefined, {
...createControls("textarea", {
ignore: [
"unstable_system",
"unstable_clickOnEnter",
"unstable_clickOnSpace",
"ref",
"wrapElement",
"focusable",
"as",
"setState",
"checked",
"value",
"defaultState",
"state",
"onStateChange",
"icon",
"spinner",
"inputRef",
"ghostRef",
"inputStyles",
"autoSizeOnChange",
"autoFocus",
"focusable",
"accessibleWhenDisabled",
"onFocusVisible",
"clickOnEnter",
"clickOnSpace",
],
}),
},
Expand All @@ -54,6 +54,8 @@ export const Default: Story = {
variant: "outline",
rowsMin: 3,
cols: 30,
autoSize: false,
resize: "none",
},
};

Expand Down
Loading