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
e8a4fb4d
Commit
e8a4fb4d
authored
Feb 12, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix copy to clipboard component
parent
0a79c372
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
116 additions
and
54 deletions
+116
-54
tooltip.tsx
toolkit/chakra/tooltip.tsx
+1
-0
useClipboard.tsx
toolkit/hooks/useClipboard.tsx
+29
-8
semanticTokens.ts
toolkit/theme/foundations/semanticTokens.ts
+3
-0
TriggerButton.tsx
ui/marketplace/Rating/TriggerButton.tsx
+1
-0
Chakra.tsx
ui/pages/Chakra.tsx
+3
-0
CopyToClipboard.tsx
ui/shared/CopyToClipboard.tsx
+40
-46
Button.tsx
ui/showcases/Button.tsx
+1
-0
Clipboard.tsx
ui/showcases/Clipboard.tsx
+38
-0
No files found.
toolkit/chakra/tooltip.tsx
View file @
e8a4fb4d
...
@@ -72,6 +72,7 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
...
@@ -72,6 +72,7 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
open=
{
open
}
open=
{
open
}
onOpenChange=
{
isMobile
?
undefined
:
handleOpenChange
}
onOpenChange=
{
isMobile
?
undefined
:
handleOpenChange
}
closeOnClick=
{
false
}
closeOnClick=
{
false
}
closeOnPointerDown=
{
false
}
variant=
{
variant
}
variant=
{
variant
}
lazyMount=
{
lazyMount
}
lazyMount=
{
lazyMount
}
unmountOnExit=
{
unmountOnExit
}
unmountOnExit=
{
unmountOnExit
}
...
...
toolkit/hooks/useClipboard.tsx
View file @
e8a4fb4d
import
{
useCopyToClipboard
}
from
'
@uidotdev/usehooks
'
;
import
{
useCopyToClipboard
}
from
'
@uidotdev/usehooks
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
export
default
function
useClipboard
(
text
:
string
,
timeout
?:
number
)
{
import
{
SECOND
}
from
'
lib/consts
'
;
const
timeoutRef
=
React
.
useRef
<
number
|
null
>
(
null
);
import
{
useDisclosure
}
from
'
./useDisclosure
'
;
// NOTE: If you don't need the disclosure and the timeout features, please use the useCopyToClipboard hook directly
export
default
function
useClipboard
(
text
:
string
,
timeout
=
SECOND
)
{
const
flagTimeoutRef
=
React
.
useRef
<
number
|
null
>
(
null
);
const
disclosureTimeoutRef
=
React
.
useRef
<
number
|
null
>
(
null
);
const
[
hasCopied
,
setHasCopied
]
=
React
.
useState
(
false
);
const
[
hasCopied
,
setHasCopied
]
=
React
.
useState
(
false
);
const
[
,
copyToClipboard
]
=
useCopyToClipboard
();
const
[
,
copyToClipboard
]
=
useCopyToClipboard
();
const
{
open
,
onOpenChange
}
=
useDisclosure
();
const
copy
=
React
.
useCallback
(()
=>
{
const
copy
=
React
.
useCallback
(()
=>
{
copyToClipboard
(
text
);
copyToClipboard
(
text
);
setHasCopied
(
true
);
setHasCopied
(
true
);
timeoutRef
.
current
=
window
.
setTimeout
(()
=>
{
setHasCopied
(
false
);
disclosureTimeoutRef
.
current
=
window
.
setTimeout
(()
=>
{
onOpenChange
({
open
:
false
});
},
timeout
);
},
timeout
);
},
[
text
,
copyToClipboard
,
timeout
]);
// We need to wait for the disclosure to close before setting the flag to false
flagTimeoutRef
.
current
=
window
.
setTimeout
(()
=>
{
setHasCopied
(
false
);
},
timeout
+
200
);
},
[
text
,
copyToClipboard
,
timeout
,
onOpenChange
]);
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
return
()
=>
{
return
()
=>
{
if
(
timeoutRef
.
current
)
{
if
(
disclosureTimeoutRef
.
current
)
{
window
.
clearTimeout
(
timeoutRef
.
current
);
window
.
clearTimeout
(
disclosureTimeoutRef
.
current
);
}
if
(
flagTimeoutRef
.
current
)
{
window
.
clearTimeout
(
flagTimeoutRef
.
current
);
}
}
};
};
},
[]);
},
[]);
...
@@ -26,6 +43,10 @@ export default function useClipboard(text: string, timeout?: number) {
...
@@ -26,6 +43,10 @@ export default function useClipboard(text: string, timeout?: number) {
return
{
return
{
hasCopied
,
hasCopied
,
copy
,
copy
,
disclosure
:
{
open
,
onOpenChange
,
},
};
};
},
[
hasCopied
,
copy
]);
},
[
hasCopied
,
copy
,
open
,
onOpenChange
]);
}
}
toolkit/theme/foundations/semanticTokens.ts
View file @
e8a4fb4d
...
@@ -366,8 +366,11 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
...
@@ -366,8 +366,11 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
error
:
{
value
:
'
{colors.red.500}
'
},
error
:
{
value
:
'
{colors.red.500}
'
},
},
},
icon
:
{
icon
:
{
// TODO @tom2drum revise this colors
backTo
:
{
value
:
'
{colors.gray.400}
'
},
backTo
:
{
value
:
'
{colors.gray.400}
'
},
externalLink
:
{
value
:
{
_light
:
'
{colors.gray.400}
'
,
_dark
:
'
{colors.gray.400}
'
}
},
externalLink
:
{
value
:
{
_light
:
'
{colors.gray.400}
'
,
_dark
:
'
{colors.gray.400}
'
}
},
content
:
{
value
:
{
_light
:
'
{colors.gray.500}
'
,
_dark
:
'
{colors.gray.300}
'
}
},
info
:
{
value
:
{
_light
:
'
{colors.gray.400}
'
,
_dark
:
'
{colors.gray.500}
'
}
},
},
},
address
:
{
address
:
{
highlighted
:
{
highlighted
:
{
...
...
ui/marketplace/Rating/TriggerButton.tsx
View file @
e8a4fb4d
...
@@ -31,6 +31,7 @@ const TriggerButton = (
...
@@ -31,6 +31,7 @@ const TriggerButton = (
const
textColor
=
useColorModeValue
(
'
blackAlpha.800
'
,
'
whiteAlpha.800
'
);
const
textColor
=
useColorModeValue
(
'
blackAlpha.800
'
,
'
whiteAlpha.800
'
);
const
onFocusCapture
=
usePreventFocusAfterModalClosing
();
const
onFocusCapture
=
usePreventFocusAfterModalClosing
();
// TODO @tom2drum remove all such occurrences of useDisclosure
// have to implement controlled tooltip on mobile because of the issue - https://github.com/chakra-ui/chakra-ui/issues/7107
// have to implement controlled tooltip on mobile because of the issue - https://github.com/chakra-ui/chakra-ui/issues/7107
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
...
...
ui/pages/Chakra.tsx
View file @
e8a4fb4d
...
@@ -23,6 +23,7 @@ import AlertShowcase from 'ui/showcases/Alert';
...
@@ -23,6 +23,7 @@ import AlertShowcase from 'ui/showcases/Alert';
import
BadgeShowcase
from
'
ui/showcases/Badge
'
;
import
BadgeShowcase
from
'
ui/showcases/Badge
'
;
import
ButtonShowcase
from
'
ui/showcases/Button
'
;
import
ButtonShowcase
from
'
ui/showcases/Button
'
;
import
CheckboxShowcase
from
'
ui/showcases/Checkbox
'
;
import
CheckboxShowcase
from
'
ui/showcases/Checkbox
'
;
import
ClipboardShowcase
from
'
ui/showcases/Clipboard
'
;
import
DialogShowcase
from
'
ui/showcases/Dialog
'
;
import
DialogShowcase
from
'
ui/showcases/Dialog
'
;
import
InputShowcase
from
'
ui/showcases/Input
'
;
import
InputShowcase
from
'
ui/showcases/Input
'
;
import
LinkShowcase
from
'
ui/showcases/Link
'
;
import
LinkShowcase
from
'
ui/showcases/Link
'
;
...
@@ -54,6 +55,7 @@ const ChakraShowcases = () => {
...
@@ -54,6 +55,7 @@ const ChakraShowcases = () => {
<
TabsTrigger
value=
"badge"
>
Badge
</
TabsTrigger
>
<
TabsTrigger
value=
"badge"
>
Badge
</
TabsTrigger
>
<
TabsTrigger
value=
"button"
>
Button
</
TabsTrigger
>
<
TabsTrigger
value=
"button"
>
Button
</
TabsTrigger
>
<
TabsTrigger
value=
"checkbox"
>
Checkbox
</
TabsTrigger
>
<
TabsTrigger
value=
"checkbox"
>
Checkbox
</
TabsTrigger
>
<
TabsTrigger
value=
"clipboard"
>
Clipboard
</
TabsTrigger
>
<
TabsTrigger
value=
"dialog"
>
Dialog
</
TabsTrigger
>
<
TabsTrigger
value=
"dialog"
>
Dialog
</
TabsTrigger
>
<
TabsTrigger
value=
"input"
>
Input
</
TabsTrigger
>
<
TabsTrigger
value=
"input"
>
Input
</
TabsTrigger
>
<
TabsTrigger
value=
"link"
>
Link
</
TabsTrigger
>
<
TabsTrigger
value=
"link"
>
Link
</
TabsTrigger
>
...
@@ -71,6 +73,7 @@ const ChakraShowcases = () => {
...
@@ -71,6 +73,7 @@ const ChakraShowcases = () => {
<
BadgeShowcase
/>
<
BadgeShowcase
/>
<
ButtonShowcase
/>
<
ButtonShowcase
/>
<
CheckboxShowcase
/>
<
CheckboxShowcase
/>
<
ClipboardShowcase
/>
<
DialogShowcase
/>
<
DialogShowcase
/>
<
InputShowcase
/>
<
InputShowcase
/>
<
LinkShowcase
/>
<
LinkShowcase
/>
...
...
ui/shared/CopyToClipboard.tsx
View file @
e8a4fb4d
import
{
chakra
}
from
'
@chakra-ui/react
'
;
import
{
chakra
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
IconButtonProps
}
from
'
toolkit/chakra/icon-button
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
useClipboard
from
'
toolkit/hooks/useClipboard
'
;
import
useClipboard
from
'
toolkit/hooks/useClipboard
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
export
interface
Props
{
export
interface
Props
extends
Omit
<
IconButtonProps
,
'
type
'
|
'
loading
'
>
{
text
:
string
;
text
:
string
;
className
?:
string
;
type
?:
'
link
'
|
'
text
'
|
'
share
'
;
isLoading
?:
boolean
;
isLoading
?:
boolean
;
onClick
?:
(
event
:
React
.
MouseEvent
)
=>
void
;
size
?:
number
;
type
?:
'
link
'
;
icon
?:
IconName
;
// TODO @tom2drum check if we need this
visual
?:
string
;
// TODO @tom2drum check if we need this
colorScheme
?:
string
;
}
}
const
CopyToClipboard
=
({
text
,
className
,
isLoading
,
onClick
,
size
=
5
,
type
,
icon
,
colorScheme
}:
Props
)
=>
{
const
CopyToClipboard
=
(
props
:
Props
)
=>
{
const
{
hasCopied
,
copy
}
=
useClipboard
(
text
,
1000
);
const
{
text
,
type
=
'
text
'
,
isLoading
,
onClick
,
boxSize
=
5
,
...
rest
}
=
props
;
// const [ copiedText, copyToClipboard ] = useCopyToClipboard();
// const [ copied, setCopied ] = useState(false);
// TODO @tom2drum check if we need this
// have to implement controlled tooltip because of the issue - https://github.com/chakra-ui/chakra-ui/issues/7107
const
{
open
,
onOpen
,
onClose
}
=
useDisclosure
();
const
colorProps
=
colorScheme
?
{}
:
{
color
:
{
_light
:
'
gray.400
'
,
_dark
:
'
gray.500
'
}
};
const
iconName
=
icon
||
(
type
===
'
link
'
?
'
link
'
:
'
copy
'
);
// useEffect(() => {
const
{
hasCopied
,
copy
,
disclosure
}
=
useClipboard
(
text
);
// if (hasCopied) {
// setCopied(true);
// } else {
// setCopied(false);
// }
// }, [ hasCopied ]);
const
handleClick
=
React
.
useCallback
((
event
:
React
.
MouseEvent
)
=>
{
const
handleClick
=
React
.
useCallback
((
event
:
React
.
MouseEvent
<
HTMLButtonElement
,
MouseEvent
>
)
=>
{
event
.
stopPropagation
();
event
.
stopPropagation
();
copy
();
copy
();
onClick
?.(
event
);
onClick
?.(
event
);
},
[
onClick
,
copy
]);
},
[
onClick
,
copy
]);
if
(
isLoading
)
{
const
tooltipContent
=
(()
=>
{
return
<
Skeleton
boxSize=
{
size
}
className=
{
className
}
borderRadius=
"sm"
flexShrink=
{
0
}
ml=
{
2
}
display=
"inline-block"
loading
/>;
if
(
hasCopied
)
{
}
return
'
Copied
'
;
}
if
(
type
===
'
link
'
)
{
return
'
Copy link to clipboard
'
;
}
return
'
Copy to clipboard
'
;
})();
const
iconName
=
(()
=>
{
switch
(
type
)
{
case
'
link
'
:
return
'
link
'
;
case
'
share
'
:
return
'
share
'
;
default
:
return
'
copy
'
;
}
})();
return
(
return
(
<
Tooltip
<
Tooltip
content=
{
hasCopied
?
'
Copied
'
:
`Copy${ type === 'link' ? ' link ' : ' ' }to clipboard`
}
content=
{
tooltipContent
}
contentProps=
{
{
contentProps=
{
{
zIndex
:
'
tooltip2
'
}
}
zIndex
:
'
tooltip2
'
,
open=
{
disclosure
.
open
}
}
}
onOpenChange=
{
disclosure
.
onOpenChange
}
// open={ hasCopied }
>
>
<
IconButton
<
IconButton
{
...
colorProps
}
aria
-
label=
"copy"
aria
-
label=
"copy"
boxSize=
{
size
}
boxSize=
{
boxSize
}
colorScheme=
{
colorScheme
}
onClick=
{
handleClick
}
onClick=
{
handleClick
}
className=
{
className
}
// onMouseEnter={ onOpen }
// onMouseLeave={ onClose }
ml=
{
2
}
ml=
{
2
}
borderRadius=
"none"
borderRadius=
"sm"
loading=
{
isLoading
}
color=
"icon.info"
_hover=
{
{
color
:
'
link.primary.hover
'
}
}
{
...
rest
}
>
>
<
IconSvg
name=
{
iconName
}
boxSize=
{
size
}
/>
<
IconSvg
name=
{
iconName
}
boxSize=
"full"
/>
</
IconButton
>
</
IconButton
>
</
Tooltip
>
</
Tooltip
>
);
);
...
...
ui/showcases/Button.tsx
View file @
e8a4fb4d
...
@@ -8,6 +8,7 @@ import { BACKGROUND_DEFAULT } from 'ui/home/HeroBanner';
...
@@ -8,6 +8,7 @@ import { BACKGROUND_DEFAULT } from 'ui/home/HeroBanner';
import
{
Section
,
Container
,
SectionHeader
,
SamplesStack
,
Sample
,
SectionSubHeader
}
from
'
./parts
'
;
import
{
Section
,
Container
,
SectionHeader
,
SamplesStack
,
Sample
,
SectionSubHeader
}
from
'
./parts
'
;
// ?? buttons on marketplace card
const
ButtonShowcase
=
()
=>
{
const
ButtonShowcase
=
()
=>
{
return
(
return
(
<
Container
value=
"button"
>
<
Container
value=
"button"
>
...
...
ui/showcases/Clipboard.tsx
0 → 100644
View file @
e8a4fb4d
import
React
from
'
react
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
{
Section
,
Container
,
SectionHeader
,
SamplesStack
,
Sample
}
from
'
./parts
'
;
const
ClipboardShowcase
=
()
=>
{
return
(
<
Container
value=
"clipboard"
>
<
Section
>
<
SectionHeader
>
Type
</
SectionHeader
>
<
SamplesStack
>
<
Sample
label=
"type: text"
>
<
CopyToClipboard
text=
"Hello, world!"
type=
"text"
/>
</
Sample
>
<
Sample
label=
"type: link"
>
<
CopyToClipboard
text=
"Hello, world!"
type=
"link"
/>
</
Sample
>
<
Sample
label=
"type: share"
>
<
CopyToClipboard
text=
"Hello, world!"
type=
"share"
boxSize=
{
4
}
/>
</
Sample
>
</
SamplesStack
>
</
Section
>
<
Section
>
<
SectionHeader
>
Loading
</
SectionHeader
>
<
SamplesStack
>
<
Sample
label=
"loading: true"
>
<
CopyToClipboard
text=
"Hello, world!"
type=
"text"
isLoading
/>
</
Sample
>
</
SamplesStack
>
</
Section
>
</
Container
>
);
};
export
default
React
.
memo
(
ClipboardShowcase
);
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