@asteroidcms/core-utils 0.1.3 → 0.1.5

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,6 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as react from 'react';
3
- import { PropsWithChildren } from 'react';
2
+ import { PropsWithChildren, ReactNode, RefObject } from 'react';
4
3
  import * as _apollo_client from '@apollo/client';
5
4
  import { InMemoryCacheConfig, ApolloClientOptions, ApolloClient } from '@apollo/client';
6
5
  import { useMutation } from '@apollo/client/react';
@@ -205,7 +204,7 @@ declare function useCmsImage(): (id?: string) => string;
205
204
  *
206
205
  * Idempotent: parseRichText(parseRichText(x, opts), opts) === parseRichText(x, opts).
207
206
  */
208
- type RichTextClassKey = "p" | "br" | "hr" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "ul" | "ol" | "li" | "blockquote" | "pre" | "code" | "inlineCode" | "a" | "strong" | "em" | "u" | "s" | "kbd" | "table" | "tableWrapper" | "thead" | "tbody" | "tr" | "th" | "td" | "figure" | "figcaption" | "img" | "span" | "callout" | "calloutTitle";
207
+ type RichTextClassKey = "p" | "br" | "hr" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "ul" | "ol" | "li" | "blockquote" | "pre" | "code" | "inlineCode" | "a" | "strong" | "em" | "u" | "s" | "kbd" | "table" | "tableWrapper" | "thead" | "tbody" | "tr" | "th" | "td" | "figure" | "figcaption" | "img" | "span" | "callout" | "calloutTitle" | "collapsible" | "collapsibleTitle";
209
208
  type RichTextClassMap = Partial<Record<RichTextClassKey, string>> & {
210
209
  /** Variant overrides keyed as `${matchKey}:${variant}`, e.g. "callout:warning". */
211
210
  variants?: Record<string, string>;
@@ -217,13 +216,119 @@ interface RichTextContentProps {
217
216
  /** Wrapper element. Defaults to `div`. Use `article` for blog content. */
218
217
  as?: keyof React.JSX.IntrinsicElements;
219
218
  className?: string;
219
+ /**
220
+ * Fires after the parsed HTML is in the DOM and post-render enhancements
221
+ * (syntax highlighting, copy buttons, blockquote decorations) have run.
222
+ * The wrapper element is passed back so callers can read headings, attach
223
+ * a ToC observer, or do other DOM work without re-querying.
224
+ */
225
+ onReady?: (root: HTMLElement) => void;
226
+ /**
227
+ * Optional ref to the wrapper element. Useful for hooks like
228
+ * `useTableOfContents` that need a stable reference to the rendered tree.
229
+ */
230
+ contentRef?: React.MutableRefObject<HTMLElement | null>;
231
+ /**
232
+ * Per-variant icon override for callouts that opt into icons via
233
+ * `data-icon`. Provide a React element for any variant key — these
234
+ * elements are rendered into the chip via a portal, so they live in
235
+ * React land (refs, event handlers, theme context all work). Variants
236
+ * you don't provide fall back to the built-in SVG glyph.
237
+ *
238
+ * Common variants: `"info" | "warning" | "success" | "danger" | "default"`.
239
+ * Custom variant names work too — anything you set via
240
+ * `data-variant` on an `<aside data-callout>`.
241
+ *
242
+ * Example:
243
+ * ```tsx
244
+ * import { Info, AlertTriangle } from "lucide-react";
245
+ *
246
+ * <RichTextContent
247
+ * html={article.doc}
248
+ * calloutIcons={{
249
+ * info: <Info size={14} strokeWidth={2.4} />,
250
+ * warning: <AlertTriangle size={14} strokeWidth={2.4} />,
251
+ * }}
252
+ * />
253
+ * ```
254
+ */
255
+ calloutIcons?: Partial<Record<string, ReactNode>>;
220
256
  }
221
- declare function RichTextContent({ html, classMap, as, className, }: RichTextContentProps): react.DOMElement<{
222
- ref: react.MutableRefObject<HTMLElement | null>;
223
- className: string | undefined;
224
- dangerouslySetInnerHTML: {
225
- __html: string;
226
- };
227
- }, HTMLElement>;
257
+ declare function RichTextContent({ html, classMap, as, className, onReady, contentRef, calloutIcons, }: RichTextContentProps): react_jsx_runtime.JSX.Element;
228
258
 
229
- export { AsteroidCMSProvider, type AsteroidCMSProviderProps, RichTextContent, type UseCmsContentOptions, type UseCmsMutateOptions, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate };
259
+ /**
260
+ * Heading extraction helpers used to build tables of contents (ToC) from
261
+ * rich-text HTML. Server-safe — no React, no DOM dependency in the HTML
262
+ * variant. The DOM variant assigns missing `id`s in-place so anchor links
263
+ * resolve immediately.
264
+ */
265
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
266
+ interface ExtractedHeading {
267
+ id: string;
268
+ text: string;
269
+ level: HeadingLevel;
270
+ }
271
+ interface ExtractHeadingsOptions {
272
+ /** Levels to include. Defaults to `[2, 3]` — typical doc page outline. */
273
+ levels?: ReadonlyArray<HeadingLevel>;
274
+ /** Custom slug function. Defaults to a lowercase/kebab/diacritic-safe slug. */
275
+ slugify?: (text: string, index: number) => string;
276
+ }
277
+ declare function slugify(text: string): string;
278
+ /**
279
+ * Parse headings out of a raw HTML string. Returns headings in document
280
+ * order with stable, de-duplicated IDs.
281
+ *
282
+ * If a heading already has an `id` attribute, it's preserved verbatim
283
+ * (and reserved so later slugs don't collide with it).
284
+ */
285
+ declare function extractHeadingsFromHtml(html: string, options?: ExtractHeadingsOptions): ExtractedHeading[];
286
+ /**
287
+ * Walk a rendered DOM subtree, collect headings, and assign missing `id`s
288
+ * in-place so anchor links resolve immediately. Also sets `scrollMarginTop`
289
+ * on each heading when `scrollMarginTop` is provided so navigation lands
290
+ * cleanly below a sticky header.
291
+ */
292
+ declare function extractHeadingsFromElement(root: HTMLElement, options?: ExtractHeadingsOptions & {
293
+ scrollMarginTop?: number;
294
+ }): ExtractedHeading[];
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 };
package/dist/client.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as react from 'react';
3
- import { PropsWithChildren } from 'react';
2
+ import { PropsWithChildren, ReactNode, RefObject } from 'react';
4
3
  import * as _apollo_client from '@apollo/client';
