Strip template artifacts and fix lint errors

Remove npm lockfile, unused create-next-app SVGs, project-specific
next.config workarounds, and the unused @remixicon/react and date-fns deps.

Replace three set-state-in-effect patterns with useSyncExternalStore in
use-mobile, DialogPortal, and Carousel; the carousel change also fixes a
leaked reInit listener. yarn lint and yarn build are clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K8PmydbW6A1S2Tw3SFc3Cg
This commit is contained in:
Rami Bitar
2026-07-23 19:24:23 -04:00
parent 02327188e2
commit d5e463a665
13 changed files with 144 additions and 6937 deletions

View File

@@ -58,14 +58,32 @@ function Carousel({
},
plugins
)
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
const [canScrollNext, setCanScrollNext] = React.useState(false)
// Embla is an external store: subscribe to its events rather than mirroring
// its scroll state into React state from an effect.
const subscribe = React.useCallback(
(onStoreChange: () => void) => {
if (!api) return () => {}
api.on("reInit", onStoreChange)
api.on("select", onStoreChange)
const onSelect = React.useCallback((api: CarouselApi) => {
if (!api) return
setCanScrollPrev(api.canScrollPrev())
setCanScrollNext(api.canScrollNext())
}, [])
return () => {
api.off("reInit", onStoreChange)
api.off("select", onStoreChange)
}
},
[api]
)
const canScrollPrev = React.useSyncExternalStore(
subscribe,
() => api?.canScrollPrev() ?? false,
() => false
)
const canScrollNext = React.useSyncExternalStore(
subscribe,
() => api?.canScrollNext() ?? false,
() => false
)
const scrollPrev = React.useCallback(() => {
api?.scrollPrev()
@@ -93,17 +111,6 @@ function Carousel({
setApi(api)
}, [api, setApi])
React.useEffect(() => {
if (!api) return
onSelect(api)
api.on("reInit", onSelect)
api.on("select", onSelect)
return () => {
api?.off("select", onSelect)
}
}, [api, onSelect])
return (
<CarouselContext.Provider
value={{

View File

@@ -19,15 +19,21 @@ function DialogTrigger({
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
}
const subscribeToNothing = () => () => {}
function DialogPortal({
...props
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
// Radix's Portal calls createPortal(children, document.body) as soon as it
// renders. During static prerendering there's no `document`, so gate the
// portal behind an effect that only runs in the browser. Closed dialogs
// render nothing on the server anyway, so there's no visual/hydration change.
const [mounted, setMounted] = React.useState(false)
React.useEffect(() => setMounted(true), [])
// portal on the client snapshot, which is only read in the browser. Closed
// dialogs render nothing on the server anyway, so there's no visual/
// hydration change.
const mounted = React.useSyncExternalStore(
subscribeToNothing,
() => true,
() => false
)
if (!mounted) return null