@nswds/app 1.74.0 → 1.76.0

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/index.cjs CHANGED
@@ -17465,16 +17465,33 @@ function FormatToggle({ format, setFormat }) {
17465
17465
 
17466
17466
  // package.json
17467
17467
  var package_default = {
17468
- version: "1.73.0"};
17468
+ version: "1.75.0"};
17469
+ var SluggerContext = React5__namespace.default.createContext(null);
17470
+ function flattenText(nodes) {
17471
+ if (nodes == null || typeof nodes === "boolean") return "";
17472
+ if (typeof nodes === "string" || typeof nodes === "number" || typeof nodes === "bigint")
17473
+ return String(nodes);
17474
+ if (Array.isArray(nodes)) return nodes.map(flattenText).join("");
17475
+ if (React5__namespace.default.isValidElement(nodes)) {
17476
+ return flattenText(nodes.props.children);
17477
+ }
17478
+ return "";
17479
+ }
17480
+ function baseSlug(input) {
17481
+ return input.toLowerCase().trim().replace(/[\s\W]+/g, "-").replace(/^-+|-+$/g, "");
17482
+ }
17469
17483
  function Heading({
17470
17484
  className,
17471
17485
  trim = "normal",
17472
17486
  size = 1,
17473
17487
  level = 1,
17474
17488
  display = false,
17489
+ id: idProp,
17490
+ children,
17475
17491
  ...props
17476
17492
  }) {
17477
- const Element2 = `h${level}`;
17493
+ const Tag = `h${level}`;
17494
+ const slugger = React5.useContext(SluggerContext);
17478
17495
  const headingSizeClasses = {
17479
17496
  1: "text-[calc(var(--heading-font-size-1)_*_var(--heading-font-size-adjust))] leading-[var(--line-height-52)] tracking-[calc(var(--heading-letter-spacing-2)_+_var(--heading-letter-spacing))]",
17480
17497
  2: "text-[calc(var(--heading-font-size-2)_*_var(--heading-font-size-adjust))] leading-[var(--line-height-44)] tracking-[calc(var(--heading-letter-spacing-2)_+_var(--heading-letter-spacing))]",
@@ -17506,10 +17523,19 @@ function Heading({
17506
17523
  "after:mt-[calc(var(--leading-trim-end,var(--default-leading-trim-end))-var(--line-height,calc(1em*var(--default-line-height)))/2)]"
17507
17524
  ]
17508
17525
  };
17526
+ const computedId = React5.useMemo(() => {
17527
+ if (idProp) return idProp;
17528
+ const text = flattenText(children);
17529
+ if (!text) return void 0;
17530
+ const base = baseSlug(text);
17531
+ return slugger ? slugger.slug(base) : base;
17532
+ }, [idProp, children, slugger]);
17509
17533
  return /* @__PURE__ */ jsxRuntime.jsx(
17510
- Element2,
17534
+ Tag,
17511
17535
  {
17512
17536
  ...props,
17537
+ id: computedId,
17538
+ "data-anchor": true,
17513
17539
  className: clsx12__default.default(
17514
17540
  className,
17515
17541
  trimClasses[trim],
@@ -17518,7 +17544,8 @@ function Heading({
17518
17544
  "[--leading-trim-end:var(--heading-leading-trim-end)] [--leading-trim-start:var(--heading-leading-trim-start)]",
17519
17545
  "text-primary-800 dark:text-white",
17520
17546
  sizeClass
17521
- )
17547
+ ),
17548
+ children
17522
17549
  }
17523
17550
  );
17524
17551
  }
@@ -29909,9 +29936,12 @@ function useActiveSectionObserver(tableOfContents) {
29909
29936
  return currentSection;
29910
29937
  }
29911
29938
  function TableOfContents({ tableOfContents }) {
29912
- const [mounted, setMounted] = React5.useState(false);
29913
- React5.useEffect(() => setMounted(true), []);
29914
- const currentSection = useActiveSectionObserver(mounted ? tableOfContents : []);
29939
+ const [ready, setReady] = React5.useState(false);
29940
+ React5.useEffect(() => {
29941
+ const raf = requestAnimationFrame(() => setReady(true));
29942
+ return () => cancelAnimationFrame(raf);
29943
+ }, []);
29944
+ const currentSection = useActiveSectionObserver(ready ? tableOfContents : []);
29915
29945
  const isActive = React5.useMemo(() => {
29916
29946
  const check = (section) => {
29917
29947
  if (section.id === currentSection) return true;
@@ -29919,8 +29949,8 @@ function TableOfContents({ tableOfContents }) {
29919
29949
  };
29920
29950
  return check;
29921
29951
  }, [currentSection]);
29922
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-labelledby": "on-this-page-title", className: "w-56", suppressHydrationWarning: true, children: !mounted ? (
29923
- // lightweight placeholder to avoid layout shift (optional)
29952
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-labelledby": "on-this-page-title", className: "w-56", suppressHydrationWarning: true, children: !ready ? (
29953
+ // SSR + initial client paint: deterministic skeleton
29924
29954
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "aria-hidden": true, className: "mt-3 space-y-2", children: [
29925
29955
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-40 animate-pulse rounded bg-black/10 dark:bg-white/10" }),
29926
29956
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-32 animate-pulse rounded bg-black/10 dark:bg-white/10" }),
@@ -30645,12 +30675,56 @@ function getHeadings(slugify$1 = slugify.slugifyWithCounter()) {
30645
30675
  function usePageHeadings() {
30646
30676
  const [headings, setHeadings] = React5.useState([]);
30647
30677
  const pathname = navigation.usePathname();
30678
+ const observerRef = React5.useRef(null);
30679
+ const observedElRef = React5.useRef(null);
30648
30680
  React5.useEffect(() => {
30649
- const timer = setTimeout(() => {
30650
- const result = getHeadings();
30651
- setHeadings(result);
30652
- }, 0);
30653
- return () => clearTimeout(timer);
30681
+ const update = () => setHeadings(getHeadings());
30682
+ const attachToCurrentArticle = () => {
30683
+ const article = document.querySelector("article");
30684
+ if (!article || observedElRef.current === article) return;
30685
+ observerRef.current?.disconnect();
30686
+ const obs = new MutationObserver(() => {
30687
+ update();
30688
+ });
30689
+ obs.observe(article, {
30690
+ childList: true,
30691
+ subtree: true,
30692
+ attributes: true,
30693
+ attributeFilter: ["id"]
30694
+ });
30695
+ observerRef.current = obs;
30696
+ observedElRef.current = article;
30697
+ requestAnimationFrame(update);
30698
+ };
30699
+ attachToCurrentArticle();
30700
+ const articleParent = document.querySelector("article")?.parentElement;
30701
+ const rootObserver = new MutationObserver((mutations) => {
30702
+ for (const mutation of mutations) {
30703
+ for (const node of Array.from(mutation.addedNodes)) {
30704
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === "article") {
30705
+ attachToCurrentArticle();
30706
+ return;
30707
+ }
30708
+ }
30709
+ for (const node of Array.from(mutation.removedNodes)) {
30710
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === "article") {
30711
+ attachToCurrentArticle();
30712
+ return;
30713
+ }
30714
+ }
30715
+ }
30716
+ });
30717
+ if (articleParent) {
30718
+ rootObserver.observe(articleParent, { childList: true });
30719
+ } else {
30720
+ rootObserver.observe(document.body, { childList: true });
30721
+ }
30722
+ return () => {
30723
+ rootObserver.disconnect();
30724
+ observerRef.current?.disconnect();
30725
+ observerRef.current = null;
30726
+ observedElRef.current = null;
30727
+ };
30654
30728
  }, [pathname]);
30655
30729
  return headings;
30656
30730
  }