@homebound/beam 3.71.0 → 3.72.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
@@ -10274,8 +10274,9 @@ type WorkflowLayoutProps = Pick<BaseHeaderProps, "title" | "documentTitleSuffix"
10274
10274
  *
10275
10275
  * A standalone, full-page layout for step-based workflow pages — nest it directly under
10276
10276
  * `EnvironmentBannerLayout`, never under `NavbarLayout`/`SideNavLayout`/`PageHeaderLayout`. Unlike
10277
- * `PageHeaderLayout`, the header here never auto-hides; the stepper tabs collapse to a condensed
10278
- * indicator bar on mobile instead.
10277
+ * `PageHeaderLayout`, the header here never auto-hides. The stepper tabs always collapse to a condensed
10278
+ * indicator bar on mobile, and on larger viewports also collapse once scrolled past a threshold,
10279
+ * re-expanding on scroll-up (even before reaching the top).
10279
10280
  *
10280
10281
  * Owns the workflow's fixed CTA set (Back/Cancel/Save & Exit/Continue-or-Complete) via `WorkflowActions`
10281
10282
  * so it can move them into a mobile footer at the `sm` breakpoint — `WorkflowHeader` itself is not part
package/dist/index.d.ts CHANGED
@@ -10274,8 +10274,9 @@ type WorkflowLayoutProps = Pick<BaseHeaderProps, "title" | "documentTitleSuffix"
10274
10274
  *
10275
10275
  * A standalone, full-page layout for step-based workflow pages — nest it directly under
10276
10276
  * `EnvironmentBannerLayout`, never under `NavbarLayout`/`SideNavLayout`/`PageHeaderLayout`. Unlike
10277
- * `PageHeaderLayout`, the header here never auto-hides; the stepper tabs collapse to a condensed
10278
- * indicator bar on mobile instead.
10277
+ * `PageHeaderLayout`, the header here never auto-hides. The stepper tabs always collapse to a condensed
10278
+ * indicator bar on mobile, and on larger viewports also collapse once scrolled past a threshold,
10279
+ * re-expanding on scroll-up (even before reaching the top).
10279
10280
  *
10280
10281
  * Owns the workflow's fixed CTA set (Back/Cancel/Save & Exit/Continue-or-Complete) via `WorkflowActions`
10281
10282
  * so it can move them into a mobile footer at the `sm` breakpoint — `WorkflowHeader` itself is not part
package/dist/index.js CHANGED
@@ -26469,7 +26469,7 @@ function PageHeaderLayout(props) {
26469
26469
  }
26470
26470
 
26471
26471
  // src/layouts/WorkflowLayout/WorkflowLayout.tsx
26472
- import { useLayoutEffect as useLayoutEffect10, useRef as useRef68, useState as useState59 } from "react";
26472
+ import { useLayoutEffect as useLayoutEffect11, useRef as useRef69, useState as useState60 } from "react";
26473
26473
 
26474
26474
  // src/components/Headers/WorkflowHeader.tsx
26475
26475
  import { jsx as jsx215 } from "react/jsx-runtime";
@@ -26479,14 +26479,65 @@ function WorkflowHeader(props) {
26479
26479
  return /* @__PURE__ */ jsx215(BaseHeader, { ...otherProps, bottomSlot: /* @__PURE__ */ jsx215(StepperTabs, { ...stepperTabs, ...tid.stepperTabs }) });
26480
26480
  }
26481
26481
 
