Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/html content #71

Merged
merged 6 commits into from
Feb 16, 2025
Merged

Feat/html content #71

merged 6 commits into from
Feb 16, 2025

Conversation

rick-hup
Copy link
Collaborator

  1. Added RowValue Component
  • New RowValue component for displaying and syncing MotionValue changes
  • Full test coverage included
  1. AnimatePresence Enhancements
    Added unwrapElement prop for handling nested element animations
  2. Layout System Improvements
    Enhanced LayoutFeature lifecycle management

@@ -10,4 +10,5 @@ export interface AnimatePresenceProps {
as?: string
custom?: any

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom property is currently typed as any, which can lead to potential type safety issues as it bypasses TypeScript's static type checking. It's recommended to define a more specific type or at least use unknown if the type is not determinable, which would enforce type checking at the usage points.

Recommended Change:

custom?: unknown

@@ -10,4 +10,5 @@ export interface AnimatePresenceProps {
as?: string

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property as is ambiguously named, which might cause confusion about its purpose. It's better to use a more descriptive name that clearly indicates its role, such as elementType or componentType, especially if it's used to specify the type of component or HTML tag to render.

Recommended Change:

elementType?: string

@@ -31,7 +31,7 @@ export function nodeGroup(): NodeGroup {
unsubscribe()
subscriptions.delete(node)
}
// dirtyAll()
dirtyAll()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance Concern

Calling dirtyAll on every node removal (line 34) can lead to performance issues in scenarios where the node set is large. This is because it triggers the notify function for all nodes, which might be computationally expensive.

Recommendation:
Consider optimizing this by determining if all nodes need to be notified upon the removal of one node. If not, modify the logic to selectively update nodes based on dependency or impact, or debounce the updates if multiple removals are expected in short sequences.

Comment on lines 31 to 33
unsubscribe()
subscriptions.delete(node)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lack of Error Handling

The unsubscribe function (lines 31-33) is called without any error handling. If this function throws an error, it could lead to unhandled exceptions which might crash the application or lead to unexpected behavior.

Recommendation:
Wrap the unsubscribe call in a try-catch block to handle potential errors gracefully. Log the error or handle it according to the application's error management strategy.

Comment on lines 2 to 3
export * from './animate-presence'
export * from './motion-config'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using wildcard exports (export * from ...) can lead to unintentional exposure of internal modules and makes it difficult to track dependencies. This can compromise the maintainability and security of the codebase.

Recommendation: Explicitly list the exports from each module. This approach improves clarity, makes the code easier to refactor, and helps in maintaining a clear API surface.

this.didUpdate()
globalProjectionState.hasEverUpdated = true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct manipulation of a global state (globalProjectionState.hasEverUpdated = true) within the mount method can lead to unintended side effects if this state is shared across multiple components or parts of the application. Consider encapsulating this state change within a method or using a state management pattern that isolates side effects and makes the state changes more predictable.

Comment on lines +61 to +63
else {
this.didUpdate()
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else block in the unmount method calls didUpdate() unconditionally, which could lead to unexpected behavior if didUpdate() has side effects or if it's not intended to be called in this context. It's recommended to add specific conditions or checks before calling such methods, or to ensure that the method itself handles being called in this context appropriately.

@@ -33,7 +38,7 @@ export class MotionState {
animate: true,
}

// Depth in component tree
// Depth in component tree for lifecycle ordering
public depth: number

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The depth property is used to manage the depth of the component in the component tree, which is crucial for lifecycle ordering. However, it is not initialized in the constructor, which could lead to it being undefined if accessed before being set.

Recommendation: Initialize depth in the constructor to ensure it always has a valid value, reducing the risk of runtime errors.

Comment on lines 95 to 97
get context() {
if (!this._context) {
const handler = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context getter uses a proxy to manage context inheritance, which introduces additional complexity and overhead. While this provides a flexible way to handle context, it might be over-engineered for simpler use cases and can impact performance due to the dynamic nature of proxy handling.

Recommendation: Consider simplifying the context management if the use cases are straightforward, or ensure that the benefits of using a proxy justify its overhead. Document the reasons and scenarios where this complexity is necessary.

Comment on lines 132 to 162
export function isAnimateChanged(oldOptions: Options, newOptions: Options): boolean {
const oldAnimate = oldOptions.animate
const newAnimate = newOptions.animate

if (oldAnimate === newAnimate)
return false
if (!oldAnimate || !newAnimate)
return true

if (typeof oldAnimate !== typeof newAnimate)
return true

if (typeof oldAnimate === 'string' || typeof oldAnimate === 'boolean')
return oldAnimate !== newAnimate

// Compare object keys and values
const oldKeys = Object.keys(oldAnimate)
const newKeys = Object.keys(newAnimate)

if (oldKeys.length !== newKeys.length)
return true

return oldKeys.some((key) => {
const oldVal = oldAnimate[key]
const newVal = newAnimate[key]
return oldVal !== newVal
&& (typeof oldVal === 'number'
? Math.abs(oldVal - newVal) > Number.EPSILON
: true)
})
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function isAnimateChanged performs multiple property accesses and manual comparisons which can be optimized. Consider using a deep comparison utility like lodash.isEqual for comparing the animate objects. This would not only simplify the code but also potentially improve performance by handling edge cases more efficiently.

Suggested Change:
Replace the manual key and value comparison with:

return !_.isEqual(oldAnimate, newAnimate);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant