@@ -11,7 +11,7 @@ import { Icon, type IconName, IconStyle } from '@gitbook/icons';
1111import assertNever from 'assert-never' ;
1212import QuickLRU from 'quick-lru' ;
1313import React from 'react' ;
14- import { create } from 'zustand' ;
14+ import { createStore , useStore } from 'zustand' ;
1515
1616type PageActionType = 'button' | 'dropdown-menu-item' ;
1717
@@ -41,18 +41,13 @@ export function ActionOpenAssistant(props: { assistant: Assistant; type: PageAct
4141type CopiedStore = {
4242 copied : boolean ;
4343 loading : boolean ;
44+ setLoading : ( loading : boolean ) => void ;
45+ copy : ( data : string , opts ?: { onSuccess ?: ( ) => void } ) => void ;
4446} ;
4547
46- // We need to store everything in a store to share the state between every instance of the component.
47- const useCopiedStore = create <
48- CopiedStore & {
49- setLoading : ( loading : boolean ) => void ;
50- copy : ( data : string , opts ?: { onSuccess ?: ( ) => void } ) => void ;
51- }
52- > ( ( set ) => {
48+ const createCopiedStateStore = ( ) => {
5349 let timeoutRef : ReturnType < typeof setTimeout > | null = null ;
54-
55- return {
50+ return createStore < CopiedStore > ( ) ( ( set ) => ( {
5651 copied : false ,
5752 loading : false ,
5853 setLoading : ( loading : boolean ) => set ( { loading } ) ,
@@ -70,13 +65,25 @@ const useCopiedStore = create<
7065 timeoutRef = setTimeout ( ( ) => {
7166 set ( { copied : false } ) ;
7267 onSuccess ?.( ) ;
73-
74- // Reset the timeout ref to avoid multiple timeouts
7568 timeoutRef = null ;
7669 } , 1500 ) ;
7770 } ,
78- } ;
79- } ) ;
71+ } ) ) ;
72+ } ;
73+
74+ const copiedStores = new Map < string , ReturnType < typeof createCopiedStateStore > > ( ) ;
75+
76+ const getOrCreateCopiedStoreByKey = ( storeKey : string ) => {
77+ const existing = copiedStores . get ( storeKey ) ;
78+ if ( existing ) return existing ;
79+ const created = createCopiedStateStore ( ) ;
80+ copiedStores . set ( storeKey , created ) ;
81+ return created ;
82+ } ;
83+
84+ function useCopiedStore ( stateKey : string ) {
85+ return useStore ( getOrCreateCopiedStoreByKey ( stateKey ) ) ;
86+ }
8087
8188/**
8289 * Cache for the markdown versbion of the page.
@@ -96,7 +103,7 @@ export function ActionCopyMarkdown(props: {
96103
97104 const closeDropdown = useDropdownMenuClose ( ) ;
98105
99- const { copied, loading, setLoading, copy } = useCopiedStore ( ) ;
106+ const { copied, loading, setLoading, copy } = useCopiedStore ( 'markdown' ) ;
100107
101108 // Fetch the markdown from the page
102109 const fetchMarkdown = async ( ) => {
@@ -293,14 +300,29 @@ export function CopyToClipboard(props: {
293300 icon : IconName ;
294301} ) {
295302 const { type, data, label, description, icon } = props ;
303+
304+ const closeDropdown = useDropdownMenuClose ( ) ;
305+
306+ const language = useLanguage ( ) ;
307+ const labelKey = label . toLowerCase ( ) . replace ( / \s + / g, '_' ) ;
308+ const { copied, copy } = useCopiedStore ( labelKey ) ;
309+
296310 return (
297311 < PageActionWrapper
298312 type = { type }
299- icon = { icon }
300- label = { label }
313+ icon = { copied ? 'check' : icon }
314+ label = { copied ? tString ( language , 'code_copied' ) : label }
301315 description = { description }
302- onClick = { ( ) => {
303- navigator . clipboard . writeText ( data ) ;
316+ onClick = { ( e ) => {
317+ e . preventDefault ( ) ;
318+
319+ copy ( data , {
320+ onSuccess : ( ) => {
321+ if ( type === 'dropdown-menu-item' ) {
322+ closeDropdown ( ) ;
323+ }
324+ } ,
325+ } ) ;
304326 } }
305327 />
306328 ) ;
0 commit comments