26482
+ // src/layouts/useScrollCollapse.ts
26483
+ import { useLayoutEffect as useLayoutEffect10, useRef as useRef67, useState as useState59 } from "react";
26484
+ function useScrollCollapse(enabled, restingOffset) {
26485
+ const [collapsed, setCollapsed] = useState59(() => typeof window !== "undefined" && window.scrollY > 0);
26486
+ const collapsedRef = useRef67(collapsed);
26487
+ collapsedRef.current = collapsed;
26488
+ const restingOffsetRef = useRef67(restingOffset);
26489
+ restingOffsetRef.current = restingOffset;
26490
+ const lastScrollYRef = useRef67(Number.POSITIVE_INFINITY);
26491
+ const lastScrollHeightRef = useRef67(0);
26492
+ useLayoutEffect10(() => {
26493
+ lastScrollHeightRef.current = document.documentElement.scrollHeight;
26494
+ }, [restingOffset]);
26495
+ useLayoutEffect10(() => {
26496
+ if (!enabled) return;
26497
+ const commit = (next) => {
26498
+ if (next !== collapsedRef.current) {
26499
+ collapsedRef.current = next;
26500
+ setCollapsed(next);
26501
+ }
26502
+ };
26503
+ const updateCollapsed = () => {
26504
+ const doc = document.documentElement;
26505
+ const currentY = window.scrollY;
26506
+ if (currentY <= 0) {
26507
+ lastScrollYRef.current = 0;
26508
+ lastScrollHeightRef.current = doc.scrollHeight;
26509
+ commit(false);
26510
+ return;
26511
+ }
26512
+ const currentScrollHeight = doc.scrollHeight;
26513
+ const scrollHeightChanged = lastScrollHeightRef.current !== 0 && currentScrollHeight !== lastScrollHeightRef.current;
26514
+ const dy = currentY - lastScrollYRef.current;
26515
+ lastScrollYRef.current = currentY;
26516
+ lastScrollHeightRef.current = currentScrollHeight;
26517
+ if (currentY <= restingOffsetRef.current) return;
26518
+ if (scrollHeightChanged) {
26519
+ commit(true);
26520
+ return;
26521
+ }
26522
+ const atBottom = currentY >= doc.scrollHeight - doc.clientHeight;
26523
+ if (dy > 0) commit(true);
26524
+ else if (dy < 0 && !atBottom) commit(false);
26525
+ };
26526
+ updateCollapsed();
26527
+ window.addEventListener("scroll", updateCollapsed, { passive: true });
26528
+ return () => window.removeEventListener("scroll", updateCollapsed);
26529
+ }, [enabled]);
26530
+ return collapsed;
26531
+ }
26532
+
26482
26533
  // src/layouts/WorkflowLayout/useUnsavedChangesGuard.tsx
26483
- import { useEffect as useEffect38, useRef as useRef67 } from "react";
26534
+ import { useEffect as useEffect38, useRef as useRef68 } from "react";
26484
26535
  import { useBlocker } from "react-router-dom";
26485
26536
  import { jsx as jsx216 } from "react/jsx-runtime";
26486
26537
  function useUnsavedChangesGuard(options) {
26487
26538
  const { isDirty, onCancel } = options;
26488
26539
  const { openModal } = useModal();
26489
- const isDirtyRef = useRef67(isDirty);
26540
+ const isDirtyRef = useRef68(isDirty);
26490
26541
  isDirtyRef.current = isDirty;
26491
26542
  useEffect38(() => {
26492
26543
  const onBeforeUnload = (e) => {
@@ -26570,7 +26621,7 @@ function WorkflowLayout(props) {
26570
26621
  ...step,
26571
26622
  value: defaultTestId(step.label)
26572
26623
  }));
26573
- const [currentStep, setCurrentStep] = useState59(() => getInitialStep(tabSteps, defaultStep));
26624
+ const [currentStep, setCurrentStep] = useState60(() => getInitialStep(tabSteps, defaultStep));
26574
26625
  const tid = useTestIds(props, "workflowLayout");
26575
26626
  const {
26576
26627
  sm: isMobile
@@ -26582,9 +26633,11 @@ function WorkflowLayout(props) {
26582
26633
  isDirty,
26583
26634
  onCancel
26584
26635
  });
26585
- const headerMetricsRef = useRef68(null);
26636
+ const bannerAndNavbarHeight = useBannerAndNavbarHeight();
26637
+ const headerMetricsRef = useRef69(null);
26586
26638
  const headerHeight = useMeasuredHeight(headerMetricsRef, true);
26587
- const collapsed = isMobile;
26639
+ const scrollCollapsed = useScrollCollapse(!isMobile, bannerAndNavbarHeight + headerHeight);
26640
+ const collapsed = isMobile || scrollCollapsed;
26588
26641
  const headerWidth = documentScrollChromeWidth();
26589
26642
  const outerTop = bannerAndNavbarChromeTop();
26590
26643
  const cssVars = headerHeight > 0 ? {
@@ -26603,7 +26656,7 @@ function WorkflowLayout(props) {
26603
26656
  setCurrentStep(tabSteps[currentIndex + 1].value);
26604
26657
  } });
26605
26658
  const showFooter = isMobile;
26606
- useLayoutEffect10(() => {
26659
+ useLayoutEffect11(() => {
26607
26660
  const root = document.documentElement;
26608
26661
  const previous = root.style.getPropertyValue(beamWorkflowLayoutFooterHeightVar);
26609
26662
  root.style.setProperty(beamWorkflowLayoutFooterHeightVar, showFooter ? `${mobileFooterHeightPx}px` : "0px");