@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.d.cts CHANGED
@@ -1192,19 +1192,20 @@ declare function Header({ children, sitename, navigation, version, hide, }: {
1192
1192
  };
1193
1193
  }): react_jsx_runtime.JSX.Element;
1194
1194
 
1195
- type BaseProps$1 = React.ComponentPropsWithoutRef<'h1'>;
1195
+ type BaseProps$1 = React__default.ComponentPropsWithoutRef<'h1'>;
1196
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
1196
1197
  type HeadingProps = ({
1197
1198
  display?: false;
1198
1199
  size?: 1 | 2 | 3 | 4 | 5 | 6;
1199
1200
  trim?: 'normal' | 'start' | 'end' | 'both';
1200
- level?: 1 | 2 | 3 | 4 | 5 | 6;
1201
+ level?: HeadingLevel;
1201
1202
  } & BaseProps$1) | ({
1202
1203
  display: true;
1203
1204
  size?: 1 | 2 | 3 | 4;
1204
- level?: 1 | 2 | 3 | 4 | 5 | 6;
1205
+ level?: HeadingLevel;
1205
1206
  trim?: 'normal' | 'start' | 'end' | 'both';
1206
1207
  } & BaseProps$1);
1207
- declare function Heading({ className, trim, size, level, display, ...props }: HeadingProps): react_jsx_runtime.JSX.Element;
1208
+ declare function Heading({ className, trim, size, level, display, id: idProp, children, ...props }: HeadingProps): react_jsx_runtime.JSX.Element;
1208
1209
 
