@ably/ui 17.13.0-dev.a779a1fd → 17.13.0-dev.d6a24f68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useState,useEffect,useRef}from"react";export function useContentHeight(ref,initialHeight=0){const[contentHeight,setContentHeight]=useState(initialHeight);const observerRef=useRef(null);useEffect(()=>{const element=ref.current;if(!element){return}observerRef.current=new ResizeObserver(entries=>{requestAnimationFrame(()=>{const entry=entries[0];if(entry&&entry.contentRect){const newHeight=Math.round(entry.contentRect.height);setContentHeight(newHeight)}})});observerRef.current.observe(element);return()=>{observerRef.current?.disconnect();observerRef.current=null}},[ref]);return contentHeight}
|
|
1
|
+
import{useState,useEffect,useRef}from"react";export function useContentHeight(ref,initialHeight=0){const[contentHeight,setContentHeight]=useState(initialHeight);const observerRef=useRef(null);const rafIdRef=useRef(null);useEffect(()=>{const element=ref.current;if(!element){return}let isMounted=true;observerRef.current=new ResizeObserver(entries=>{if(rafIdRef.current!==null){cancelAnimationFrame(rafIdRef.current)}rafIdRef.current=requestAnimationFrame(()=>{rafIdRef.current=null;if(!isMounted)return;const entry=entries[0];if(entry&&entry.contentRect){const newHeight=Math.round(entry.contentRect.height);setContentHeight(newHeight)}})});observerRef.current.observe(element);return()=>{isMounted=false;if(rafIdRef.current!==null){cancelAnimationFrame(rafIdRef.current);rafIdRef.current=null}observerRef.current?.disconnect();observerRef.current=null}},[ref]);return contentHeight}
|
|
2
2
|
//# sourceMappingURL=use-content-height.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/hooks/use-content-height.ts"],"sourcesContent":["import { useState, useEffect, useRef, RefObject } from \"react\";\n\n/**\n * Custom hook that tracks the content height of an element using ResizeObserver.\n * This eliminates forced reflows by using the browser's native resize observation API\n * instead of synchronous clientHeight/getBoundingClientRect queries.\n *\n * @param ref - React ref to the element to observe\n * @param initialHeight - Initial height value (default: 0)\n * @returns Current content height in pixels\n */\nexport function useContentHeight(\n ref: RefObject<HTMLElement>,\n initialHeight = 0,\n): number {\n const [contentHeight, setContentHeight] = useState<number>(initialHeight);\n const observerRef = useRef<ResizeObserver | null>(null);\n\n useEffect(() => {\n const element = ref.current;\n\n if (!element) {\n return;\n }\n\n observerRef.current = new ResizeObserver((entries) => {\n requestAnimationFrame(() => {\n const entry = entries[0];\n if (entry && entry.contentRect) {\n const newHeight = Math.round(entry.contentRect.height);\n setContentHeight(newHeight);\n }\n });\n });\n\n observerRef.current.observe(element);\n\n return () => {\n observerRef.current?.disconnect();\n observerRef.current = null;\n };\n }, [ref]);\n\n return contentHeight;\n}\n"],"names":["useState","useEffect","useRef","useContentHeight","ref","initialHeight","contentHeight","setContentHeight","observerRef","element","current","ResizeObserver","entries","requestAnimationFrame","entry","contentRect","newHeight","Math","round","height","observe","disconnect"],"mappings":"AAAA,OAASA,QAAQ,CAAEC,SAAS,CAAEC,MAAM,KAAmB,OAAQ,AAW/D,QAAO,SAASC,iBACdC,GAA2B,CAC3BC,cAAgB,CAAC,EAEjB,KAAM,CAACC,cAAeC,iBAAiB,CAAGP,SAAiBK,eAC3D,MAAMG,YAAcN,OAA8B,
|
|
1
|
+
{"version":3,"sources":["../../../src/core/hooks/use-content-height.ts"],"sourcesContent":["import { useState, useEffect, useRef, RefObject } from \"react\";\n\n/**\n * Custom hook that tracks the content height of an element using ResizeObserver.\n * This eliminates forced reflows by using the browser's native resize observation API\n * instead of synchronous clientHeight/getBoundingClientRect queries.\n *\n * @param ref - React ref to the element to observe\n * @param initialHeight - Initial height value (default: 0)\n * @returns Current content height in pixels\n */\nexport function useContentHeight(\n ref: RefObject<HTMLElement>,\n initialHeight = 0,\n): number {\n const [contentHeight, setContentHeight] = useState<number>(initialHeight);\n const observerRef = useRef<ResizeObserver | null>(null);\n const rafIdRef = useRef<number | null>(null);\n\n useEffect(() => {\n const element = ref.current;\n\n if (!element) {\n return;\n }\n\n let isMounted = true;\n\n observerRef.current = new ResizeObserver((entries) => {\n // Cancel any pending RAF to avoid stale updates\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n\n rafIdRef.current = requestAnimationFrame(() => {\n rafIdRef.current = null;\n // Guard against updates after unmount\n if (!isMounted) return;\n\n const entry = entries[0];\n if (entry && entry.contentRect) {\n const newHeight = Math.round(entry.contentRect.height);\n setContentHeight(newHeight);\n }\n });\n });\n\n observerRef.current.observe(element);\n\n return () => {\n isMounted = false;\n // Cancel pending RAF to prevent setState after unmount\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n rafIdRef.current = null;\n }\n observerRef.current?.disconnect();\n observerRef.current = null;\n };\n }, [ref]);\n\n return contentHeight;\n}\n"],"names":["useState","useEffect","useRef","useContentHeight","ref","initialHeight","contentHeight","setContentHeight","observerRef","rafIdRef","element","current","isMounted","ResizeObserver","entries","cancelAnimationFrame","requestAnimationFrame","entry","contentRect","newHeight","Math","round","height","observe","disconnect"],"mappings":"AAAA,OAASA,QAAQ,CAAEC,SAAS,CAAEC,MAAM,KAAmB,OAAQ,AAW/D,QAAO,SAASC,iBACdC,GAA2B,CAC3BC,cAAgB,CAAC,EAEjB,KAAM,CAACC,cAAeC,iBAAiB,CAAGP,SAAiBK,eAC3D,MAAMG,YAAcN,OAA8B,MAClD,MAAMO,SAAWP,OAAsB,MAEvCD,UAAU,KACR,MAAMS,QAAUN,IAAIO,OAAO,CAE3B,GAAI,CAACD,QAAS,CACZ,MACF,CAEA,IAAIE,UAAY,IAEhBJ,CAAAA,YAAYG,OAAO,CAAG,IAAIE,eAAe,AAACC,UAExC,GAAIL,SAASE,OAAO,GAAK,KAAM,CAC7BI,qBAAqBN,SAASE,OAAO,CACvC,CAEAF,SAASE,OAAO,CAAGK,sBAAsB,KACvCP,SAASE,OAAO,CAAG,KAEnB,GAAI,CAACC,UAAW,OAEhB,MAAMK,MAAQH,OAAO,CAAC,EAAE,CACxB,GAAIG,OAASA,MAAMC,WAAW,CAAE,CAC9B,MAAMC,UAAYC,KAAKC,KAAK,CAACJ,MAAMC,WAAW,CAACI,MAAM,EACrDf,iBAAiBY,UACnB,CACF,EACF,GAEAX,YAAYG,OAAO,CAACY,OAAO,CAACb,SAE5B,MAAO,KACLE,UAAY,MAEZ,GAAIH,SAASE,OAAO,GAAK,KAAM,CAC7BI,qBAAqBN,SAASE,OAAO,CACrCF,CAAAA,SAASE,OAAO,CAAG,IACrB,CACAH,YAAYG,OAAO,EAAEa,YACrBhB,CAAAA,YAAYG,OAAO,CAAG,IACxB,CACF,EAAG,CAACP,IAAI,EAER,OAAOE,aACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/hooks/use-themed-scrollpoints.ts"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { ThemedScrollpoint } from \"../Header/types\";\n\nconst HEADER_HEIGHT = 64;\n\nexport function useThemedScrollpoints(\n scrollpoints: ThemedScrollpoint[],\n): string {\n const [activeClassName, setActiveClassName] = useState<string>(\"\");\n\n const previousClassNameRef = useRef<string>(\"\");\n const observerRef = useRef<IntersectionObserver | null>(null);\n const initialCheckDoneRef = useRef<boolean>(false);\n const intersectingElementsRef = useRef<\n Map<string, IntersectionObserverEntry>\n >(new Map());\n\n useEffect(() => {\n if (scrollpoints.length === 0) {\n // Clear active className when scrollpoints becomes empty\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setActiveClassName(\"\");\n previousClassNameRef.current = \"\";\n return;\n }\n\n const intersectingElements = intersectingElementsRef.current;\n\n observerRef.current = new IntersectionObserver(\n (entries) => {\n requestAnimationFrame(() => {\n // Update the map of currently intersecting elements\n for (const entry of entries) {\n const id = (entry.target as HTMLElement).id;\n if (entry.isIntersecting) {\n intersectingElements.set(id, entry);\n } else {\n intersectingElements.delete(id);\n }\n }\n\n // Find the best match from ALL currently intersecting elements\n // Use scrollpoints array order as tiebreaker when distances are equal\n let bestMatch: {\n scrollpoint: ThemedScrollpoint;\n distance: number;\n index: number;\n } | null = null;\n\n for (const [id, entry] of intersectingElements) {\n const scrollpointIndex = scrollpoints.findIndex((sp) => sp.id === id);\n if (scrollpointIndex === -1) continue;\n\n const scrollpoint = scrollpoints[scrollpointIndex];\n\n // Use boundingClientRect from entry if available, otherwise get from target\n const rect =\n entry.boundingClientRect || entry.target.getBoundingClientRect();\n const containsHeader =\n rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT;\n\n if (containsHeader) {\n const distance = Math.abs(rect.top - HEADER_HEIGHT);\n // Pick element with smallest distance; if equal, pick earlier in scrollpoints array\n if (\n !bestMatch ||\n distance < bestMatch.distance ||\n (distance === bestMatch.distance
|
|
1
|
+
{"version":3,"sources":["../../../src/core/hooks/use-themed-scrollpoints.ts"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { ThemedScrollpoint } from \"../Header/types\";\n\nconst HEADER_HEIGHT = 64;\n\nexport function useThemedScrollpoints(\n scrollpoints: ThemedScrollpoint[],\n): string {\n const [activeClassName, setActiveClassName] = useState<string>(\"\");\n\n const previousClassNameRef = useRef<string>(\"\");\n const observerRef = useRef<IntersectionObserver | null>(null);\n const initialCheckDoneRef = useRef<boolean>(false);\n const intersectingElementsRef = useRef<\n Map<string, IntersectionObserverEntry>\n >(new Map());\n\n useEffect(() => {\n if (scrollpoints.length === 0) {\n // Clear active className when scrollpoints becomes empty\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setActiveClassName(\"\");\n previousClassNameRef.current = \"\";\n return;\n }\n\n const intersectingElements = intersectingElementsRef.current;\n\n observerRef.current = new IntersectionObserver(\n (entries) => {\n requestAnimationFrame(() => {\n // Update the map of currently intersecting elements\n for (const entry of entries) {\n const id = (entry.target as HTMLElement).id;\n if (entry.isIntersecting) {\n intersectingElements.set(id, entry);\n } else {\n intersectingElements.delete(id);\n }\n }\n\n // Find the best match from ALL currently intersecting elements\n // Use scrollpoints array order as tiebreaker when distances are equal\n let bestMatch: {\n scrollpoint: ThemedScrollpoint;\n distance: number;\n index: number;\n } | null = null;\n\n for (const [id, entry] of intersectingElements) {\n const scrollpointIndex = scrollpoints.findIndex(\n (sp) => sp.id === id,\n );\n if (scrollpointIndex === -1) continue;\n\n const scrollpoint = scrollpoints[scrollpointIndex];\n\n // Use boundingClientRect from entry if available, otherwise get from target\n const rect =\n entry.boundingClientRect || entry.target.getBoundingClientRect();\n const containsHeader =\n rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT;\n\n if (containsHeader) {\n const distance = Math.abs(rect.top - HEADER_HEIGHT);\n // Pick element with smallest distance; if equal, pick earlier in scrollpoints array\n if (\n !bestMatch ||\n distance < bestMatch.distance ||\n (distance === bestMatch.distance &&\n scrollpointIndex < bestMatch.index)\n ) {\n bestMatch = { scrollpoint, distance, index: scrollpointIndex };\n }\n }\n }\n\n if (\n bestMatch &&\n bestMatch.scrollpoint.className !== previousClassNameRef.current\n ) {\n previousClassNameRef.current = bestMatch.scrollpoint.className;\n setActiveClassName(bestMatch.scrollpoint.className);\n }\n });\n },\n {\n rootMargin: `-${HEADER_HEIGHT}px 0px 0px 0px`,\n threshold: 0,\n },\n );\n\n scrollpoints.forEach(({ id }) => {\n const element = document.getElementById(id);\n if (element) {\n observerRef.current?.observe(element);\n } else {\n console.warn(\n `useThemedScrollpoints: Element with id \"${id}\" not found in DOM`,\n );\n }\n });\n\n // Manually check initial intersection state since IntersectionObserver\n // callbacks only fire on changes, not on initial observation\n // Use a small timeout to ensure DOM is fully laid out\n const timeoutId = setTimeout(() => {\n if (initialCheckDoneRef.current) {\n return;\n }\n initialCheckDoneRef.current = true;\n\n // Find the element closest to the header position\n // Use scrollpoints array order as tiebreaker when distances are equal\n let bestMatch: {\n scrollpoint: ThemedScrollpoint;\n distance: number;\n index: number;\n } | null = null;\n\n for (let i = 0; i < scrollpoints.length; i++) {\n const scrollpoint = scrollpoints[i];\n const element = document.getElementById(scrollpoint.id);\n if (element) {\n const rect = element.getBoundingClientRect();\n const containsHeader =\n rect.top <= HEADER_HEIGHT && rect.bottom >= HEADER_HEIGHT;\n\n if (containsHeader) {\n const distance = Math.abs(rect.top - HEADER_HEIGHT);\n // Pick element with smallest distance; if equal, pick earlier in scrollpoints array\n if (\n !bestMatch ||\n distance < bestMatch.distance ||\n (distance === bestMatch.distance && i < bestMatch.index)\n ) {\n bestMatch = { scrollpoint, distance, index: i };\n }\n }\n }\n }\n\n if (bestMatch) {\n previousClassNameRef.current = bestMatch.scrollpoint.className;\n setActiveClassName(bestMatch.scrollpoint.className);\n }\n }, 0);\n\n return () => {\n clearTimeout(timeoutId);\n observerRef.current?.disconnect();\n observerRef.current = null;\n initialCheckDoneRef.current = false;\n intersectingElements.clear();\n };\n }, [scrollpoints]);\n\n return activeClassName;\n}\n"],"names":["useState","useEffect","useRef","HEADER_HEIGHT","useThemedScrollpoints","scrollpoints","activeClassName","setActiveClassName","previousClassNameRef","observerRef","initialCheckDoneRef","intersectingElementsRef","Map","length","current","intersectingElements","IntersectionObserver","entries","requestAnimationFrame","entry","id","target","isIntersecting","set","delete","bestMatch","scrollpointIndex","findIndex","sp","scrollpoint","rect","boundingClientRect","getBoundingClientRect","containsHeader","top","bottom","distance","Math","abs","index","className","rootMargin","threshold","forEach","element","document","getElementById","observe","console","warn","timeoutId","setTimeout","i","clearTimeout","disconnect","clear"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ably/ui",
|
|
3
|
-
"version": "17.13.0-dev.
|
|
3
|
+
"version": "17.13.0-dev.d6a24f68",
|
|
4
4
|
"description": "Home of the Ably design system library ([design.ably.com](https://design.ably.com)). It provides a showcase, development/test environment and a publishing pipeline for different distributables.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|