5
4
  import { InMemoryCacheConfig, ApolloClientOptions, ApolloClient } from '@apollo/client';
6
5
  import { useMutation } from '@apollo/client/react';
@@ -205,7 +204,7 @@ declare function useCmsImage(): (id?: string) => string;
205
204
  *
206
205
  * Idempotent: parseRichText(parseRichText(x, opts), opts) === parseRichText(x, opts).
207
206
  */
208
- type RichTextClassKey = "p" | "br" | "hr" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "ul" | "ol" | "li" | "blockquote" | "pre" | "code" | "inlineCode" | "a" | "strong" | "em" | "u" | "s" | "kbd" | "table" | "tableWrapper" | "thead" | "tbody" | "tr" | "th" | "td" | "figure" | "figcaption" | "img" | "span" | "callout" | "calloutTitle";
207
+ type RichTextClassKey = "p" | "br" | "hr" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "ul" | "ol" | "li" | "blockquote" | "pre" | "code" | "inlineCode" | "a" | "strong" | "em" | "u" | "s" | "kbd" | "table" | "tableWrapper" | "thead" | "tbody" | "tr" | "th" | "td" | "figure" | "figcaption" | "img" | "span" | "callout" | "calloutTitle" | "collapsible" | "collapsibleTitle";
209
208
  type RichTextClassMap = Partial<Record<RichTextClassKey, string>> & {
210
209
  /** Variant overrides keyed as `${matchKey}:${variant}`, e.g. "callout:warning". */
211
210
  variants?: Record<string, string>;
@@ -217,13 +216,119 @@ interface RichTextContentProps {
217
216
  /** Wrapper element. Defaults to `div`. Use `article` for blog content. */
218
217
  as?: keyof React.JSX.IntrinsicElements;
219
218
  className?: string;
219
+ /**
220
+ * Fires after the parsed HTML is in the DOM and post-render enhancements
221
+ * (syntax highlighting, copy buttons, blockquote decorations) have run.
222
+ * The wrapper element is passed back so callers can read headings, attach
223
+ * a ToC observer, or do other DOM work without re-querying.
224
+ */
225
+ onReady?: (root: HTMLElement) => void;
226
+ /**
227
+ * Optional ref to the wrapper element. Useful for hooks like
228
+ * `useTableOfContents` that need a stable reference to the rendered tree.
229
+ */
230
+ contentRef?: React.MutableRefObject<HTMLElement | null>;
231
+ /**
232
+ * Per-variant icon override for callouts that opt into icons via
233
+ * `data-icon`. Provide a React element for any variant key — these
234
+ * elements are rendered into the chip via a portal, so they live in
235
+ * React land (refs, event handlers, theme context all work). Variants
236
+ * you don't provide fall back to the built-in SVG glyph.
237
+ *
238
+ * Common variants: `"info" | "warning" | "success" | "danger" | "default"`.
239
+ * Custom variant names work too — anything you set via
240
+ * `data-variant` on an `<aside data-callout>`.
241
+ *
242
+ * Example:
243
+ * ```tsx
244
+ * import { Info, AlertTriangle } from "lucide-react";
245
+ *
246
+ * <RichTextContent
247
+ * html={article.doc}
248
+ * calloutIcons={{
249
+ * info: <Info size={14} strokeWidth={2.4} />,
250
+ * warning: <AlertTriangle size={14} strokeWidth={2.4} />,
251
+ * }}
252
+ * />
253
+ * ```
254
+ */
255
+ calloutIcons?: Partial<Record<string, ReactNode>>;
220
256
  }
221
- declare function RichTextContent({ html, classMap, as, className, }: RichTextContentProps): react.DOMElement<{
222
- ref: react.MutableRefObject<HTMLElement | null>;
223
- className: string | undefined;
224
- dangerouslySetInnerHTML: {
225
- __html: string;
226
- };
227
- }, HTMLElement>;
257
+ declare function RichTextContent({ html, classMap, as, className, onReady, contentRef, calloutIcons, }: RichTextContentProps): react_jsx_runtime.JSX.Element;
228
258
 
229
- export { AsteroidCMSProvider, type AsteroidCMSProviderProps, RichTextContent, type UseCmsContentOptions, type UseCmsMutateOptions, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate };
259
+ /**
260
+ * Heading extraction helpers used to build tables of contents (ToC) from
261
+ * rich-text HTML. Server-safe — no React, no DOM dependency in the HTML
262
+ * variant. The DOM variant assigns missing `id`s in-place so anchor links
263
+ * resolve immediately.
264
+ */
265
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
266
+ interface ExtractedHeading {
267
+ id: string;
268
+ text: string;
269
+ level: HeadingLevel;
270
+ }
271
+ interface ExtractHeadingsOptions {
272
+ /** Levels to include. Defaults to `[2, 3]` — typical doc page outline. */
273
+ levels?: ReadonlyArray<HeadingLevel>;
274
+ /** Custom slug function. Defaults to a lowercase/kebab/diacritic-safe slug. */
275
+ slugify?: (text: string, index: number) => string;
276
+ }
277
+ declare function slugify(text: string): string;
278
+ /**
279
+ * Parse headings out of a raw HTML string. Returns headings in document
280
+ * order with stable, de-duplicated IDs.
281
+ *
282
+ * If a heading already has an `id` attribute, it's preserved verbatim
283
+ * (and reserved so later slugs don't collide with it).
284
+ */
285
+ declare function extractHeadingsFromHtml(html: string, options?: ExtractHeadingsOptions): ExtractedHeading[];
286
+ /**
287
+ * Walk a rendered DOM subtree, collect headings, and assign missing `id`s
288
+ * in-place so anchor links resolve immediately. Also sets `scrollMarginTop`
289
+ * on each heading when `scrollMarginTop` is provided so navigation lands
290
+ * cleanly below a sticky header.
291
+ */
292
+ declare function extractHeadingsFromElement(root: HTMLElement, options?: ExtractHeadingsOptions & {
293
+ scrollMarginTop?: number;
294
+ }): ExtractedHeading[];
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 };