@@ -9,11 +9,13 @@ import NumberFlowLite, {
99} from "number-flow/lite"
1010import {
1111 type Accessor ,
12+ createComputed ,
1213 createContext ,
1314 createEffect ,
1415 createMemo ,
1516 createSignal ,
1617 type FlowProps ,
18+ on ,
1719 onCleanup ,
1820 onMount ,
1921 splitProps ,
@@ -72,11 +74,14 @@ function NumberFlowImpl(props: VoidProps<NumberFlowImplProps>) {
7274 const updateProperties = ( prevProps ?: NumberFlowImplProps_NoSignals ) => {
7375 if ( ! el ) return
7476
75- // el.batched = !props.isolate (Not sure why but this breaks the animations, so isolate might not work right now. I personally think it has a very niche usecase though).
77+ el . batched = ! props . isolate
7678 if ( props . transformTiming )
77- el . transformTiming ?? NumberFlowElement . defaultProps [ "transformTiming" ]
78- if ( props . spinTiming ) el . spinTiming ?? NumberFlowElement . defaultProps [ "spinTiming" ]
79- if ( props . opacityTiming ) el . opacityTiming ?? NumberFlowElement . defaultProps [ "opacityTiming" ]
79+ el . transformTiming =
80+ props . transformTiming ?? NumberFlowElement . defaultProps [ "transformTiming" ]
81+ if ( props . spinTiming )
82+ el . spinTiming = props . spinTiming ?? NumberFlowElement . defaultProps [ "spinTiming" ]
83+ if ( props . opacityTiming )
84+ el . opacityTiming = props . opacityTiming ?? NumberFlowElement . defaultProps [ "opacityTiming" ]
8085 if ( props . animated != null ) el . animated = props . animated
8186 if ( props . respectMotionPreference != null )
8287 el . respectMotionPreference = props . respectMotionPreference
@@ -107,32 +112,59 @@ function NumberFlowImpl(props: VoidProps<NumberFlowImplProps>) {
107112 }
108113 } )
109114
110- // Equivalent of getSnapshotBeforeUpdate
111- // @ts -expect-error
115+ // Update non-data properties when they change
116+ // @ts -expect-error - using return value for prev props tracking
112117 createEffect ( ( prevProps ?: NumberFlowImplProps_NoSignals ) => {
113118 updateProperties ( prevProps )
114-
115- // eslint-disable-next-line solid/reactivity
116- if ( prevProps ?. data !== props . data ( ) ) {
117- if ( props . group ( ) ) {
118- props . group ( ) ! . willUpdate ( )
119- props . group ( ) ! . didUpdate ( )
120- return
121- }
122- if ( ! props . isolate ) {
123- el ?. willUpdate ( )
124- el ?. didUpdate ( )
125- return
126- }
127- }
128-
129119 return {
130120 ...props ,
131121 group : props . group ( ) ,
132122 data : props . data ( ) ,
133123 }
134124 } )
135125
126+ // Track whether we've mounted (to skip initial render)
127+ let mounted = false
128+ onMount ( ( ) => {
129+ mounted = true
130+ } )
131+
132+ // Equivalent of getSnapshotBeforeUpdate: call willUpdate() BEFORE DOM changes
133+ // createComputed runs synchronously during the reactive update phase, before effects/rendering
134+ createComputed (
135+ on (
136+ ( ) => props . data ( ) ,
137+ ( current , prev ) => {
138+ // Skip initial render, only run on updates after mount
139+ if ( ! mounted || ! el || current === prev ) return
140+
141+ if ( props . group ( ) ) {
142+ props . group ( ) ! . willUpdate ( )
143+ } else if ( ! props . isolate ) {
144+ el . willUpdate ( )
145+ }
146+ }
147+ )
148+ )
149+
150+ // Equivalent of componentDidUpdate: call didUpdate() AFTER DOM changes
151+ // createEffect runs after DOM updates
152+ createEffect (
153+ on (
154+ ( ) => props . data ( ) ,
155+ ( current , prev ) => {
156+ // Skip initial render, only run on updates after mount
157+ if ( ! mounted || ! el || current === prev ) return
158+
159+ if ( props . group ( ) ) {
160+ props . group ( ) ! . didUpdate ( )
161+ } else if ( ! props . isolate ) {
162+ el . didUpdate ( )
163+ }
164+ }
165+ )
166+ )
167+
136168 /**
137169 * It's exactly like a signal setter, but we're setting two things:
138170 * - innerRef (from props)
0 commit comments