@asteroidcms/core-utils 0.1.5 → 0.1.6

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.
package/dist/client.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PropsWithChildren, ReactNode, RefObject } from 'react';
2
+ import { PropsWithChildren, ReactNode } from 'react';
3
3
  import * as _apollo_client from '@apollo/client';
4
4
  import { InMemoryCacheConfig, ApolloClientOptions, ApolloClient } from '@apollo/client';
5
5
  import { useMutation } from '@apollo/client/react';
@@ -224,8 +224,8 @@ interface RichTextContentProps {
224
224
  */
225
225
  onReady?: (root: HTMLElement) => void;
226
226
  /**
227
- * Optional ref to the wrapper element. Useful for hooks like
228
- * `useTableOfContents` that need a stable reference to the rendered tree.
227
+ * Optional ref to the wrapper element. Useful for consumers that need a
228
+ * stable reference to the rendered tree (e.g. scroll observers, ToC hooks).
229
229
  */
230
230
  contentRef?: React.MutableRefObject<HTMLElement | null>;
231
231
  /**
@@ -293,42 +293,4 @@ declare function extractHeadingsFromElement(root: HTMLElement, options?: Extract
293
293
  scrollMarginTop?: number;
294
294
  }): ExtractedHeading[];
295
295
 
296
- interface UseTableOfContentsOptions {
297
- /** Heading levels to include. Defaults to `[2, 3]`. */
298
- levels?: ReadonlyArray<HeadingLevel>;
299
- /**
300
- * Re-collect headings whenever this value changes. Pass the article slug
301
- * (or any stable identifier) so swapping content rebuilds the ToC.
302
- */
303
- contentKey?: string | number | null;
304
- /** Pixels to subtract from heading scroll-into-view target. Default 24. */
305
- scrollMarginTop?: number;
306
- /**
307
- * Distance from the top of the viewport (in px) at which a heading becomes
308
- * "active". A heading is considered active once its top edge has scrolled
309
- * past this line. Default `96` — works well with a sticky header that
310
- * stands ~60–80px tall.
311
- */
312
- activationOffset?: number;
313
- }
314
- interface UseTableOfContentsResult {
315
- items: ExtractedHeading[];
316
- activeId: string;
317
- }
318
- /**
319
- * Build a table of contents from a rendered element and track which
320
- * heading is currently in view via IntersectionObserver. Resilient to
321
- * content swaps when `contentKey` is provided.
322
- *
323
- * Usage:
324
- * ```tsx
325
- * const ref = useRef<HTMLDivElement>(null);
326
- * const { items, activeId } = useTableOfContents(ref, {
327
- * contentKey: article.slug,
328
- * levels: [2, 3],
329
- * });
330
- * ```
331
- */
332
- declare function useTableOfContents(ref: RefObject<HTMLElement | null>, options?: UseTableOfContentsOptions): UseTableOfContentsResult;
333
-
334
- export { AsteroidCMSProvider, type AsteroidCMSProviderProps, type ExtractHeadingsOptions, type ExtractedHeading, type HeadingLevel, RichTextContent, type UseCmsContentOptions, type UseCmsMutateOptions, type UseTableOfContentsOptions, type UseTableOfContentsResult, extractHeadingsFromElement, extractHeadingsFromHtml, slugify, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate, useTableOfContents };
296
+ export { AsteroidCMSProvider, type AsteroidCMSProviderProps, type ExtractHeadingsOptions, type ExtractedHeading, type HeadingLevel, RichTextContent, type UseCmsContentOptions, type UseCmsMutateOptions, extractHeadingsFromElement, extractHeadingsFromHtml, slugify, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate };
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PropsWithChildren, ReactNode, RefObject } from 'react';
2
+ import { PropsWithChildren, ReactNode } from 'react';
3
3
  import * as _apollo_client from '@apollo/client';
4
4
  import { InMemoryCacheConfig, ApolloClientOptions, ApolloClient } from '@apollo/client';
5
5
  import { useMutation } from '@apollo/client/react';
@@ -224,8 +224,8 @@ interface RichTextContentProps {
224
224
  */
225
225
  onReady?: (root: HTMLElement) => void;
226
226
  /**
227
- * Optional ref to the wrapper element. Useful for hooks like
228
- * `useTableOfContents` that need a stable reference to the rendered tree.
227
+ * Optional ref to the wrapper element. Useful for consumers that need a
228
+ * stable reference to the rendered tree (e.g. scroll observers, ToC hooks).
229
229
  */
230
230
  contentRef?: React.MutableRefObject<HTMLElement | null>;
231
231
  /**
@@ -293,42 +293,4 @@ declare function extractHeadingsFromElement(root: HTMLElement, options?: Extract
293
293
  scrollMarginTop?: number;
294
294
  }): ExtractedHeading[];
295
295
 
296
- interface UseTableOfContentsOptions {
297
- /** Heading levels to include. Defaults to `[2, 3]`. */
298
- levels?: ReadonlyArray<HeadingLevel>;
299
- /**
300
- * Re-collect headings whenever this value changes. Pass the article slug
301
- * (or any stable identifier) so swapping content rebuilds the ToC.
302
- */
303
- contentKey?: string | number | null;
304
- /** Pixels to subtract from heading scroll-into-view target. Default 24. */
305
- scrollMarginTop?: number;
306
- /**
307
- * Distance from the top of the viewport (in px) at which a heading becomes
308
- * "active". A heading is considered active once its top edge has scrolled
309
- * past this line. Default `96` — works well with a sticky header that
310
- * stands ~60–80px tall.
311
- */
312
- activationOffset?: number;
313
- }
314
- interface UseTableOfContentsResult {
315
- items: ExtractedHeading[];
316
- activeId: string;
317
- }
318
- /**
319
- * Build a table of contents from a rendered element and track which
320
- * heading is currently in view via IntersectionObserver. Resilient to
321
- * content swaps when `contentKey` is provided.
322
- *
323
- * Usage:
324
- * ```tsx
325
- * const ref = useRef<HTMLDivElement>(null);
326
- * const { items, activeId } = useTableOfContents(ref, {
327
- * contentKey: article.slug,
328
- * levels: [2, 3],
329
- * });
330
- * ```
331
- */
332
- declare function useTableOfContents(ref: RefObject<HTMLElement | null>, options?: UseTableOfContentsOptions): UseTableOfContentsResult;
333
-
334
- export { AsteroidCMSProvider, type AsteroidCMSProviderProps, type ExtractHeadingsOptions, type ExtractedHeading, type HeadingLevel, RichTextContent, type UseCmsContentOptions, type UseCmsMutateOptions, type UseTableOfContentsOptions, type UseTableOfContentsResult, extractHeadingsFromElement, extractHeadingsFromHtml, slugify, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate, useTableOfContents };
296
+ export { AsteroidCMSProvider, type AsteroidCMSProviderProps, type ExtractHeadingsOptions, type ExtractedHeading, type HeadingLevel, RichTextContent, type UseCmsContentOptions, type UseCmsMutateOptions, extractHeadingsFromElement, extractHeadingsFromHtml, slugify, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate };
package/dist/client.js CHANGED
@@ -1721,97 +1721,6 @@ function extractHeadingsFromElement(root, options = {}) {
1721
1721
  return out;
1722
1722
  }
