1
1
'use client'
2
2
3
3
import { AnimatePresence , motion } from 'framer-motion'
4
- import { startTransition , useEffect , useOptimistic , useState } from 'react'
5
- import { Square } from './Square '
4
+ import { startTransition , use , useEffect , useOptimistic , useState } from 'react'
5
+ import { ReactionFallback , Square } from './ReactionPrimitives '
6
6
7
7
interface Emoji {
8
8
key : string
@@ -22,7 +22,33 @@ function insert(emojis: Emoji[], delay: number) {
22
22
return [ ...emojis , createEmoji ( delay ) ]
23
23
}
24
24
25
- export function ReactionButton ( props : { onClick : ( ) => void ; emoji : string ; reactions : number } ) {
25
+ function insertMany ( emojis : Emoji [ ] , needed : number ) {
26
+ const stagger = 5_000 / needed
27
+ const nextEmojis = [ ...emojis ]
28
+ for ( let i = 0 ; i < needed ; i ++ ) {
29
+ nextEmojis . push ( createEmoji ( i * stagger ) )
30
+ }
31
+ return nextEmojis
32
+ }
33
+
34
+ export function ReactionButton ( props : {
35
+ onClick : ( ) => void
36
+ data : Promise < {
37
+ emoji : string | null
38
+ reactions : number | null
39
+ } | null >
40
+ } ) {
41
+ const { onClick} = props
42
+ const data = use ( props . data )
43
+
44
+ if ( ! data ?. emoji || typeof data . reactions !== 'number' ) {
45
+ return < ReactionFallback />
46
+ }
47
+
48
+ return < EmojiReactionButton onClick = { onClick } emoji = { data . emoji } reactions = { data . reactions } />
49
+ }
50
+
51
+ function EmojiReactionButton ( props : { onClick : ( ) => void ; emoji : string ; reactions : number } ) {
26
52
const { onClick, emoji, reactions} = props
27
53
const [ initialReactions ] = useState ( reactions )
28
54
@@ -36,22 +62,12 @@ export function ReactionButton(props: {onClick: () => void; emoji: string; react
36
62
useEffect ( ( ) => {
37
63
if ( nextReactions > emojis . length ) {
38
64
const needed = nextReactions - emojis . length
39
- startTransition ( ( ) =>
40
- setEmojis ( ( emojis ) => {
41
- const nextEmojis = [ ...emojis ]
42
- for ( let i = 0 ; i < needed ; i ++ ) {
43
- nextEmojis . push ( createEmoji ( i * 60 ) )
44
- }
45
- return nextEmojis
46
- } ) ,
47
- )
65
+ startTransition ( ( ) => setEmojis ( ( emojis ) => insertMany ( emojis , needed ) ) )
48
66
}
49
67
} , [ nextReactions , emojis . length ] )
50
68
51
69
const pendingEmojis = emojis . filter ( ( { done} ) => ! done )
52
70
53
- // focus-within:ring-(--theme-text) focus-within:ring-offset-(--theme-background) focus-within:ring-2 focus-within:ring-offset-2 focus-within:duration-0
54
-
55
71
return (
56
72
< div className = "bg-(--theme-text)/40 focus-within:ring-(--theme-text) focus-within:ring-offset-(--theme-background) relative aspect-square rounded-lg transition duration-1000 ease-in-out focus-within:ring-2 focus-within:ring-offset-2 focus-within:duration-0" >
57
73
< motion . button
@@ -69,13 +85,7 @@ export function ReactionButton(props: {onClick: () => void; emoji: string; react
69
85
</ motion . button >
70
86
< AnimatePresence >
71
87
{ pendingEmojis . map ( ( { key, delay} ) => (
72
- < FloatingEmoji
73
- key = { key }
74
- _key = { key }
75
- emoji = { props . emoji }
76
- delay = { delay }
77
- setEmojis = { setEmojis }
78
- />
88
+ < FloatingEmoji key = { key } _key = { key } emoji = { emoji } delay = { delay } setEmojis = { setEmojis } />
79
89
) ) }
80
90
</ AnimatePresence >
81
91
</ div >
0 commit comments