solid-presence
Advanced tools
Comparing version
@@ -1,2 +0,24 @@ | ||
import { createPresence } from 'corvu'; | ||
export { createPresence as default } from 'corvu'; | ||
import { MaybeAccessor } from '@corvu/utils'; | ||
import { Accessor } from 'solid-js'; | ||
/** | ||
* Manages the presence of an element in the DOM while being aware of pending animations. | ||
* | ||
* @param props.show - Whether the presence is showing. | ||
* @param props.element - The element which animations should be tracked. | ||
* @returns ```typescript | ||
* { | ||
* present: Accessor<boolean> | ||
* state: Accessor<'present' | 'hiding' | 'hidden'> | ||
* } | ||
* ``` | ||
*/ | ||
declare const createPresence: (props: { | ||
show: MaybeAccessor<boolean>; | ||
element: MaybeAccessor<HTMLElement | null>; | ||
}) => { | ||
present: Accessor<boolean>; | ||
state: Accessor<'present' | 'hiding' | 'hidden'>; | ||
}; | ||
export { createPresence as default }; |
@@ -1,6 +0,76 @@ | ||
import { createPresence } from 'corvu'; | ||
import { access } from '@corvu/utils'; | ||
import { createMemo, createSignal, createEffect, untrack, onCleanup } from 'solid-js'; | ||
// src/presence.ts | ||
var createPresence = (props) => { | ||
const refStyles = createMemo(() => { | ||
const element = access(props.element); | ||
if (!element) | ||
return; | ||
return getComputedStyle(element); | ||
}); | ||
const getAnimationName = () => { | ||
return refStyles()?.animationName ?? "none"; | ||
}; | ||
const [presentState, setPresentState] = createSignal(access(props.show) ? "present" : "hidden"); | ||
let animationName = "none"; | ||
createEffect((prevShow) => { | ||
const show = access(props.show); | ||
untrack(() => { | ||
if (prevShow === show) | ||
return show; | ||
const prevAnimationName = animationName; | ||
const currentAnimationName = getAnimationName(); | ||
if (show) { | ||
setPresentState("present"); | ||
} else if (currentAnimationName === "none" || refStyles()?.display === "none") { | ||
setPresentState("hidden"); | ||
} else { | ||
const isAnimating = prevAnimationName !== currentAnimationName; | ||
if (prevShow && isAnimating) { | ||
setPresentState("hiding"); | ||
} else { | ||
setPresentState("hidden"); | ||
} | ||
} | ||
}); | ||
return show; | ||
}); | ||
createEffect(() => { | ||
const element = access(props.element); | ||
if (!element) | ||
return; | ||
const handleAnimationStart = (event) => { | ||
if (event.target === element) { | ||
animationName = getAnimationName(); | ||
} | ||
}; | ||
const handleAnimationEnd = (event) => { | ||
const currentAnimationName = getAnimationName(); | ||
const isCurrentAnimation = currentAnimationName.includes( | ||
event.animationName | ||
); | ||
if (event.target === element && isCurrentAnimation && presentState() === "hiding") { | ||
setPresentState("hidden"); | ||
} | ||
}; | ||
element.addEventListener("animationstart", handleAnimationStart); | ||
element.addEventListener("animationcancel", handleAnimationEnd); | ||
element.addEventListener("animationend", handleAnimationEnd); | ||
onCleanup(() => { | ||
element.removeEventListener("animationstart", handleAnimationStart); | ||
element.removeEventListener("animationcancel", handleAnimationEnd); | ||
element.removeEventListener("animationend", handleAnimationEnd); | ||
}); | ||
}); | ||
return { | ||
present: () => presentState() === "present" || presentState() === "hiding", | ||
state: presentState | ||
}; | ||
}; | ||
var presence_default = createPresence; | ||
// src/index.ts | ||
var src_default = createPresence; | ||
var src_default = presence_default; | ||
export { src_default as default }; |
@@ -0,6 +1,82 @@ | ||
// src/presence.ts | ||
import { access } from "@corvu/utils"; | ||
import { | ||
createEffect, | ||
createMemo, | ||
createSignal, | ||
onCleanup, | ||
untrack | ||
} from "solid-js"; | ||
var createPresence = (props) => { | ||
const refStyles = createMemo(() => { | ||
const element = access(props.element); | ||
if (!element) | ||
return; | ||
return getComputedStyle(element); | ||
}); | ||
const getAnimationName = () => { | ||
return refStyles()?.animationName ?? "none"; | ||
}; | ||
const [presentState, setPresentState] = createSignal(access(props.show) ? "present" : "hidden"); | ||
let animationName = "none"; | ||
createEffect((prevShow) => { | ||
const show = access(props.show); | ||
untrack(() => { | ||
if (prevShow === show) | ||
return show; | ||
const prevAnimationName = animationName; | ||
const currentAnimationName = getAnimationName(); | ||
if (show) { | ||
setPresentState("present"); | ||
} else if (currentAnimationName === "none" || refStyles()?.display === "none") { | ||
setPresentState("hidden"); | ||
} else { | ||
const isAnimating = prevAnimationName !== currentAnimationName; | ||
if (prevShow && isAnimating) { | ||
setPresentState("hiding"); | ||
} else { | ||
setPresentState("hidden"); | ||
} | ||
} | ||
}); | ||
return show; | ||
}); | ||
createEffect(() => { | ||
const element = access(props.element); | ||
if (!element) | ||
return; | ||
const handleAnimationStart = (event) => { | ||
if (event.target === element) { | ||
animationName = getAnimationName(); | ||
} | ||
}; | ||
const handleAnimationEnd = (event) => { | ||
const currentAnimationName = getAnimationName(); | ||
const isCurrentAnimation = currentAnimationName.includes( | ||
event.animationName | ||
); | ||
if (event.target === element && isCurrentAnimation && presentState() === "hiding") { | ||
setPresentState("hidden"); | ||
} | ||
}; | ||
element.addEventListener("animationstart", handleAnimationStart); | ||
element.addEventListener("animationcancel", handleAnimationEnd); | ||
element.addEventListener("animationend", handleAnimationEnd); | ||
onCleanup(() => { | ||
element.removeEventListener("animationstart", handleAnimationStart); | ||
element.removeEventListener("animationcancel", handleAnimationEnd); | ||
element.removeEventListener("animationend", handleAnimationEnd); | ||
}); | ||
}); | ||
return { | ||
present: () => presentState() === "present" || presentState() === "hiding", | ||
state: presentState | ||
}; | ||
}; | ||
var presence_default = createPresence; | ||
// src/index.ts | ||
import { createPresence } from "corvu"; | ||
var src_default = createPresence; | ||
var src_default = presence_default; | ||
export { | ||
src_default as default | ||
}; |
{ | ||
"name": "solid-presence", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"private": false, | ||
@@ -42,8 +42,8 @@ "description": "SolidJS utility that manages the presence of an element in the DOM while being aware of pending animations.", | ||
"dependencies": { | ||
"corvu": "~0.4.0" | ||
"@corvu/utils": "^0.1.0" | ||
}, | ||
"devDependencies": { | ||
"@typescript-eslint/eslint-plugin": "^6.21.0", | ||
"@typescript-eslint/eslint-plugin": "^7.0.2", | ||
"esbuild-plugin-solid": "^0.5.0", | ||
"eslint": "^8.56.0", | ||
"eslint": "^8.57.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
@@ -53,4 +53,5 @@ "eslint-plugin-prettier": "^5.1.3", | ||
"prettier": "^3.2.5", | ||
"solid-js": "^1.8.14", | ||
"tsup": "^8.0.1", | ||
"solid-js": "^1.8.15", | ||
"tsup": "^8.0.2", | ||
"typedoc": "0.25.4", | ||
"typescript": "^5.3.3" | ||
@@ -62,6 +63,7 @@ }, | ||
"scripts": { | ||
"build": "pnpm lint && tsup", | ||
"build": "tsup", | ||
"clean": "rm -rf .turbo dist node_modules", | ||
"lint": "eslint --max-warnings=0 .", | ||
"watch": "tsup --watch" | ||
"typedoc": "typedoc --json api.json --entryPoints ./src/index.ts" | ||
} | ||
} |
@@ -38,2 +38,2 @@ <div align="center"> | ||
## Further Reading | ||
This utility is a re-export of the `createPresence` function from [corvu](https://corvu.dev). For more information, see [Presence](https://corvu.dev/docs/utilities/presence) in the corvu docs. | ||
This utility is from the maintainers of [corvu](https://corvu.dev), a collection of unstyled, accessible and customizable UI primitives for SolidJS. It is also documented in the corvu docs under [Presence](https://corvu.dev/docs/utilities/presence). |
9702
136.29%176
1366.67%11
10%+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed