File size: 3,654 Bytes
0bfe2e3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { cva } from 'class-variance-authority';
import * as React from 'react';
import {
  BasicField,
  BasicFieldOptions,
  extractBasicFieldProps,
} from '../basic-field';
import { cn, defineStyleAnatomy } from '../core/styling';
import {
  extractInputPartProps,
  InputAddon,
  InputAnatomy,
  InputContainer,
  InputIcon,
  InputStyling,
} from '../input';

/* -------------------------------------------------------------------------------------------------
 * Anatomy
 * -----------------------------------------------------------------------------------------------*/

export const TextareaAnatomy = defineStyleAnatomy({
  root: cva(['UI-Textarea__root', 'w-full p-2'], {
    variants: {
      size: {
        sm: 'h-20',
        md: 'h-32',
        lg: 'h-64',
      },
    },
    defaultVariants: {
      size: 'md',
    },
  }),
});

/* -------------------------------------------------------------------------------------------------
 * Textarea
 * -----------------------------------------------------------------------------------------------*/

export type TextareaProps = Omit<
  React.ComponentPropsWithRef<'textarea'>,
  'size'
> &
  InputStyling &
  BasicFieldOptions & {
    /**
     * Callback invoked when the value changes. Returns the string value.
     */
    onValueChange?: (value: string) => void;
  };

export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
  (props, ref) => {
    const [props1, basicFieldProps] = extractBasicFieldProps<TextareaProps>(
      props,
      React.useId()
    );

    const [
      {
        size,
        intent,
        leftAddon,
        leftIcon,
        rightAddon,
        rightIcon,
        className,
        onValueChange,
        onChange,
        ...rest
      },
      {
        inputContainerProps,
        leftAddonProps,
        leftIconProps,
        rightAddonProps,
        rightIconProps,
      },
    ] = extractInputPartProps<TextareaProps>({
      ...props1,
      size: props1.size ?? 'md',
      intent: props1.intent ?? 'basic',
      leftAddon: props1.leftAddon,
      leftIcon: props1.leftIcon,
      rightAddon: props1.rightAddon,
      rightIcon: props1.rightIcon,
    });

    const handleOnChange = React.useCallback(
      (e: React.ChangeEvent<HTMLTextAreaElement>) => {
        onValueChange?.(e.target.value);
        onChange?.(e);
      },
      []
    );

    return (
      <BasicField {...basicFieldProps}>
        <InputContainer {...inputContainerProps}>
          <InputAddon {...leftAddonProps} />
          <InputIcon {...leftIconProps} />

          <textarea
            id={basicFieldProps.id}
            name={basicFieldProps.name}
            className={cn(
              'form-textarea',
              InputAnatomy.root({
                size,
                intent,
                hasError: !!basicFieldProps.error,
                isDisabled: !!basicFieldProps.disabled,
                isReadonly: !!basicFieldProps.readonly,
                hasRightAddon: !!rightAddon,
                hasRightIcon: !!rightIcon,
                hasLeftAddon: !!leftAddon,
                hasLeftIcon: !!leftIcon,
              }),
              TextareaAnatomy.root({ size }),
              className
            )}
            disabled={basicFieldProps.disabled || basicFieldProps.readonly}
            data-disabled={basicFieldProps.disabled}
            onChange={handleOnChange}
            {...rest}
            ref={ref}
          />

          <InputAddon {...rightAddonProps} />
          <InputIcon {...rightIconProps} />
        </InputContainer>
      </BasicField>
    );
  }
);

Textarea.displayName = 'Textarea';