@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
8 lines (7 loc) • 3.65 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/lib/hooks/useScreenBounds.ts"],
"sourcesContent": ["import { throttle } from '@tldraw/utils'\nimport { useLayoutEffect } from 'react'\nimport { useEditor } from './useEditor'\n\nexport function useScreenBounds(ref: React.RefObject<HTMLElement>) {\n\tconst editor = useEditor()\n\n\tuseLayoutEffect(() => {\n\t\t// Everything else uses a debounced update...\n\t\tconst updateBounds = throttle(\n\t\t\t() => {\n\t\t\t\tif (!ref.current) return\n\t\t\t\teditor.updateViewportScreenBounds(ref.current)\n\t\t\t},\n\t\t\t200,\n\t\t\t{\n\t\t\t\ttrailing: true,\n\t\t\t}\n\t\t)\n\n\t\t// Rather than running getClientRects on every frame, we'll\n\t\t// run it once a second or when the window resizes.\n\t\tconst interval = editor.timers.setInterval(updateBounds, 1000)\n\t\twindow.addEventListener('resize', updateBounds)\n\n\t\tconst resizeObserver = new ResizeObserver((entries) => {\n\t\t\tif (!entries[0].contentRect) return\n\t\t\tupdateBounds()\n\t\t})\n\n\t\tconst container = ref.current\n\t\tlet scrollingParent: HTMLElement | Document | null = null\n\n\t\tif (container) {\n\t\t\t// When the container's size changes, update the bounds\n\t\t\tresizeObserver.observe(container)\n\n\t\t\t// When the container's nearest scrollable parent scrolls, update the bounds\n\t\t\tscrollingParent = getNearestScrollableContainer(container)\n\t\t\tscrollingParent.addEventListener('scroll', updateBounds)\n\t\t}\n\n\t\treturn () => {\n\t\t\tclearInterval(interval)\n\t\t\twindow.removeEventListener('resize', updateBounds)\n\t\t\tresizeObserver.disconnect()\n\t\t\tscrollingParent?.removeEventListener('scroll', updateBounds)\n\t\t\tupdateBounds.cancel()\n\t\t}\n\t}, [editor, ref])\n}\n\n/*!\n * Author: excalidraw\n * MIT License: https://github.com/excalidraw/excalidraw/blob/master/LICENSE\n * https://github.com/excalidraw/excalidraw/blob/48c3465b19f10ec755b3eb84e21a01a468e96e43/packages/excalidraw/utils.ts#L600\n */\nconst getNearestScrollableContainer = (element: HTMLElement): HTMLElement | Document => {\n\tlet parent = element.parentElement\n\twhile (parent) {\n\t\tif (parent === document.body) {\n\t\t\treturn document\n\t\t}\n\t\tconst { overflowY } = window.getComputedStyle(parent)\n\t\tconst hasScrollableContent = parent.scrollHeight > parent.clientHeight\n\t\tif (\n\t\t\thasScrollableContent &&\n\t\t\t(overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay')\n\t\t) {\n\t\t\treturn parent\n\t\t}\n\t\tparent = parent.parentElement\n\t}\n\treturn document\n}\n"],
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAEnB,SAAS,gBAAgB,KAAmC;AAClE,QAAM,SAAS,UAAU;AAEzB,kBAAgB,MAAM;AAErB,UAAM,eAAe;AAAA,MACpB,MAAM;AACL,YAAI,CAAC,IAAI,QAAS;AAClB,eAAO,2BAA2B,IAAI,OAAO;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,QACC,UAAU;AAAA,MACX;AAAA,IACD;AAIA,UAAM,WAAW,OAAO,OAAO,YAAY,cAAc,GAAI;AAC7D,WAAO,iBAAiB,UAAU,YAAY;AAE9C,UAAM,iBAAiB,IAAI,eAAe,CAAC,YAAY;AACtD,UAAI,CAAC,QAAQ,CAAC,EAAE,YAAa;AAC7B,mBAAa;AAAA,IACd,CAAC;AAED,UAAM,YAAY,IAAI;AACtB,QAAI,kBAAiD;AAErD,QAAI,WAAW;AAEd,qBAAe,QAAQ,SAAS;AAGhC,wBAAkB,8BAA8B,SAAS;AACzD,sBAAgB,iBAAiB,UAAU,YAAY;AAAA,IACxD;AAEA,WAAO,MAAM;AACZ,oBAAc,QAAQ;AACtB,aAAO,oBAAoB,UAAU,YAAY;AACjD,qBAAe,WAAW;AAC1B,uBAAiB,oBAAoB,UAAU,YAAY;AAC3D,mBAAa,OAAO;AAAA,IACrB;AAAA,EACD,GAAG,CAAC,QAAQ,GAAG,CAAC;AACjB;AAEA;AAAA;AAAA;AAAA;AAAA;AAKA,MAAM,gCAAgC,CAAC,YAAiD;AACvF,MAAI,SAAS,QAAQ;AACrB,SAAO,QAAQ;AACd,QAAI,WAAW,SAAS,MAAM;AAC7B,aAAO;AAAA,IACR;AACA,UAAM,EAAE,UAAU,IAAI,OAAO,iBAAiB,MAAM;AACpD,UAAM,uBAAuB,OAAO,eAAe,OAAO;AAC1D,QACC,yBACC,cAAc,UAAU,cAAc,YAAY,cAAc,YAChE;AACD,aAAO;AAAA,IACR;AACA,aAAS,OAAO;AAAA,EACjB;AACA,SAAO;AACR;",
"names": []
}