1209
1210
  declare const heroBannerVariants: (props?: ({
1210
1211
  variant?: "white" | "primary-800" | "grey-150" | "accent-800" | "primary-200" | null | undefined;
package/dist/index.d.ts CHANGED
@@ -1192,19 +1192,20 @@ declare function Header({ children, sitename, navigation, version, hide, }: {
1192
1192
  };
1193
1193
  }): react_jsx_runtime.JSX.Element;
1194
1194
 
1195
- type BaseProps$1 = React.ComponentPropsWithoutRef<'h1'>;
1195
+ type BaseProps$1 = React__default.ComponentPropsWithoutRef<'h1'>;
1196
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
1196
1197
  type HeadingProps = ({
1197
1198
  display?: false;
1198
1199
  size?: 1 | 2 | 3 | 4 | 5 | 6;
1199
1200
  trim?: 'normal' | 'start' | 'end' | 'both';
1200
- level?: 1 | 2 | 3 | 4 | 5 | 6;
1201
+ level?: HeadingLevel;
1201
1202
  } & BaseProps$1) | ({
1202
1203
  display: true;
1203
1204
  size?: 1 | 2 | 3 | 4;
1204
- level?: 1 | 2 | 3 | 4 | 5 | 6;
1205
+ level?: HeadingLevel;
1205
1206
  trim?: 'normal' | 'start' | 'end' | 'both';
1206
1207
  } & BaseProps$1);
1207
- declare function Heading({ className, trim, size, level, display, ...props }: HeadingProps): react_jsx_runtime.JSX.Element;
1208
+ declare function Heading({ className, trim, size, level, display, id: idProp, children, ...props }: HeadingProps): react_jsx_runtime.JSX.Element;
1208
1209
 
1209
1210
  declare const heroBannerVariants: (props?: ({
1210
1211
  variant?: "white" | "primary-800" | "grey-150" | "accent-800" | "primary-200" | null | undefined;
package/dist/index.js CHANGED
@@ -17412,16 +17412,33 @@ function FormatToggle({ format, setFormat }) {
17412
17412
 
17413
17413
  // package.json
17414
17414
  var package_default = {
17415
- version: "1.73.0"};
17415
+ version: "1.75.0"};
17416
+ var SluggerContext = React5__default.createContext(null);
17417
+ function flattenText(nodes) {
17418
+ if (nodes == null || typeof nodes === "boolean") return "";
17419
+ if (typeof nodes === "string" || typeof nodes === "number" || typeof nodes === "bigint")
17420
+ return String(nodes);
17421
+ if (Array.isArray(nodes)) return nodes.map(flattenText).join("");
17422
+ if (React5__default.isValidElement(nodes)) {
17423
+ return flattenText(nodes.props.children);
17424
+ }
17425
+ return "";
17426
+ }
17427
+ function baseSlug(input) {
17428
+ return input.toLowerCase().trim().replace(/[\s\W]+/g, "-").replace(/^-+|-+$/g, "");
17429
+ }
17416
17430
  function Heading({
17417
17431
  className,
17418
17432
  trim = "normal",
17419
17433
  size = 1,
17420
17434
  level = 1,
17421
17435
  display = false,
17436
+ id: idProp,
17437
+ children,
17422
17438
  ...props
17423
17439
  }) {
17424
- const Element2 = `h${level}`;
17440
+ const Tag = `h${level}`;
17441
+ const slugger = useContext(SluggerContext);
17425
17442
  const headingSizeClasses = {
17426
17443
  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))]",
17427
17444
  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))]",
@@ -17453,10 +17470,19 @@ function Heading({
17453
17470
  "after:mt-[calc(var(--leading-trim-end,var(--default-leading-trim-end))-var(--line-height,calc(1em*var(--default-line-height)))/2)]"
17454
17471
  ]
17455
17472
  };
17473
+ const computedId = useMemo(() => {
17474
+ if (idProp) return idProp;
17475
+ const text = flattenText(children);
17476
+ if (!text) return void 0;
17477
+ const base = baseSlug(text);
17478
+ return slugger ? slugger.slug(base) : base;
17479
+ }, [idProp, children, slugger]);
17456
17480
  return /* @__PURE__ */ jsx(
17457
- Element2,
17481
+ Tag,
17458
17482
  {
17459
17483
  ...props,
17484
+ id: computedId,
17485
+ "data-anchor": true,
17460
17486
  className: clsx12(
17461
17487
  className,
17462
17488
  trimClasses[trim],
@@ -17465,7 +17491,8 @@ function Heading({
17465
17491
  "[--leading-trim-end:var(--heading-leading-trim-end)] [--leading-trim-start:var(--heading-leading-trim-start)]",
17466
17492
  "text-primary-800 dark:text-white",
17467
17493
  sizeClass
17468
- )
17494
+ ),
17495
+ children
17469
17496
  }
17470
17497
  );
17471
17498
  }
@@ -29856,9 +29883,12 @@ function useActiveSectionObserver(tableOfContents) {
29856
29883
  return currentSection;
29857
29884
  }
29858
29885
  function TableOfContents({ tableOfContents }) {
29859
- const [mounted, setMounted] = useState(false);
29860
- useEffect(() => setMounted(true), []);
29861
- const currentSection = useActiveSectionObserver(mounted ? tableOfContents : []);
29886
+ const [ready, setReady] = useState(false);
29887
+ useEffect(() => {
29888
+ const raf = requestAnimationFrame(() => setReady(true));
29889
+ return () => cancelAnimationFrame(raf);
29890
+ }, []);
29891
+ const currentSection = useActiveSectionObserver(ready ? tableOfContents : []);
29862
29892
  const isActive = useMemo(() => {
29863
29893
  const check = (section) => {
29864
29894
  if (section.id === currentSection) return true;
@@ -29866,8 +29896,8 @@ function TableOfContents({ tableOfContents }) {
29866
29896
  };
29867
29897
  return check;
29868
29898
  }, [currentSection]);
29869
- return /* @__PURE__ */ jsx("nav", { "aria-labelledby": "on-this-page-title", className: "w-56", suppressHydrationWarning: true, children: !mounted ? (
29870
- // lightweight placeholder to avoid layout shift (optional)
29899
+ return /* @__PURE__ */ jsx("nav", { "aria-labelledby": "on-this-page-title", className: "w-56", suppressHydrationWarning: true, children: !ready ? (
29900
+ // SSR + initial client paint: deterministic skeleton
29871
29901
  /* @__PURE__ */ jsxs("div", { "aria-hidden": true, className: "mt-3 space-y-2", children: [
29872
29902
  /* @__PURE__ */ jsx("div", { className: "h-4 w-40 animate-pulse rounded bg-black/10 dark:bg-white/10" }),
29873
29903
  /* @__PURE__ */ jsx("div", { className: "h-3 w-32 animate-pulse rounded bg-black/10 dark:bg-white/10" }),
@@ -30592,12 +30622,56 @@ function getHeadings(slugify = slugifyWithCounter()) {
30592
30622
  function usePageHeadings() {
30593
30623
  const [headings, setHeadings] = useState([]);
30594
30624
  const pathname = usePathname();
30625
+ const observerRef = useRef(null);
30626
+ const observedElRef = useRef(null);
30595
30627
  useEffect(() => {
30596
- const timer = setTimeout(() => {
30597
- const result = getHeadings();
30598
- setHeadings(result);
30599
- }, 0);
30600
- return () => clearTimeout(timer);
30628
+ const update = () => setHeadings(getHeadings());
30629
+ const attachToCurrentArticle = () => {
30630
+ const article = document.querySelector("article");
30631
+ if (!article || observedElRef.current === article) return;
30632
+ observerRef.current?.disconnect();
30633
+ const obs = new MutationObserver(() => {
30634
+ update();
30635
+ });
30636
+ obs.observe(article, {
30637
+ childList: true,
30638
+ subtree: true,
30639
+ attributes: true,
30640
+ attributeFilter: ["id"]
30641
+ });
30642
+ observerRef.current = obs;
30643
+ observedElRef.current = article;
30644
+ requestAnimationFrame(update);
30645
+ };
30646
+ attachToCurrentArticle();
30647
+ const articleParent = document.querySelector("article")?.parentElement;
30648
+ const rootObserver = new MutationObserver((mutations) => {
30649
+ for (const mutation of mutations) {
30650
+ for (const node of Array.from(mutation.addedNodes)) {
30651
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === "article") {
30652
+ attachToCurrentArticle();
30653
+ return;
30654
+ }
30655
+ }
30656
+ for (const node of Array.from(mutation.removedNodes)) {
30657
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === "article") {
30658
+ attachToCurrentArticle();
30659
+ return;
30660
+ }
30661
+ }
30662
+ }
30663
+ });
30664
+ if (articleParent) {
30665
+ rootObserver.observe(articleParent, { childList: true });
30666
+ } else {
30667
+ rootObserver.observe(document.body, { childList: true });
30668
+ }
30669
+ return () => {
30670
+ rootObserver.disconnect();
30671
+ observerRef.current?.disconnect();
30672
+ observerRef.current = null;
30673
+ observedElRef.current = null;
30674
+ };
30601
30675
  }, [pathname]);
30602
30676
  return headings;
30603
30677
  }