1723
1723
 
1724
- // src/hooks/useTableOfContents.tsx
1725
- function useTableOfContents(ref, options = {}) {
1726
- const {
1727
- levels,
1728
- contentKey = null,
1729
- scrollMarginTop = 24,
1730
- activationOffset = 96
1731
- } = options;
1732
- const [items, setItems] = useState([]);
1733
- const [activeId, setActiveId] = useState("");
1734
- useEffect(() => {
1735
- const root = ref.current;
1736
- if (!root) {
1737
- setItems([]);
1738
- setActiveId("");
1739
- return;
1740
- }
1741
- let raf = 0;
1742
- const collect = () => {
1743
- const next = extractHeadingsFromElement(root, {
1744
- levels,
1745
- scrollMarginTop
1746
- });
1747
- setItems(next);
1748
- setActiveId(
1749
- (prev) => next.some((h) => h.id === prev) ? prev : next[0]?.id ?? ""
1750
- );
1751
- };
1752
- raf = requestAnimationFrame(collect);
1753
- const mo = new MutationObserver(() => {
1754
- if (raf) cancelAnimationFrame(raf);
1755
- raf = requestAnimationFrame(collect);
1756
- });
1757
- mo.observe(root, { childList: true, subtree: true, characterData: true });
1758
- return () => {
1759
- mo.disconnect();
1760
- if (raf) cancelAnimationFrame(raf);
1761
- };
1762
- }, [ref, contentKey, levels, scrollMarginTop]);
1763
- useEffect(() => {
1764
- if (items.length === 0) return;
1765
- const targets = items.map((it) => document.getElementById(it.id)).filter((el) => el !== null);
1766
- if (targets.length === 0) return;
1767
- let raf = 0;
1768
- const compute = () => {
1769
- raf = 0;
1770
- let activeIdx = 0;
1771
- for (let i = 0; i < items.length; i++) {
1772
- const el = document.getElementById(items[i].id);
1773
- if (!el) continue;
1774
- if (el.getBoundingClientRect().top - activationOffset <= 0) {
1775
- activeIdx = i;
1776
- } else {
1777
- break;
1778
- }
1779
- }
1780
- const scroller = document.scrollingElement || document.documentElement;
1781
- const scrollY = window.scrollY;
1782
- const viewportH = window.innerHeight;
1783
- const atBottom = scrollY + viewportH >= scroller.scrollHeight - 2;
1784
- if (atBottom) {
1785
- for (let i = items.length - 1; i > activeIdx; i--) {
1786
- const el = document.getElementById(items[i].id);
1787
- if (el && el.getBoundingClientRect().top < viewportH) {
1788
- activeIdx = i;
1789
- break;
1790
- }
1791
- }
1792
- }
1793
- setActiveId(items[activeIdx].id);
1794
- };
1795
- const schedule = () => {
1796
- if (raf) return;
1797
- raf = requestAnimationFrame(compute);
1798
- };
1799
- const io = new IntersectionObserver(schedule, {
1800
- rootMargin: `-${activationOffset}px 0px -${Math.max(0, window.innerHeight - activationOffset - 1)}px 0px`,
1801
- threshold: 0
1802
- });
1803
- targets.forEach((t) => io.observe(t));
1804
- window.addEventListener("resize", schedule, { passive: true });
1805
- compute();
1806
- return () => {
1807
- io.disconnect();
1808
- window.removeEventListener("resize", schedule);
1809
- if (raf) cancelAnimationFrame(raf);
1810
- };
1811
- }, [items, activationOffset]);
1812
- return { items, activeId };
1813
- }
1814
-
1815
- export { AsteroidCMSProvider, RichTextContent, extractHeadingsFromElement, extractHeadingsFromHtml, slugify, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate, useTableOfContents };
1724
+ export { AsteroidCMSProvider, RichTextContent, extractHeadingsFromElement, extractHeadingsFromHtml, slugify, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate };
1816
1725
  //# sourceMappingURL=client.js.map
1817
1726
  //# sourceMappingURL=client.js.map