@@ -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,44 +41,49 @@ export function ActionOpenAssistant(props: { assistant: Assistant; type: PageAct
4141type CopiedStore = {
4242 copied : boolean ;
4343 loading : boolean ;
44- key ?: string ;
44+ setLoading : ( loading : boolean ) => void ;
45+ copy : ( data : string , opts ?: { onSuccess ?: ( ) => void } ) => void ;
4546} ;
4647
47- // We need to store everything in a store to share the state between every instance of the component.
48- const useCopiedStore = create <
49- CopiedStore & {
50- setLoading : ( loading : boolean ) => void ;
51- copy : ( data : string , opts ?: { onSuccess ?: ( ) => void ; key ?: string } ) => void ;
52- }
53- > ( ( set ) => {
48+ const createCopiedStateStore = ( ) => {
5449 let timeoutRef : ReturnType < typeof setTimeout > | null = null ;
55-
56- return {
50+ return createStore < CopiedStore > ( ) ( ( set ) => ( {
5751 copied : false ,
5852 loading : false ,
59- key : undefined ,
6053 setLoading : ( loading : boolean ) => set ( { loading } ) ,
6154 copy : async ( data , opts ) => {
62- const { onSuccess, key } = opts || { } ;
55+ const { onSuccess } = opts || { } ;
6356
6457 if ( timeoutRef ) {
6558 clearTimeout ( timeoutRef ) ;
6659 }
6760
6861 await navigator . clipboard . writeText ( data ) ;
6962
70- set ( { copied : true , key : key } ) ;
63+ set ( { copied : true } ) ;
7164
7265 timeoutRef = setTimeout ( ( ) => {
7366 set ( { copied : false } ) ;
7467 onSuccess ?.( ) ;
75-
76- // Reset the timeout ref to avoid multiple timeouts
7768 timeoutRef = null ;
7869 } , 1500 ) ;
7970 } ,
80- } ;
81- } ) ;
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+ }
8287
8388/**
8489 * Cache for the markdown versbion of the page.
@@ -98,7 +103,7 @@ export function ActionCopyMarkdown(props: {
98103
99104 const closeDropdown = useDropdownMenuClose ( ) ;
100105
101- const { copied, loading, setLoading, copy, key } = useCopiedStore ( ) ;
106+ const { copied, loading, setLoading, copy } = useCopiedStore ( 'markdown' ) ;
102107
103108 // Fetch the markdown from the page
104109 const fetchMarkdown = async ( ) => {
@@ -120,7 +125,6 @@ export function ActionCopyMarkdown(props: {
120125 }
121126
122127 copy ( markdownCache . get ( markdownPageURL ) || ( await fetchMarkdown ( ) ) , {
123- key : 'markdown' ,
124128 onSuccess : ( ) => {
125129 // We close the dropdown menu if the action is a dropdown menu item and not the default action.
126130 if ( type === 'dropdown-menu-item' && ! isDefaultAction ) {
@@ -133,17 +137,9 @@ export function ActionCopyMarkdown(props: {
133137 return (
134138 < PageActionWrapper
135139 type = { type }
136- icon = { copied && key === 'markdown' ? 'check' : 'copy' }
137- label = {
138- copied && key === 'markdown'
139- ? tString ( language , 'code_copied' )
140- : tString ( language , 'copy_page' )
141- }
142- shortLabel = {
143- copied && key === 'markdown'
144- ? tString ( language , 'code_copied' )
145- : tString ( language , 'code_copy' )
146- }
140+ icon = { copied ? 'check' : 'copy' }
141+ label = { copied ? tString ( language , 'code_copied' ) : tString ( language , 'copy_page' ) }
142+ shortLabel = { copied ? tString ( language , 'code_copied' ) : tString ( language , 'code_copy' ) }
147143 description = { tString ( language , 'copy_page_markdown' ) }
148144 onClick = { onClick }
149145 loading = { loading }
@@ -308,19 +304,18 @@ export function CopyToClipboard(props: {
308304 const closeDropdown = useDropdownMenuClose ( ) ;
309305
310306 const language = useLanguage ( ) ;
311- const { copied, copy, key } = useCopiedStore ( ) ;
307+ const { copied, copy } = useCopiedStore ( 'label' ) ;
312308
313309 return (
314310 < PageActionWrapper
315311 type = { type }
316- icon = { copied && key === label ? 'check' : icon }
317- label = { copied && key === label ? tString ( language , 'code_copied' ) : label }
312+ icon = { copied ? 'check' : icon }
313+ label = { copied ? tString ( language , 'code_copied' ) : label }
318314 description = { description }
319315 onClick = { ( e ) => {
320316 e . preventDefault ( ) ;
321317
322318 copy ( data , {
323- key : label ,
324319 onSuccess : ( ) => {
325320 if ( type === 'dropdown-menu-item' ) {
326321 closeDropdown ( ) ;
0 commit comments