@liguelead/design-system 0.0.36 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Alert/Alert.style.ts +1 -1
- package/components/Alert/Alert.tsx +3 -1
- package/components/Alert/Alert.variants.ts +2 -4
- package/components/Button/Button.appearance.ts +3 -4
- package/components/Button/Button.styles.ts +0 -1
- package/components/Button/Button.tsx +4 -7
- package/components/Button/Button.types.ts +1 -1
- package/components/Checkbox/Checkbox.tsx +5 -5
- package/components/Combobox/Combobox.styles.ts +1 -1
- package/components/Combobox/Combobox.tsx +1 -1
- package/components/Dialog/Dialog.style.ts +2 -1
- package/components/Dialog/Dialog.tsx +6 -8
- package/components/IconButton/IconButton.tsx +3 -1
- package/components/LinkButton/LinkButton.tsx +3 -1
- package/components/PageWrapper/PageWrapper.tsx +1 -1
- package/components/RadioCardGroup/RadioCardGroup.stories.tsx +203 -0
- package/components/RadioCardGroup/RadioCardGroup.styles.ts +198 -0
- package/components/RadioCardGroup/RadioCardGroup.tsx +159 -0
- package/components/RadioCardGroup/RadioCardGroup.types.ts +29 -0
- package/components/RadioCardGroup/index.ts +2 -0
- package/components/SplitButton/SplitButton.tsx +1 -1
- package/components/Stepper/Stepper.appearance.ts +57 -0
- package/components/Stepper/Stepper.stories.tsx +300 -0
- package/components/Stepper/Stepper.styles.ts +179 -0
- package/components/Stepper/Stepper.tsx +118 -0
- package/components/Stepper/Stepper.types.ts +27 -0
- package/components/Stepper/index.ts +7 -0
- package/components/Tabs/Tabs.tsx +2 -0
- package/components/TextField/TextField.stories.tsx +109 -2
- package/components/TextField/TextField.styles.ts +44 -0
- package/components/TextField/TextField.tsx +130 -8
- package/components/TextField/TextField.types.ts +11 -1
- package/components/Toaster/Toaster.ts +5 -19
- package/package.json +1 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import styled, { css, keyframes } from 'styled-components'
|
|
2
|
+
import { spacing, fontSize, fontWeight, lineHeight, radius } from '@liguelead/foundation'
|
|
3
|
+
import { parseColor } from '../../utils'
|
|
4
|
+
import {
|
|
5
|
+
TStepIndicatorProps,
|
|
6
|
+
TStepSeparatorProps,
|
|
7
|
+
TStepperContainerProps,
|
|
8
|
+
} from './Stepper.types'
|
|
9
|
+
import { StepIndicatorAppearance } from './Stepper.appearance'
|
|
10
|
+
|
|
11
|
+
const popIn = keyframes`
|
|
12
|
+
0% { transform: scale(0.5); opacity: 0; }
|
|
13
|
+
60% { transform: scale(1.2); }
|
|
14
|
+
100% { transform: scale(1); opacity: 1; }
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
const fillLine = keyframes`
|
|
18
|
+
from { width: 0%; }
|
|
19
|
+
to { width: 100%; }
|
|
20
|
+
`
|
|
21
|
+
|
|
22
|
+
const fillLineV = keyframes`
|
|
23
|
+
from { height: 0%; }
|
|
24
|
+
to { height: 100%; }
|
|
25
|
+
`
|
|
26
|
+
export const StepperWrapper = styled.div`
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: row;
|
|
29
|
+
align-items: flex-start;
|
|
30
|
+
width: 100%;
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
export const StepColumn = styled.div`
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: center;
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
`
|
|
39
|
+
|
|
40
|
+
export const StepperLabelsRow = styled.div`
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: row;
|
|
43
|
+
align-items: flex-start;
|
|
44
|
+
width: 100%;
|
|
45
|
+
`
|
|
46
|
+
|
|
47
|
+
export const StepLabelCell = styled.div`
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
align-items: center;
|
|
51
|
+
text-align: center;
|
|
52
|
+
margin-top: ${spacing.spacing8}px;
|
|
53
|
+
`
|
|
54
|
+
|
|
55
|
+
export const StepperContainer = styled.ol<TStepperContainerProps>`
|
|
56
|
+
display: flex;
|
|
57
|
+
list-style: none;
|
|
58
|
+
margin: 0;
|
|
59
|
+
padding: 0;
|
|
60
|
+
width: 100%;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
`
|
|
63
|
+
|
|
64
|
+
export const StepperItem = styled.li<{ $orientation: 'horizontal' | 'vertical' }>`
|
|
65
|
+
display: flex;
|
|
66
|
+
position: relative;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
align-items: flex-start;
|
|
69
|
+
gap: ${spacing.spacing8}px;
|
|
70
|
+
`
|
|
71
|
+
|
|
72
|
+
export const StepBody = styled.div<{ $orientation: 'horizontal' | 'vertical' }>`
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-direction: row;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: ${spacing.spacing8}px;
|
|
77
|
+
`
|
|
78
|
+
|
|
79
|
+
export const StepTrigger = styled.div<{ $orientation: 'horizontal' | 'vertical' }>`
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
cursor: default;
|
|
83
|
+
gap: ${spacing.spacing8}px;
|
|
84
|
+
`
|
|
85
|
+
|
|
86
|
+
export const StepIndicator = styled.div<TStepIndicatorProps>`
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
border-radius: 50%;
|
|
91
|
+
flex-shrink: 0;
|
|
92
|
+
font-size: ${fontSize.fontSize14}px;
|
|
93
|
+
font-weight: ${fontWeight.fontWeight600};
|
|
94
|
+
line-height: 1;
|
|
95
|
+
animation: ${popIn} 0.35s ease both;
|
|
96
|
+
transition:
|
|
97
|
+
width 0.3s ease,
|
|
98
|
+
height 0.3s ease,
|
|
99
|
+
background-color 0.3s ease,
|
|
100
|
+
border-color 0.3s ease,
|
|
101
|
+
box-shadow 0.3s ease;
|
|
102
|
+
|
|
103
|
+
${({ $state }) => StepIndicatorAppearance($state)}
|
|
104
|
+
`
|
|
105
|
+
|
|
106
|
+
export const StepSeparator = styled.div<TStepSeparatorProps>`
|
|
107
|
+
border-radius: ${radius.radius4}px;
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
position: relative;
|
|
110
|
+
background-color: ${({ theme }) => parseColor(theme.colors.neutral400)};
|
|
111
|
+
|
|
112
|
+
${({ $orientation }) =>
|
|
113
|
+
$orientation === 'vertical'
|
|
114
|
+
? css`
|
|
115
|
+
width: 2px;
|
|
116
|
+
min-height: ${spacing.spacing8}px;
|
|
117
|
+
margin-left: 13px;
|
|
118
|
+
`
|
|
119
|
+
: css`
|
|
120
|
+
height: 2px;
|
|
121
|
+
flex: 1;
|
|
122
|
+
min-width: ${spacing.spacing16}px;
|
|
123
|
+
margin: 14px ${spacing.spacing4}px 0;
|
|
124
|
+
`}
|
|
125
|
+
|
|
126
|
+
&::after {
|
|
127
|
+
content: '';
|
|
128
|
+
position: absolute;
|
|
129
|
+
inset: 0;
|
|
130
|
+
background-color: ${({ theme }) => parseColor(theme.colors.primary)};
|
|
131
|
+
border-radius: ${radius.radius4}px;
|
|
132
|
+
|
|
133
|
+
${({ $completed, $orientation }) =>
|
|
134
|
+
$completed
|
|
135
|
+
? $orientation === 'vertical'
|
|
136
|
+
? css`
|
|
137
|
+
animation: ${fillLineV} 0.4s ease forwards;
|
|
138
|
+
`
|
|
139
|
+
: css`
|
|
140
|
+
animation: ${fillLine} 0.4s ease forwards;
|
|
141
|
+
`
|
|
142
|
+
: css`
|
|
143
|
+
width: 0%;
|
|
144
|
+
height: 0%;
|
|
145
|
+
`}
|
|
146
|
+
}
|
|
147
|
+
`
|
|
148
|
+
|
|
149
|
+
export const StepContent = styled.div<{ $orientation: 'horizontal' | 'vertical' }>`
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
align-items: flex-start;
|
|
153
|
+
`
|
|
154
|
+
|
|
155
|
+
export const StepLabel = styled.strong<{ $active: boolean }>`
|
|
156
|
+
font-size: ${fontSize.fontSize14}px;
|
|
157
|
+
font-weight: ${({ $active }) =>
|
|
158
|
+
$active ? fontWeight.fontWeight600 : fontWeight.fontWeight400};
|
|
159
|
+
line-height: ${lineHeight.lineHeight20}px;
|
|
160
|
+
color: ${({ theme, $active }) =>
|
|
161
|
+
$active
|
|
162
|
+
? parseColor(theme.colors.textDark)
|
|
163
|
+
: parseColor(theme.colors.textMedium)};
|
|
164
|
+
transition: color 0.3s ease;
|
|
165
|
+
`
|
|
166
|
+
|
|
167
|
+
export const StepDescription = styled.p`
|
|
168
|
+
font-size: ${fontSize.fontSize12}px;
|
|
169
|
+
font-weight: ${fontWeight.fontWeight400};
|
|
170
|
+
line-height: ${lineHeight.lineHeight20}px;
|
|
171
|
+
color: ${({ theme }) => parseColor(theme.colors.textMedium)};
|
|
172
|
+
margin: 0;
|
|
173
|
+
`
|
|
174
|
+
|
|
175
|
+
export const StepNumber = styled.span`
|
|
176
|
+
font-size: ${fontSize.fontSize14}px;
|
|
177
|
+
font-weight: ${fontWeight.fontWeight600};
|
|
178
|
+
line-height: 1;
|
|
179
|
+
`
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { CheckFatIcon, WarningCircleIcon } from '@phosphor-icons/react'
|
|
3
|
+
import * as S from './Stepper.styles'
|
|
4
|
+
import { TStepperProps, StepState } from './Stepper.types'
|
|
5
|
+
|
|
6
|
+
const getStepState = (index: number, currentStep: number): StepState => {
|
|
7
|
+
if (index < currentStep) return 'completed'
|
|
8
|
+
if (index === currentStep) return 'active'
|
|
9
|
+
return 'pending'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const StepIndicatorContent: React.FC<{ state: StepState; index: number }> = ({
|
|
13
|
+
state,
|
|
14
|
+
index,
|
|
15
|
+
}) => {
|
|
16
|
+
if (state === 'completed') return <CheckFatIcon size={14} weight="fill" />
|
|
17
|
+
if (state === 'error') return <WarningCircleIcon size={14} weight="fill" />
|
|
18
|
+
if (state === 'active') return <S.StepNumber>{index + 1}</S.StepNumber>
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const Stepper: React.FC<TStepperProps> = ({
|
|
23
|
+
steps,
|
|
24
|
+
currentStep,
|
|
25
|
+
orientation = 'horizontal',
|
|
26
|
+
className,
|
|
27
|
+
}) => {
|
|
28
|
+
if (orientation === 'horizontal') {
|
|
29
|
+
return (
|
|
30
|
+
<S.StepperWrapper className={className} aria-label="stepper">
|
|
31
|
+
{steps.map((step, index) => {
|
|
32
|
+
const state = getStepState(index, currentStep)
|
|
33
|
+
const isLast = index === steps.length - 1
|
|
34
|
+
return (
|
|
35
|
+
<React.Fragment key={index}>
|
|
36
|
+
<S.StepColumn>
|
|
37
|
+
<S.StepIndicator
|
|
38
|
+
$state={state}
|
|
39
|
+
aria-label={`Etapa ${index + 1}: ${step.label}`}
|
|
40
|
+
aria-current={state === 'active' ? 'step' : undefined}
|
|
41
|
+
>
|
|
42
|
+
<StepIndicatorContent state={state} index={index} />
|
|
43
|
+
</S.StepIndicator>
|
|
44
|
+
<S.StepLabelCell role="listitem" aria-current={state === 'active' ? 'step' : undefined}>
|
|
45
|
+
<S.StepLabel $active={state === 'active'}>
|
|
46
|
+
{step.label}
|
|
47
|
+
</S.StepLabel>
|
|
48
|
+
{step.description && (
|
|
49
|
+
<S.StepDescription>
|
|
50
|
+
{step.description}
|
|
51
|
+
</S.StepDescription>
|
|
52
|
+
)}
|
|
53
|
+
</S.StepLabelCell>
|
|
54
|
+
</S.StepColumn>
|
|
55
|
+
{!isLast && (
|
|
56
|
+
<S.StepSeparator
|
|
57
|
+
role="separator"
|
|
58
|
+
aria-hidden="true"
|
|
59
|
+
$completed={state === 'completed'}
|
|
60
|
+
$orientation="horizontal"
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
</React.Fragment>
|
|
64
|
+
)
|
|
65
|
+
})}
|
|
66
|
+
</S.StepperWrapper>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<S.StepperContainer
|
|
72
|
+
$orientation="vertical"
|
|
73
|
+
className={className}
|
|
74
|
+
role="list"
|
|
75
|
+
aria-label="stepper"
|
|
76
|
+
>
|
|
77
|
+
{steps.map((step, index) => {
|
|
78
|
+
const state = getStepState(index, currentStep)
|
|
79
|
+
const isLast = index === steps.length - 1
|
|
80
|
+
return (
|
|
81
|
+
<S.StepperItem
|
|
82
|
+
key={index}
|
|
83
|
+
$orientation="vertical"
|
|
84
|
+
role="listitem"
|
|
85
|
+
aria-current={state === 'active' ? 'step' : undefined}
|
|
86
|
+
>
|
|
87
|
+
<S.StepBody $orientation="vertical">
|
|
88
|
+
<S.StepIndicator
|
|
89
|
+
$state={state}
|
|
90
|
+
aria-label={`Etapa ${index + 1}: ${step.label}`}
|
|
91
|
+
>
|
|
92
|
+
<StepIndicatorContent state={state} index={index} />
|
|
93
|
+
</S.StepIndicator>
|
|
94
|
+
<S.StepContent $orientation="vertical">
|
|
95
|
+
<S.StepLabel $active={state === 'active'}>
|
|
96
|
+
{step.label}
|
|
97
|
+
</S.StepLabel>
|
|
98
|
+
{step.description && (
|
|
99
|
+
<S.StepDescription>
|
|
100
|
+
{step.description}
|
|
101
|
+
</S.StepDescription>
|
|
102
|
+
)}
|
|
103
|
+
</S.StepContent>
|
|
104
|
+
</S.StepBody>
|
|
105
|
+
{!isLast && (
|
|
106
|
+
<S.StepSeparator
|
|
107
|
+
role="separator"
|
|
108
|
+
aria-hidden="true"
|
|
109
|
+
$completed={state === 'completed'}
|
|
110
|
+
$orientation="vertical"
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
113
|
+
</S.StepperItem>
|
|
114
|
+
)
|
|
115
|
+
})}
|
|
116
|
+
</S.StepperContainer>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type StepperOrientation = 'horizontal' | 'vertical'
|
|
2
|
+
export type StepState = 'completed' | 'active' | 'pending' | 'error'
|
|
3
|
+
|
|
4
|
+
export type TStepItem = {
|
|
5
|
+
label: string
|
|
6
|
+
description?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type TStepperProps = {
|
|
10
|
+
steps: TStepItem[]
|
|
11
|
+
currentStep: number
|
|
12
|
+
orientation?: StepperOrientation
|
|
13
|
+
className?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type TStepIndicatorProps = {
|
|
17
|
+
$state: StepState
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type TStepSeparatorProps = {
|
|
21
|
+
$completed: boolean
|
|
22
|
+
$orientation: StepperOrientation
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type TStepperContainerProps = {
|
|
26
|
+
$orientation: StepperOrientation
|
|
27
|
+
}
|
package/components/Tabs/Tabs.tsx
CHANGED
|
@@ -15,6 +15,8 @@ const Tabs: React.FC<TabsProps> = ({
|
|
|
15
15
|
{items.map(item => (
|
|
16
16
|
<Button
|
|
17
17
|
key={item.key}
|
|
18
|
+
aria-controls={`tab-${item.key}`}
|
|
19
|
+
aria-selected={activeKey === item.key}
|
|
18
20
|
variant={activeKey === item.key ? 'solid' : 'neutralGhost'}
|
|
19
21
|
color={activeKey === item.key ? 'primary' : undefined}
|
|
20
22
|
size="sm"
|
|
@@ -15,13 +15,14 @@ Campo de texto para entrada de dados pelo usuário.
|
|
|
15
15
|
|
|
16
16
|
**Tamanhos:** \`sm\` · \`md\` · \`lg\`
|
|
17
17
|
|
|
18
|
-
**Tipos suportados:** \`text\` · \`password\` · \`email\` · \`number\` · \`file\`
|
|
18
|
+
**Tipos suportados:** \`text\` · \`password\` · \`email\` · \`number\` · \`file\` · \`textarea\`
|
|
19
19
|
|
|
20
20
|
**Boas práticas:**
|
|
21
21
|
- Sempre use \`label\` para identificar o campo
|
|
22
22
|
- Use \`helperText\` para instruções ou validações
|
|
23
23
|
- Use \`error\` para comunicar erros de validação
|
|
24
24
|
- Ícones devem reforçar o tipo de dado esperado
|
|
25
|
+
- No \`textarea\`, use \`maxLength\` para o contador visual e \`htmlMaxLength\` para bloquear digitação pelo browser
|
|
25
26
|
`,
|
|
26
27
|
},
|
|
27
28
|
},
|
|
@@ -48,7 +49,7 @@ Campo de texto para entrada de dados pelo usuário.
|
|
|
48
49
|
},
|
|
49
50
|
type: {
|
|
50
51
|
control: 'select',
|
|
51
|
-
options: ['text', 'password', 'email', 'number', 'file'],
|
|
52
|
+
options: ['text', 'password', 'email', 'number', 'file', 'textarea'],
|
|
52
53
|
description: 'Tipo do input HTML',
|
|
53
54
|
table: { defaultValue: { summary: 'text' } },
|
|
54
55
|
},
|
|
@@ -180,6 +181,112 @@ export const Obrigatorio: Story = {
|
|
|
180
181
|
},
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
export const TextArea: Story = {
|
|
185
|
+
name: 'TextArea',
|
|
186
|
+
parameters: {
|
|
187
|
+
docs: {
|
|
188
|
+
description: {
|
|
189
|
+
story: 'Variante textarea com contador de caracteres, botão de variável e controle de maxLength.',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
render: () => (
|
|
194
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 24, width: 480 }}>
|
|
195
|
+
<TextField
|
|
196
|
+
label="Mensagem simples"
|
|
197
|
+
type="textarea"
|
|
198
|
+
placeholder="Digite sua mensagem..."
|
|
199
|
+
maxLength={160}
|
|
200
|
+
/>
|
|
201
|
+
<TextField
|
|
202
|
+
label="Com botão de variável"
|
|
203
|
+
type="textarea"
|
|
204
|
+
placeholder="Digite sua mensagem..."
|
|
205
|
+
maxLength={160}
|
|
206
|
+
showVariableButton
|
|
207
|
+
variableButtonLabel="Inserir variável"
|
|
208
|
+
/>
|
|
209
|
+
<TextField
|
|
210
|
+
label="Com bloqueio nativo (htmlMaxLength)"
|
|
211
|
+
type="textarea"
|
|
212
|
+
placeholder="Máximo 60 caracteres — browser bloqueia ao atingir o limite"
|
|
213
|
+
maxLength={60}
|
|
214
|
+
htmlMaxLength
|
|
215
|
+
showVariableButton
|
|
216
|
+
variableButtonLabel="Inserir variável"
|
|
217
|
+
/>
|
|
218
|
+
<TextField
|
|
219
|
+
label="Desabilitado"
|
|
220
|
+
type="textarea"
|
|
221
|
+
placeholder="Campo desabilitado"
|
|
222
|
+
maxLength={160}
|
|
223
|
+
showVariableButton
|
|
224
|
+
disabled
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
),
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export const TextAreaHtmlMaxLength: Story = {
|
|
231
|
+
name: 'TextArea — htmlMaxLength',
|
|
232
|
+
parameters: {
|
|
233
|
+
docs: {
|
|
234
|
+
description: {
|
|
235
|
+
story: `
|
|
236
|
+
Por padrão \`maxLength\` só exibe o contador visual — o usuário pode digitar além do limite (estado de erro).
|
|
237
|
+
|
|
238
|
+
Com \`htmlMaxLength\` o browser bloqueia a digitação ao atingir o limite. O botão "Inserir variável" também respeita o limite.
|
|
239
|
+
|
|
240
|
+
| Prop | Comportamento |
|
|
241
|
+
|------|--------------|
|
|
242
|
+
| \`maxLength={n}\` | Contador visual, sem bloqueio |
|
|
243
|
+
| \`maxLength={n} htmlMaxLength\` | Contador + bloqueio nativo |
|
|
244
|
+
`,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
render: () => (
|
|
249
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 24, width: 480 }}>
|
|
250
|
+
<TextField
|
|
251
|
+
label="Só contador (sem bloqueio)"
|
|
252
|
+
type="textarea"
|
|
253
|
+
placeholder="Pode digitar além de 30..."
|
|
254
|
+
maxLength={30}
|
|
255
|
+
showVariableButton
|
|
256
|
+
variableButtonLabel="Inserir variável"
|
|
257
|
+
/>
|
|
258
|
+
<TextField
|
|
259
|
+
label="Contador + bloqueio nativo"
|
|
260
|
+
type="textarea"
|
|
261
|
+
placeholder="Bloqueado em 30 caracteres"
|
|
262
|
+
maxLength={30}
|
|
263
|
+
htmlMaxLength
|
|
264
|
+
showVariableButton
|
|
265
|
+
variableButtonLabel="Inserir variável"
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
),
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export const TextAreaComErro: Story = {
|
|
272
|
+
name: 'TextArea com erro',
|
|
273
|
+
parameters: {
|
|
274
|
+
docs: { description: { story: 'Estado de erro no textarea.' } },
|
|
275
|
+
},
|
|
276
|
+
render: () => (
|
|
277
|
+
<div style={{ width: 480 }}>
|
|
278
|
+
<TextField
|
|
279
|
+
label="Mensagem"
|
|
280
|
+
type="textarea"
|
|
281
|
+
placeholder="Digite sua mensagem..."
|
|
282
|
+
maxLength={160}
|
|
283
|
+
showVariableButton
|
|
284
|
+
error={{ message: 'Campo obrigatório.' }}
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
),
|
|
288
|
+
}
|
|
289
|
+
|
|
183
290
|
export const ExemploLogin: Story = {
|
|
184
291
|
name: 'Exemplo: Formulário de login',
|
|
185
292
|
parameters: {
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
fontSize,
|
|
5
5
|
fontWeight,
|
|
6
6
|
lineHeight,
|
|
7
|
+
radius,
|
|
7
8
|
shadow,
|
|
8
9
|
spacing
|
|
9
10
|
} from '@liguelead/foundation'
|
|
@@ -76,6 +77,9 @@ export const Wrapper = styled.div<StyledInputProps>`
|
|
|
76
77
|
${$themefication.input}
|
|
77
78
|
${size.input}
|
|
78
79
|
}
|
|
80
|
+
${StyledTextArea} {
|
|
81
|
+
${$themefication.input}
|
|
82
|
+
}
|
|
79
83
|
${Label} {
|
|
80
84
|
${$themefication.label}
|
|
81
85
|
${size.label}
|
|
@@ -124,3 +128,43 @@ export const FileInputContainer = styled.div`
|
|
|
124
128
|
width: 100%;
|
|
125
129
|
position: relative;
|
|
126
130
|
`
|
|
131
|
+
|
|
132
|
+
export const StyledTextArea = styled.textarea.withConfig({
|
|
133
|
+
shouldForwardProp: prop => !['control', 'errors', 'rules'].includes(prop)
|
|
134
|
+
})`
|
|
135
|
+
width: 100%;
|
|
136
|
+
border-radius: ${radius.radius4}px;
|
|
137
|
+
outline: none;
|
|
138
|
+
border: 1px solid ${parseColor('neutral400')};
|
|
139
|
+
transition: border-color 0.2s ease;
|
|
140
|
+
background: transparent;
|
|
141
|
+
resize: vertical;
|
|
142
|
+
font-family: inherit;
|
|
143
|
+
font-size: ${fontSize.fontSize14}px;
|
|
144
|
+
line-height: ${lineHeight.lineHeight22}px;
|
|
145
|
+
padding: ${spacing.spacing12}px ${spacing.spacing16}px;
|
|
146
|
+
color: inherit;
|
|
147
|
+
`
|
|
148
|
+
|
|
149
|
+
export const TextAreaWrapper = styled.div`
|
|
150
|
+
position: relative;
|
|
151
|
+
width: 100%;
|
|
152
|
+
border-radius: ${radius.radius4}px;
|
|
153
|
+
background: transparent;
|
|
154
|
+
`
|
|
155
|
+
|
|
156
|
+
export const TextAreaFooter = styled.div`
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: space-between;
|
|
160
|
+
margin-top: -6px;
|
|
161
|
+
`
|
|
162
|
+
|
|
163
|
+
export const CharCount = styled.span<{ $isOver?: boolean }>`
|
|
164
|
+
font-size: ${fontSize.fontSize12}px;
|
|
165
|
+
line-height: ${lineHeight.lineHeight16}px;
|
|
166
|
+
color: ${({ theme, $isOver }) =>
|
|
167
|
+
$isOver
|
|
168
|
+
? parseColor(theme.colors.danger200)
|
|
169
|
+
: parseColor(theme.colors.textMedium)};
|
|
170
|
+
`
|