Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
e91e9ae1
Commit
e91e9ae1
authored
Jan 14, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dialog styles and AuthModal first step refactoring
parent
302a4760
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
430 additions
and
128 deletions
+430
-128
close-button.tsx
toolkit/chakra/close-button.tsx
+12
-3
dialog.tsx
toolkit/chakra/dialog.tsx
+20
-5
field.tsx
toolkit/chakra/field.tsx
+2
-1
icon-button.tsx
toolkit/chakra/icon-button.tsx
+2
-0
popover.tsx
toolkit/chakra/popover.tsx
+1
-1
semanticTokens.ts
toolkit/theme/foundations/semanticTokens.ts
+12
-1
button.recipe.ts
toolkit/theme/recipes/button.recipe.ts
+10
-0
close-button.recipe.ts
toolkit/theme/recipes/close-button.recipe.ts
+34
-0
dialog.recipe.ts
toolkit/theme/recipes/dialog.recipe.ts
+211
-0
field.recipe.ts
toolkit/theme/recipes/field.recipe.ts
+3
-2
index.ts
toolkit/theme/recipes/index.ts
+4
-0
textarea.recipe.ts
toolkit/theme/recipes/textarea.recipe.ts
+2
-2
Chakra.tsx
ui/pages/Chakra.tsx
+3
-2
ButtonBackTo.tsx
ui/shared/buttons/ButtonBackTo.tsx
+25
-0
FormFieldEmail.tsx
ui/shared/forms/fields/FormFieldEmail.tsx
+2
-8
FormFieldText.tsx
ui/shared/forms/fields/FormFieldText.tsx
+56
-66
types.ts
ui/shared/forms/fields/types.ts
+5
-13
FormInputPlaceholder.tsx
ui/shared/forms/inputs/FormInputPlaceholder.tsx
+1
-0
getFieldErrorText.ts
ui/shared/forms/utils/getFieldErrorText.ts
+9
-0
AuthModal.tsx
ui/snippets/auth/AuthModal.tsx
+8
-18
AuthModalScreenEmail.tsx
ui/snippets/auth/screens/AuthModalScreenEmail.tsx
+6
-5
UserProfileDesktop.tsx
ui/snippets/user/profile/UserProfileDesktop.tsx
+2
-1
No files found.
toolkit/chakra/close-button.tsx
View file @
e91e9ae1
import
type
{
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
type
{
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
{
IconButton
as
ChakraIconButton
}
from
'
@chakra-ui/react
'
;
import
{
IconButton
as
ChakraIconButton
,
useRecipe
}
from
'
@chakra-ui/react
'
;
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
LuX
}
from
'
react-icons/lu
'
;
import
{
LuX
}
from
'
react-icons/lu
'
;
export
type
CloseButtonProps
=
ButtonProps
;
import
{
recipe
as
closeButtonRecipe
}
from
'
../theme/recipes/close-button.recipe
'
;
export
interface
CloseButtonProps
extends
Omit
<
ButtonProps
,
'
visual
'
|
'
size
'
>
{
visual
?:
'
plain
'
;
size
?:
'
md
'
;
}
export
const
CloseButton
=
React
.
forwardRef
<
export
const
CloseButton
=
React
.
forwardRef
<
HTMLButtonElement
,
HTMLButtonElement
,
CloseButtonProps
CloseButtonProps
>
(
function
CloseButton
(
props
,
ref
)
{
>
(
function
CloseButton
(
props
,
ref
)
{
const
recipe
=
useRecipe
({
recipe
:
closeButtonRecipe
});
const
[
recipeProps
,
restProps
]
=
recipe
.
splitVariantProps
(
props
);
const
styles
=
recipe
(
recipeProps
);
return
(
return
(
<
ChakraIconButton
variant=
"ghost"
aria
-
label=
"Close"
ref=
{
ref
}
{
...
p
rops
}
>
<
ChakraIconButton
aria
-
label=
"Close"
ref=
{
ref
}
css=
{
styles
}
{
...
restP
rops
}
>
{
props
.
children
??
<
LuX
/>
}
{
props
.
children
??
<
LuX
/>
}
</
ChakraIconButton
>
</
ChakraIconButton
>
);
);
...
...
toolkit/chakra/dialog.tsx
View file @
e91e9ae1
...
@@ -39,22 +39,37 @@ export const DialogCloseTrigger = React.forwardRef<
...
@@ -39,22 +39,37 @@ export const DialogCloseTrigger = React.forwardRef<
>
(
function
DialogCloseTrigger
(
props
,
ref
)
{
>
(
function
DialogCloseTrigger
(
props
,
ref
)
{
return
(
return
(
<
ChakraDialog
.
CloseTrigger
<
ChakraDialog
.
CloseTrigger
position=
"absolute"
top=
"2"
insetEnd=
"2"
{
...
props
}
{
...
props
}
asChild
asChild
>
>
<
CloseButton
size=
"sm"
ref=
{
ref
}
>
<
CloseButton
ref=
{
ref
}
>
{
props
.
children
}
{
props
.
children
}
</
CloseButton
>
</
CloseButton
>
</
ChakraDialog
.
CloseTrigger
>
</
ChakraDialog
.
CloseTrigger
>
);
);
});
});
export
interface
DialogHeaderProps
extends
ChakraDialog
.
HeaderProps
{
startElement
?:
React
.
ReactNode
;
}
export
const
DialogHeader
=
React
.
forwardRef
<
HTMLDivElement
,
DialogHeaderProps
>
(
function
DialogHeader
(
props
,
ref
)
{
const
{
startElement
,
...
rest
}
=
props
;
return
(
<
ChakraDialog
.
Header
ref=
{
ref
}
{
...
rest
}
>
{
startElement
}
<
ChakraDialog
.
Title
>
{
props
.
children
}
</
ChakraDialog
.
Title
>
<
DialogCloseTrigger
ml=
"auto"
/>
</
ChakraDialog
.
Header
>
);
});
export
const
DialogRoot
=
ChakraDialog
.
Root
;
export
const
DialogRoot
=
ChakraDialog
.
Root
;
export
const
DialogFooter
=
ChakraDialog
.
Footer
;
export
const
DialogFooter
=
ChakraDialog
.
Footer
;
export
const
DialogHeader
=
ChakraDialog
.
Header
;
export
const
DialogBody
=
ChakraDialog
.
Body
;
export
const
DialogBody
=
ChakraDialog
.
Body
;
export
const
DialogBackdrop
=
ChakraDialog
.
Backdrop
;
export
const
DialogBackdrop
=
ChakraDialog
.
Backdrop
;
export
const
DialogTitle
=
ChakraDialog
.
Title
;
export
const
DialogTitle
=
ChakraDialog
.
Title
;
...
...
toolkit/chakra/field.tsx
View file @
e91e9ae1
...
@@ -25,12 +25,13 @@ export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
...
@@ -25,12 +25,13 @@ export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
placeholder
:
'
'
,
placeholder
:
'
'
,
size
:
props
.
size
,
size
:
props
.
size
,
floating
:
props
.
floating
,
floating
:
props
.
floating
,
bgColor
:
rest
.
bgColor
,
});
});
return
(
return
(
<
ChakraField
.
Root
pos=
"relative"
w=
"full"
ref=
{
ref
}
{
...
rest
}
>
<
ChakraField
.
Root
pos=
"relative"
w=
"full"
ref=
{
ref
}
{
...
rest
}
>
{
clonedChild
}
{
clonedChild
}
<
ChakraField
.
Label
>
<
ChakraField
.
Label
bgColor=
{
rest
.
bgColor
}
>
{
label
}
{
label
}
<
ChakraField
.
RequiredIndicator
fallback=
{
optionalText
}
/>
<
ChakraField
.
RequiredIndicator
fallback=
{
optionalText
}
/>
{
errorText
&&
(
{
errorText
&&
(
...
...
toolkit/chakra/icon-button.tsx
View file @
e91e9ae1
...
@@ -12,8 +12,10 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
...
@@ -12,8 +12,10 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
py=
"0"
py=
"0"
height=
"auto"
height=
"auto"
minW=
"auto"
minW=
"auto"
flexShrink=
"0"
ref=
{
ref
}
ref=
{
ref
}
{
...
props
}
{
...
props
}
visual=
{
props
.
visual
??
'
plain
'
}
/>
/>
);
);
},
},
...
...
toolkit/chakra/popover.tsx
View file @
e91e9ae1
...
@@ -46,7 +46,7 @@ export const PopoverCloseTrigger = React.forwardRef<
...
@@ -46,7 +46,7 @@ export const PopoverCloseTrigger = React.forwardRef<
asChild
asChild
ref=
{
ref
}
ref=
{
ref
}
>
>
<
CloseButton
size=
"sm"
/>
<
CloseButton
/>
</
ChakraPopover
.
CloseTrigger
>
</
ChakraPopover
.
CloseTrigger
>
);
);
});
});
...
...
toolkit/theme/foundations/semanticTokens.ts
View file @
e91e9ae1
...
@@ -140,7 +140,7 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
...
@@ -140,7 +140,7 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
},
},
input
:
{
input
:
{
fg
:
{
fg
:
{
DEFAULT
:
{
value
:
{
_light
:
'
{colors.
blue
.800}
'
,
_dark
:
'
{colors.gray.50}
'
}
},
DEFAULT
:
{
value
:
{
_light
:
'
{colors.
gray
.800}
'
,
_dark
:
'
{colors.gray.50}
'
}
},
error
:
{
value
:
'
{colors.text.error}
'
},
error
:
{
value
:
'
{colors.text.error}
'
},
},
},
bg
:
{
bg
:
{
...
@@ -163,6 +163,14 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
...
@@ -163,6 +163,14 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
error
:
{
value
:
'
{colors.red.500}
'
},
error
:
{
value
:
'
{colors.red.500}
'
},
},
},
},
},
dialog
:
{
bg
:
{
DEFAULT
:
{
value
:
{
_light
:
'
{colors.white}
'
,
_dark
:
'
{colors.gray.900}
'
}
},
},
fg
:
{
DEFAULT
:
{
value
:
{
_light
:
'
{colors.blackAlpha.800}
'
,
_dark
:
'
{colors.whiteAlpha.800}
'
}
},
},
},
text
:
{
text
:
{
primary
:
{
value
:
{
_light
:
'
{colors.blackAlpha.800}
'
,
_dark
:
'
{colors.whiteAlpha.800}
'
}
},
primary
:
{
value
:
{
_light
:
'
{colors.blackAlpha.800}
'
,
_dark
:
'
{colors.whiteAlpha.800}
'
}
},
secondary
:
{
value
:
{
_light
:
'
{colors.gray.500}
'
,
_dark
:
'
{colors.gray.400}
'
}
},
secondary
:
{
value
:
{
_light
:
'
{colors.gray.500}
'
,
_dark
:
'
{colors.gray.400}
'
}
},
...
@@ -172,6 +180,9 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
...
@@ -172,6 +180,9 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
divider
:
{
value
:
{
_light
:
'
{colors.blackAlpha.200}
'
,
_dark
:
'
{colors.whiteAlpha.200}
'
}
},
divider
:
{
value
:
{
_light
:
'
{colors.blackAlpha.200}
'
,
_dark
:
'
{colors.whiteAlpha.200}
'
}
},
error
:
{
value
:
'
{colors.red.500}
'
},
error
:
{
value
:
'
{colors.red.500}
'
},
},
},
icon
:
{
backTo
:
{
value
:
'
{colors.gray.400}
'
},
},
global
:
{
global
:
{
body
:
{
body
:
{
bg
:
{
value
:
{
_light
:
'
{colors.white}
'
,
_dark
:
'
{colors.black}
'
}
},
bg
:
{
value
:
{
_light
:
'
{colors.white}
'
,
_dark
:
'
{colors.black}
'
}
},
...
...
toolkit/theme/recipes/button.recipe.ts
View file @
e91e9ae1
...
@@ -105,6 +105,16 @@ export const recipe = defineRecipe({
...
@@ -105,6 +105,16 @@ export const recipe = defineRecipe({
bg
:
'
transparent
'
,
bg
:
'
transparent
'
,
},
},
},
},
link
:
{
bg
:
'
transparent
'
,
color
:
'
link.primary
'
,
border
:
'
none
'
,
fontWeight
:
'
400
'
,
_hover
:
{
bg
:
'
transparent
'
,
color
:
'
link.primary.hovered
'
,
},
},
},
},
size
:
{
size
:
{
xs
:
{
px
:
2
,
h
:
6
,
fontSize
:
'
12px
'
},
xs
:
{
px
:
2
,
h
:
6
,
fontSize
:
'
12px
'
},
...
...
toolkit/theme/recipes/close-button.recipe.ts
0 → 100644
View file @
e91e9ae1
import
{
defineRecipe
}
from
'
@chakra-ui/react
'
;
export
const
recipe
=
defineRecipe
({
base
:
{
display
:
'
flex
'
,
gap
:
0
,
borderRadius
:
'
sm
'
,
overflow
:
'
hidden
'
,
_disabled
:
{
opacity
:
0.2
,
},
minWidth
:
'
auto
'
,
},
variants
:
{
visual
:
{
plain
:
{
bg
:
'
transparent
'
,
color
:
'
icon.backTo
'
,
border
:
'
none
'
,
_hover
:
{
bg
:
'
transparent
'
,
color
:
'
link.primary.hover
'
,
},
},
},
size
:
{
md
:
{
boxSize
:
6
,
'
& svg
'
:
{
boxSize
:
5
}
},
},
},
defaultVariants
:
{
size
:
'
md
'
,
visual
:
'
plain
'
,
},
});
toolkit/theme/recipes/dialog.recipe.ts
0 → 100644
View file @
e91e9ae1
import
{
defineSlotRecipe
}
from
'
@chakra-ui/react
'
;
export
const
recipe
=
defineSlotRecipe
({
slots
:
[
'
backdrop
'
,
'
positioner
'
,
'
content
'
,
'
header
'
,
'
body
'
,
'
footer
'
,
'
title
'
,
'
description
'
],
base
:
{
backdrop
:
{
bg
:
'
blackAlpha.500
'
,
pos
:
'
fixed
'
,
left
:
0
,
top
:
0
,
w
:
'
100vw
'
,
h
:
'
100dvh
'
,
zIndex
:
'
modal
'
,
_open
:
{
animationName
:
'
fade-in
'
,
animationDuration
:
'
slow
'
,
},
_closed
:
{
animationName
:
'
fade-out
'
,
animationDuration
:
'
moderate
'
,
},
},
positioner
:
{
display
:
'
flex
'
,
width
:
'
100vw
'
,
height
:
'
100dvh
'
,
position
:
'
fixed
'
,
left
:
0
,
top
:
0
,
'
--dialog-z-index
'
:
'
zIndex.modal
'
,
zIndex
:
'
calc(var(--dialog-z-index) + var(--layer-index, 0))
'
,
justifyContent
:
'
center
'
,
overscrollBehaviorY
:
'
none
'
,
},
content
:
{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
position
:
'
relative
'
,
width
:
'
100%
'
,
padding
:
6
,
outline
:
0
,
textStyle
:
'
md
'
,
my
:
'
var(--dialog-margin, var(--dialog-base-margin))
'
,
'
--dialog-z-index
'
:
'
zIndex.modal
'
,
zIndex
:
'
calc(var(--dialog-z-index) + var(--layer-index, 0))
'
,
bg
:
'
dialog.bg
'
,
color
:
'
dialog.fg
'
,
boxShadow
:
'
lg
'
,
_open
:
{
animationDuration
:
'
moderate
'
,
},
_closed
:
{
animationDuration
:
'
faster
'
,
},
},
header
:
{
flex
:
0
,
p
:
0
,
mb
:
2
,
display
:
'
flex
'
,
alignItems
:
'
center
'
,
columnGap
:
2
,
},
body
:
{
flex
:
'
1
'
,
p
:
0
,
},
footer
:
{
display
:
'
flex
'
,
alignItems
:
'
center
'
,
justifyContent
:
'
flex-end
'
,
gap
:
'
3
'
,
px
:
'
6
'
,
pt
:
'
2
'
,
pb
:
'
4
'
,
},
title
:
{
textStyle
:
'
heading.md
'
,
fontWeight
:
'
500
'
,
},
description
:
{
color
:
'
dialog.fg
'
,
},
},
variants
:
{
placement
:
{
center
:
{
positioner
:
{
alignItems
:
'
center
'
,
},
content
:
{
'
--dialog-base-margin
'
:
'
auto
'
,
mx
:
'
auto
'
,
},
},
top
:
{
positioner
:
{
alignItems
:
'
flex-start
'
,
},
content
:
{
'
--dialog-base-margin
'
:
'
spacing.16
'
,
mx
:
'
auto
'
,
},
},
bottom
:
{
positioner
:
{
alignItems
:
'
flex-end
'
,
},
content
:
{
'
--dialog-base-margin
'
:
'
spacing.16
'
,
mx
:
'
auto
'
,
},
},
},
scrollBehavior
:
{
inside
:
{
positioner
:
{
overflow
:
'
hidden
'
,
},
content
:
{
minH
:
'
auto
'
,
maxH
:
'
calc(100% - 7.5rem)
'
,
borderRadius
:
'
xl
'
,
},
body
:
{
overflow
:
'
auto
'
,
},
},
outside
:
{
positioner
:
{
overflow
:
'
auto
'
,
pointerEvents
:
'
auto
'
,
},
},
},
size
:
{
sm
:
{
content
:
{
maxW
:
'
400px
'
,
},
},
md
:
{
content
:
{
maxW
:
'
640px
'
,
},
},
cover
:
{
positioner
:
{
padding
:
'
10
'
,
},
content
:
{
width
:
'
100%
'
,
height
:
'
100%
'
,
'
--dialog-margin
'
:
'
0
'
,
},
},
full
:
{
content
:
{
maxW
:
'
100vw
'
,
minH
:
'
100vh
'
,
'
--dialog-margin
'
:
'
0
'
,
borderRadius
:
'
0
'
,
},
},
},
motionPreset
:
{
scale
:
{
content
:
{
_open
:
{
animationName
:
'
scale-in, fade-in
'
},
_closed
:
{
animationName
:
'
scale-out, fade-out
'
},
},
},
'
slide-in-bottom
'
:
{
content
:
{
_open
:
{
animationName
:
'
slide-from-bottom, fade-in
'
},
_closed
:
{
animationName
:
'
slide-to-bottom, fade-out
'
},
},
},
'
slide-in-top
'
:
{
content
:
{
_open
:
{
animationName
:
'
slide-from-top, fade-in
'
},
_closed
:
{
animationName
:
'
slide-to-top, fade-out
'
},
},
},
'
slide-in-left
'
:
{
content
:
{
_open
:
{
animationName
:
'
slide-from-left, fade-in
'
},
_closed
:
{
animationName
:
'
slide-to-left, fade-out
'
},
},
},
'
slide-in-right
'
:
{
content
:
{
_open
:
{
animationName
:
'
slide-from-right, fade-in
'
},
_closed
:
{
animationName
:
'
slide-to-right, fade-out
'
},
},
},
none
:
{},
},
},
defaultVariants
:
{
size
:
'
md
'
,
scrollBehavior
:
'
inside
'
,
placement
:
'
center
'
,
motionPreset
:
'
scale
'
,
},
});
toolkit/theme/recipes/field.recipe.ts
View file @
e91e9ae1
...
@@ -51,6 +51,7 @@ export const recipe = defineSlotRecipe({
...
@@ -51,6 +51,7 @@ export const recipe = defineSlotRecipe({
bg
:
'
bg
'
,
bg
:
'
bg
'
,
top
:
'
2px
'
,
top
:
'
2px
'
,
left
:
'
2px
'
,
left
:
'
2px
'
,
color
:
'
gray.500
'
,
width
:
'
calc(100% - 4px)
'
,
width
:
'
calc(100% - 4px)
'
,
borderRadius
:
'
base
'
,
borderRadius
:
'
base
'
,
pointerEvents
:
'
none
'
,
pointerEvents
:
'
none
'
,
...
@@ -83,7 +84,7 @@ export const recipe = defineSlotRecipe({
...
@@ -83,7 +84,7 @@ export const recipe = defineSlotRecipe({
},
},
},
},
// special size for textarea
// special size for textarea
xxl
:
{
'
2xl
'
:
{
label
:
{
label
:
{
fontSize
:
'
md
'
,
fontSize
:
'
md
'
,
},
},
...
@@ -136,7 +137,7 @@ export const recipe = defineSlotRecipe({
...
@@ -136,7 +137,7 @@ export const recipe = defineSlotRecipe({
},
},
},
},
{
{
size
:
'
x
xl
'
,
size
:
'
2
xl
'
,
floating
:
true
,
floating
:
true
,
css
:
{
css
:
{
label
:
{
label
:
{
...
...
toolkit/theme/recipes/index.ts
View file @
e91e9ae1
import
{
recipe
as
alert
}
from
'
./alert.recipe
'
;
import
{
recipe
as
alert
}
from
'
./alert.recipe
'
;
import
{
recipe
as
button
}
from
'
./button.recipe
'
;
import
{
recipe
as
button
}
from
'
./button.recipe
'
;
import
{
recipe
as
closeButton
}
from
'
./close-button.recipe
'
;
import
{
recipe
as
dialog
}
from
'
./dialog.recipe
'
;
import
{
recipe
as
field
}
from
'
./field.recipe
'
;
import
{
recipe
as
field
}
from
'
./field.recipe
'
;
import
{
recipe
as
input
}
from
'
./input.recipe
'
;
import
{
recipe
as
input
}
from
'
./input.recipe
'
;
import
{
recipe
as
link
}
from
'
./link.recipe
'
;
import
{
recipe
as
link
}
from
'
./link.recipe
'
;
...
@@ -14,6 +16,7 @@ import { recipe as tooltip } from './tooltip.recipe';
...
@@ -14,6 +16,7 @@ import { recipe as tooltip } from './tooltip.recipe';
export
const
recipes
=
{
export
const
recipes
=
{
button
,
button
,
closeButton
,
input
,
input
,
link
,
link
,
skeleton
,
skeleton
,
...
@@ -22,6 +25,7 @@ export const recipes = {
...
@@ -22,6 +25,7 @@ export const recipes = {
export
const
slotRecipes
=
{
export
const
slotRecipes
=
{
alert
,
alert
,
dialog
,
field
,
field
,
popover
,
popover
,
progressCircle
,
progressCircle
,
...
...
toolkit/theme/recipes/textarea.recipe.ts
View file @
e91e9ae1
...
@@ -20,7 +20,7 @@ export const recipe = defineRecipe({
...
@@ -20,7 +20,7 @@ export const recipe = defineRecipe({
},
},
variants
:
{
variants
:
{
size
:
{
size
:
{
xxl
:
{
'
2xl
'
:
{
textStyle
:
'
md
'
,
textStyle
:
'
md
'
,
px
:
'
6
'
,
px
:
'
6
'
,
py
:
'
4
'
,
py
:
'
4
'
,
...
@@ -76,7 +76,7 @@ export const recipe = defineRecipe({
...
@@ -76,7 +76,7 @@ export const recipe = defineRecipe({
},
},
defaultVariants
:
{
defaultVariants
:
{
size
:
'
x
xl
'
,
size
:
'
2
xl
'
,
variant
:
'
outline
'
,
variant
:
'
outline
'
,
},
},
});
});
ui/pages/Chakra.tsx
View file @
e91e9ae1
...
@@ -40,6 +40,7 @@ const ChakraShowcases = () => {
...
@@ -40,6 +40,7 @@ const ChakraShowcases = () => {
<
Button
visual=
"header"
>
Header
</
Button
>
<
Button
visual=
"header"
>
Header
</
Button
>
<
Button
visual=
"header"
selected
>
Header selected
</
Button
>
<
Button
visual=
"header"
selected
>
Header selected
</
Button
>
<
Button
visual=
"header"
selected
highlighted
>
Header highlighted
</
Button
>
<
Button
visual=
"header"
selected
highlighted
>
Header highlighted
</
Button
>
<
Button
visual=
"link"
>
Link
</
Button
>
</
HStack
>
</
HStack
>
</
section
>
</
section
>
...
@@ -102,10 +103,10 @@ const ChakraShowcases = () => {
...
@@ -102,10 +103,10 @@ const ChakraShowcases = () => {
<
section
>
<
section
>
<
Heading
textStyle=
"heading.md"
mb=
{
2
}
>
Textarea
</
Heading
>
<
Heading
textStyle=
"heading.md"
mb=
{
2
}
>
Textarea
</
Heading
>
<
HStack
gap=
{
4
}
>
<
HStack
gap=
{
4
}
>
<
Field
label=
"Description"
required
floating
size=
"
x
xl"
w=
"400px"
>
<
Field
label=
"Description"
required
floating
size=
"
2
xl"
w=
"400px"
>
<
Textarea
/>
<
Textarea
/>
</
Field
>
</
Field
>
<
Field
label=
"Description"
required
floating
size=
"
x
xl"
w=
"400px"
>
<
Field
label=
"Description"
required
floating
size=
"
2
xl"
w=
"400px"
>
<
Textarea
value=
{
TEXT
}
/>
<
Textarea
value=
{
TEXT
}
/>
</
Field
>
</
Field
>
</
HStack
>
</
HStack
>
...
...
ui/shared/buttons/ButtonBackTo.tsx
0 → 100644
View file @
e91e9ae1
import
React
from
'
react
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
interface
Props
{
onClick
:
()
=>
void
;
}
const
ButtonBackTo
=
({
onClick
}:
Props
)
=>
{
return
(
<
IconButton
>
<
IconSvg
name=
"arrows/east"
boxSize=
{
6
}
transform=
"rotate(180deg)"
color=
"icon.backTo"
_hover=
{
{
color
:
'
link.primary.hover
'
}
}
onClick=
{
onClick
}
/>
</
IconButton
>
);
};
export
default
React
.
memo
(
ButtonBackTo
);
ui/shared/forms/fields/FormFieldEmail.tsx
View file @
e91e9ae1
import
type
{
ChakraProps
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
FieldValues
,
Path
}
from
'
react-hook-form
'
;
import
type
{
FieldValues
}
from
'
react-hook-form
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
type
{
PartialBy
}
from
'
types/utils
'
;
import
type
{
PartialBy
}
from
'
types/utils
'
;
...
@@ -28,9 +27,4 @@ const FormFieldEmail = <FormFields extends FieldValues>(
...
@@ -28,9 +27,4 @@ const FormFieldEmail = <FormFields extends FieldValues>(
);
);
}
;
}
;
export type WrappedComponent =
<
export default React.memo(FormFieldEmail) as typeof FormFieldEmail;
FormFields
extends
FieldValues
,
Name
extends
Path
<
FormFields
>
= Path
<
FormFields
>
,
>
(props: PartialBy
<
FormFieldPropsBase
<
FormFields
,
Name
>
, 'placeholder'
>
&
ChakraProps) =
>
React.JSX.Element;
export default React.memo(FormFieldEmail) as WrappedComponent;
ui/shared/forms/fields/FormFieldText.tsx
View file @
e91e9ae1
import
type
{
ChakraProps
}
from
'
@chakra-ui/react
'
;
import
type
{
HTMLChakraProps
}
from
'
@chakra-ui/react
'
;
import
{
FormControl
,
Input
,
InputGroup
,
InputRightElement
,
Textarea
,
chakra
,
shouldForwardProp
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
FieldValues
,
Path
}
from
'
react-hook-form
'
;
import
type
{
FieldValues
,
Path
}
from
'
react-hook-form
'
;
import
{
useController
,
useFormContext
}
from
'
react-hook-form
'
;
import
{
useController
,
useFormContext
}
from
'
react-hook-form
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
FormInputPlaceholder
from
'
../inputs/FormInputPlaceholder
'
;
import
{
Field
}
from
'
toolkit/chakra/field
'
;
import
{
Input
}
from
'
toolkit/chakra/input
'
;
import
{
Textarea
}
from
'
toolkit/chakra/textarea
'
;
import
getFieldErrorText
from
'
../utils/getFieldErrorText
'
;
interface
Props
<
interface
Props
<
FormFields
extends
FieldValues
,
FormFields
extends
FieldValues
,
...
@@ -21,95 +24,82 @@ const FormFieldText = <
...
@@ -21,95 +24,82 @@ const FormFieldText = <
>
(
{
>
(
{
name
,
name
,
placeholder
,
placeholder
,
isReadOnly
,
isRequired
,
rules
,
rules
,
onBlur
,
onBlur
,
type
=
'
text
'
,
rightElement
,
rightElement
,
inputProps
,
asComponent
,
asComponent
,
max
,
size
=
'
xl
'
,
disabled
,
className
,
...
restProps
size
=
'
md
'
,
bgColor
,
minH
,
maxH
,
}
: Props
<
FormFields
,
Name
>
) =
>
{
}
: Props
<
FormFields
,
Name
>
) =
>
{
const
{
control
}
=
useFormContext
<
FormFields
>
();
const
{
control
}
=
useFormContext
<
FormFields
>
();
const
{
field
,
fieldState
,
formState
}
=
useController
<
FormFields
,
typeof
name
>
({
const
{
field
,
fieldState
,
formState
}
=
useController
<
FormFields
,
typeof
name
>
({
control
,
control
,
name
,
name
,
rules
:
{
...
rules
,
required
:
isR
equired
},
rules
:
{
...
rules
,
required
:
restProps
.
r
equired
},
});
});
const
isDisabled
=
formState
.
isSubmitting
;
const
handleBlur
=
React
.
useCallback
(()
=>
{
const
handleBlur
=
React
.
useCallback
(()
=>
{
field
.
onBlur
();
field
.
onBlur
();
onBlur
?.();
onBlur
?.();
},
[
field
,
onBlur
]);
},
[
field
,
onBlur
]);
const
Component
=
asComponent
===
'
Textarea
'
?
Textarea
:
Input
;
const
input
=
asComponent
===
'
Textarea
'
?
(
const
input
=
(
<
Textarea
<
Component
{
...
field
}
{
...
field
}
autoComplete=
"off"
{
...
inputProps
as
HTMLChakraProps
<'
textarea
'
>
}
onBlur=
{
handleBlur
}
onBlur=
{
handleBlur
}
isInvalid=
{
Boolean
(
fieldState
.
error
)
}
/
>
isDisabled=
{
isDisabled
}
) : (
isReadOnly=
{
isReadOnly
}
<
Input
{
...
field
}
autoComplete=
"off"
autoComplete=
"off"
type=
{
type
}
{
...
inputProps
as
HTMLChakraProps
<'
input
'
>
}
placeholder=
" "
onBlur=
{
handleBlur
}
max=
{
max
}
size=
{
size
}
bgColor=
{
bgColor
}
minH=
{
minH
}
maxH=
{
maxH
}
/
>
/
>
);
);
const
inputPlaceholder
=
size
!==
'
xs
'
&&
<
FormInputPlaceholder
text=
{
placeholder
}
error=
{
fieldState
.
error
}
/>;
return (
return (
<
F
ormControl
<
F
ield
className=
{
className
}
label=
{
placeholder
}
variant=
"floating"
errorText=
{
getFieldErrorText
(
fieldState
.
error
)
}
i
sDisabled=
{
isDisabled
}
i
nvalid=
{
Boolean
(
fieldState
.
error
)
}
isRequired=
{
isRequir
ed
}
disabled=
{
formState
.
isSubmitting
||
disabl
ed
}
size=
{
size
}
size=
{
size
}
bgColor=
{
bgColor
}
floating
{
...
restProps
}
>
>
{
rightElement
?
(
{
input
}
<
InputGroup
>
</
Field
>
{
input
}
{
inputPlaceholder
}
<
InputRightElement
h=
"100%"
>
{
rightElement
({
field
})
}
</
InputRightElement
>
</
InputGroup
>
)
:
(
<>
{
input
}
{
inputPlaceholder
}
</>
)
}
</
FormControl
>
);
);
}
;
const WrappedFormFieldText = chakra(FormFieldText,
{
shouldForwardProp
:
(
prop
)
=>
{
const
isChakraProp
=
!
shouldForwardProp
(
prop
);
if
(
isChakraProp
&&
!
[
'
bgColor
'
,
'
size
'
,
'
minH
'
,
'
maxH
'
].
includes
(
prop
))
{
return
false
;
}
return
true
;
// TODO @tom2drum add input group
},
}
);
export type WrappedComponent =
<
// return (
FormFields
extends
FieldValues
,
//
<
FormControl
Name
extends
Path
<
FormFields
>
= Path
<
FormFields
>
,
// className=
{
className
}
>
(props: Props
<
FormFields
,
Name
>
&
ChakraProps) =
>
React.JSX.Element;
// variant="floating"
// isDisabled=
{
isDisabled
}
// isRequired=
{
isRequired
}
// size=
{
size
}
// bgColor=
{
bgColor
}
// >
//
{
rightElement
?
(
// <InputGroup>
//
{
input
}
//
{
inputPlaceholder
}
// <InputRightElement h="100%">
{
rightElement
({
field
})
}
</
InputRightElement
>
//
</
InputGroup
>
// ) : (
//
<>
//
{
input
}
//
{
inputPlaceholder
}
//
</>
// ) }
//
</
FormControl
>
// );
}
;
export default React.memo(
WrappedFormFieldText) as WrappedComponen
t;
export default React.memo(
FormFieldText) as typeof FormFieldTex
t;
ui/shared/forms/fields/types.ts
View file @
e91e9ae1
import
type
{
FormControl
Props
}
from
'
@chakra-ui/react
'
;
import
type
{
HTMLChakra
Props
}
from
'
@chakra-ui/react
'
;
import
type
React
from
'
react
'
;
import
type
React
from
'
react
'
;
import
type
{
ControllerRenderProps
,
FieldValues
,
Path
,
RegisterOptions
}
from
'
react-hook-form
'
;
import
type
{
ControllerRenderProps
,
FieldValues
,
Path
,
RegisterOptions
}
from
'
react-hook-form
'
;
import
type
{
FieldProps
}
from
'
toolkit/chakra/field
'
;
export
interface
FormFieldPropsBase
<
export
interface
FormFieldPropsBase
<
FormFields
extends
FieldValues
,
FormFields
extends
FieldValues
,
Name
extends
Path
<
FormFields
>
=
Path
<
FormFields
>
,
Name
extends
Path
<
FormFields
>
=
Path
<
FormFields
>
,
>
{
>
extends
Omit
<
FieldProps
,
'
children
'
>
{
name
:
Name
;
name
:
Name
;
placeholder
:
string
;
placeholder
:
string
;
isReadOnly
?:
boolean
;
isRequired
?:
boolean
;
rules
?:
Omit
<
RegisterOptions
<
FormFields
,
Name
>
,
'
valueAsNumber
'
|
'
valueAsDate
'
|
'
setValueAs
'
|
'
disabled
'
>
;
rules
?:
Omit
<
RegisterOptions
<
FormFields
,
Name
>
,
'
valueAsNumber
'
|
'
valueAsDate
'
|
'
setValueAs
'
|
'
disabled
'
>
;
onBlur
?:
()
=>
void
;
onBlur
?:
()
=>
void
;
onChange
?:
()
=>
void
;
onChange
?:
()
=>
void
;
type
?:
HTMLInputElement
[
'
type
'
];
rightElement
?:
({
field
}:
{
field
:
ControllerRenderProps
<
FormFields
,
Name
>
})
=>
React
.
ReactNode
;
rightElement
?:
({
field
}:
{
field
:
ControllerRenderProps
<
FormFields
,
Name
>
})
=>
React
.
ReactNode
;
max
?:
HTMLInputElement
[
'
max
'
];
inputProps
?:
HTMLChakraProps
<
'
input
'
|
'
textarea
'
>
;
// styles
size
?:
FormControlProps
[
'
size
'
];
bgColor
?:
FormControlProps
[
'
bgColor
'
];
maxH
?:
FormControlProps
[
'
maxH
'
];
minH
?:
FormControlProps
[
'
minH
'
];
className
?:
string
;
}
}
ui/shared/forms/inputs/FormInputPlaceholder.tsx
View file @
e91e9ae1
...
@@ -9,6 +9,7 @@ interface Props {
...
@@ -9,6 +9,7 @@ interface Props {
isFancy
?:
boolean
;
isFancy
?:
boolean
;
}
}
// TODO @tom2drum remove this component
const
FormInputPlaceholder
=
({
text
,
icon
,
error
,
isFancy
}:
Props
)
=>
{
const
FormInputPlaceholder
=
({
text
,
icon
,
error
,
isFancy
}:
Props
)
=>
{
let
errorMessage
=
error
?.
message
;
let
errorMessage
=
error
?.
message
;
...
...
ui/shared/forms/utils/getFieldErrorText.ts
0 → 100644
View file @
e91e9ae1
import
type
{
FieldError
}
from
'
react-hook-form
'
;
export
default
function
getFieldErrorText
(
error
:
FieldError
|
undefined
)
{
if
(
!
error
?.
message
&&
error
?.
type
===
'
pattern
'
)
{
return
'
Invalid format
'
;
}
return
error
?.
message
;
}
ui/snippets/auth/AuthModal.tsx
View file @
e91e9ae1
...
@@ -8,8 +8,8 @@ import config from 'configs/app';
...
@@ -8,8 +8,8 @@ import config from 'configs/app';
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
useGetCsrfToken
from
'
lib/hooks/useGetCsrfToken
'
;
import
useGetCsrfToken
from
'
lib/hooks/useGetCsrfToken
'
;
import
*
as
mixpanel
from
'
lib/mixpanel
'
;
import
*
as
mixpanel
from
'
lib/mixpanel
'
;
import
{
DialogBackdrop
,
DialogBody
,
DialogC
loseTrigger
,
DialogC
ontent
,
DialogHeader
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
{
DialogBackdrop
,
DialogBody
,
DialogContent
,
DialogHeader
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
ButtonBackTo
from
'
ui/shared/buttons/ButtonBackTo
'
;
import
AuthModalScreenConnectWallet
from
'
./screens/AuthModalScreenConnectWallet
'
;
import
AuthModalScreenConnectWallet
from
'
./screens/AuthModalScreenConnectWallet
'
;
import
AuthModalScreenEmail
from
'
./screens/AuthModalScreenEmail
'
;
import
AuthModalScreenEmail
from
'
./screens/AuthModalScreenEmail
'
;
...
@@ -96,7 +96,7 @@ const AuthModal = ({ initialScreen, onClose, mixpanelConfig, closeOnError }: Pro
...
@@ -96,7 +96,7 @@ const AuthModal = ({ initialScreen, onClose, mixpanelConfig, closeOnError }: Pro
},
[
isSuccess
,
onClose
]);
},
[
isSuccess
,
onClose
]);
const
onModalOpenChange
=
React
.
useCallback
(({
open
}:
{
open
:
boolean
})
=>
{
const
onModalOpenChange
=
React
.
useCallback
(({
open
}:
{
open
:
boolean
})
=>
{
open
&&
onClose
();
!
open
&&
onClose
();
},
[
onClose
]);
},
[
onClose
]);
const
header
=
(()
=>
{
const
header
=
(()
=>
{
...
@@ -170,23 +170,13 @@ const AuthModal = ({ initialScreen, onClose, mixpanelConfig, closeOnError }: Pro
...
@@ -170,23 +170,13 @@ const AuthModal = ({ initialScreen, onClose, mixpanelConfig, closeOnError }: Pro
return
(
return
(
<
DialogRoot
open
onOpenChange=
{
onModalOpenChange
}
size=
{
{
base
:
'
full
'
,
lg
:
'
sm
'
}
}
>
<
DialogRoot
open
onOpenChange=
{
onModalOpenChange
}
size=
{
{
base
:
'
full
'
,
lg
:
'
sm
'
}
}
>
<
DialogBackdrop
/>
<
DialogBackdrop
/>
<
DialogContent
p=
{
6
}
maxW=
{
{
lg
:
'
400px
'
}
}
>
<
DialogContent
>
<
DialogHeader
fontWeight=
"500"
textStyle=
"h3"
mb=
{
2
}
display=
"flex"
alignItems=
"center"
columnGap=
{
2
}
>
<
DialogHeader
{
steps
.
length
>
1
&&
!
steps
[
steps
.
length
-
1
].
type
.
startsWith
(
'
success
'
)
&&
(
startElement=
{
steps
.
length
>
1
&&
!
steps
[
steps
.
length
-
1
].
type
.
startsWith
(
'
success
'
)
&&
<
ButtonBackTo
onClick=
{
onPrevStep
}
/>
}
<
IconSvg
>
name=
"arrows/east"
boxSize=
{
6
}
transform=
"rotate(180deg)"
color=
"gray.400"
flexShrink=
{
0
}
onClick=
{
onPrevStep
}
cursor=
"pointer"
/>
)
}
{
header
}
{
header
}
</
DialogHeader
>
</
DialogHeader
>
<
DialogCloseTrigger
top=
{
6
}
right=
{
6
}
color=
"gray.400"
/>
<
DialogBody
>
<
DialogBody
mb=
{
0
}
>
{
content
}
{
content
}
</
DialogBody
>
</
DialogBody
>
</
DialogContent
>
</
DialogContent
>
...
...
ui/snippets/auth/screens/AuthModalScreenEmail.tsx
View file @
e91e9ae1
import
{
chakra
,
Button
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
{
FormProvider
,
useForm
}
from
'
react-hook-form
'
;
import
{
FormProvider
,
useForm
}
from
'
react-hook-form
'
;
import
type
{
EmailFormFields
,
Screen
}
from
'
../types
'
;
import
type
{
EmailFormFields
,
Screen
}
from
'
../types
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
getErrorMessage
from
'
lib/errors/getErrorMessage
'
;
import
getErrorMessage
from
'
lib/errors/getErrorMessage
'
;
import
getErrorObjPayload
from
'
lib/errors/getErrorObjPayload
'
;
import
getErrorObjPayload
from
'
lib/errors/getErrorObjPayload
'
;
import
*
as
mixpanel
from
'
lib/mixpanel
'
;
import
*
as
mixpanel
from
'
lib/mixpanel
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
import
FormFieldEmail
from
'
ui/shared/forms/fields/FormFieldEmail
'
;
import
FormFieldEmail
from
'
ui/shared/forms/fields/FormFieldEmail
'
;
import
ReCaptcha
from
'
ui/shared/reCaptcha/ReCaptcha
'
;
import
ReCaptcha
from
'
ui/shared/reCaptcha/ReCaptcha
'
;
import
useReCaptcha
from
'
ui/shared/reCaptcha/useReCaptcha
'
;
import
useReCaptcha
from
'
ui/shared/reCaptcha/useReCaptcha
'
;
...
@@ -79,16 +80,16 @@ const AuthModalScreenEmail = ({ onSubmit, isAuth, mixpanelConfig }: Props) => {
...
@@ -79,16 +80,16 @@ const AuthModalScreenEmail = ({ onSubmit, isAuth, mixpanelConfig }: Props) => {
<
Text
>
Account email, used for transaction notifications from your watchlist.
</
Text
>
<
Text
>
Account email, used for transaction notifications from your watchlist.
</
Text
>
<
FormFieldEmail
<
EmailFormFields
>
<
FormFieldEmail
<
EmailFormFields
>
name="email"
name="email"
isR
equired
r
equired
placeholder="Email"
placeholder="Email"
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
mt=
{
6
}
mt=
{
6
}
/
>
/
>
<
Button
<
Button
mt=
{
6
}
mt=
{
6
}
type=
"submit"
type=
"submit"
disabled=
{
formApi
.
formState
.
isSubmitting
}
disabled=
{
formApi
.
formState
.
isSubmitting
}
isL
oading=
{
formApi
.
formState
.
isSubmitting
}
l
oading=
{
formApi
.
formState
.
isSubmitting
}
loadingText=
"Send a code"
loadingText=
"Send a code"
>
>
Send a code
Send a code
...
...
ui/snippets/user/profile/UserProfileDesktop.tsx
View file @
e91e9ae1
import
{
useDisclosure
,
type
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
{
type
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
...
@@ -8,6 +8,7 @@ import config from 'configs/app';
...
@@ -8,6 +8,7 @@ import config from 'configs/app';
import
*
as
mixpanel
from
'
lib/mixpanel
'
;
import
*
as
mixpanel
from
'
lib/mixpanel
'
;
import
useAccount
from
'
lib/web3/useAccount
'
;
import
useAccount
from
'
lib/web3/useAccount
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
,
PopoverTrigger
}
from
'
toolkit/chakra/popover
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
,
PopoverTrigger
}
from
'
toolkit/chakra/popover
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
AuthModal
from
'
ui/snippets/auth/AuthModal
'
;
import
AuthModal
from
'
ui/snippets/auth/AuthModal
'
;
import
useProfileQuery
from
'
ui/snippets/auth/useProfileQuery
'
;
import
useProfileQuery
from
'
ui/snippets/auth/useProfileQuery
'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment