@elaraai/east-ui-components 1.0.7 → 1.0.8

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
@@ -47439,8 +47439,8 @@ function Plot({ node: node2, style, brush, onBrushEnd, brushKey }) {
47439
47439
  const maxSize = sizeVals.length ? Math.max(...sizeVals) : 0;
47440
47440
  const sizeScale = maxSize > 0 ? createSqrtScale({ domain: [0, maxSize], range: [0, 16] }) : void 0;
47441
47441
  const sizeR = sizeScale ? (v2) => Math.max(3, sizeScale(v2) ?? 3) : void 0;
47442
- const render3 = (w2) => {
47443
- const svgH = f2.height - legendH;
47442
+ const render3 = (w2, hOverride) => {
47443
+ const svgH = (hOverride ?? f2.height) - legendH;
47444
47444
  const innerW = Math.max(0, w2 - margin.left - margin.right);
47445
47445
  const innerH = Math.max(0, svgH - margin.top - margin.bottom);
47446
47446
  const mkY = (dom2, dMin, dMax) => dom2 ? createLinearScale({ domain: dom2, range: [innerH, 0] }) : createLinearScale({ domain: [Math.min(0, dMin), dMax || 1], range: [innerH, 0], nice: true });
@@ -47546,6 +47546,9 @@ function Plot({ node: node2, style, brush, onBrushEnd, brushKey }) {
47546
47546
  ] }) })
47547
47547
  ] });
47548
47548
  };
47549
+ if (f2.height <= 0) {
47550
+ return /* @__PURE__ */ jsxRuntime.jsx(ParentSize, { children: ({ width, height }) => render3(width || 320, height || 240) });
47551
+ }
47549
47552
  return explicitW !== void 0 ? render3(explicitW) : /* @__PURE__ */ jsxRuntime.jsx(ParentSize, { children: ({ width }) => render3(width || 320) });
47550
47553
  }
47551
47554
  }, null);
@@ -49669,6 +49672,596 @@ const EastChakraTabs = React.memo(function EastChakraTabs2({ value, storageKey }
49669
49672
  }
49670
49673
  );
49671
49674
  }, (prev, next) => tabsEqual(prev.value, next.value) && prev.storageKey === next.storageKey);
49675
+ const storyEqual = east.equalFor(internal.Story.Types.Story);
49676
+ const storyStepEqual = east.equalFor(internal.Story.Types.Step);
49677
+ const storyProgressEqual = east.equalFor(internal.Story.Types.Progress);
49678
+ function isStaticForScrollport(value) {
49679
+ return getSomeorUndefined(value.activeStep) !== void 0;
49680
+ }
49681
+ const TRIGGER_LINE = 0.38;
49682
+ const NAV_OFFSET = 0.3;
49683
+ const STACK_BREAKPOINT = 720;
49684
+ const STEP_RUNWAY_VH = { compact: 36, default: 52, long: 72 };
49685
+ const DEFAULT_STAGE_HEIGHT = "420px";
49686
+ const STACKED_STAGE_CAP = "280px";
49687
+ let warnedNonStepChild = false;
49688
+ function extractSteps(children) {
49689
+ const steps = [];
49690
+ for (const child of children) {
49691
+ const tagged = child;
49692
+ if (tagged.type === "StoryStep") {
49693
+ const step = tagged.value;
49694
+ steps.push({
49695
+ id: step.id,
49696
+ eyebrow: getSomeorUndefined(step.eyebrow),
49697
+ title: getSomeorUndefined(step.title),
49698
+ stage: getSomeorUndefined(step.stage),
49699
+ body: step.body
49700
+ });
49701
+ } else if (!warnedNonStepChild) {
49702
+ warnedNonStepChild = true;
49703
+ console.warn(`Story: skipping non-StoryStep child (got '${tagged.type}'). Story children should be Story.Step components.`);
49704
+ }
49705
+ }
49706
+ return steps;
49707
+ }
49708
+ function keyframeOwner(steps, active) {
49709
+ var _a2;
49710
+ for (let i2 = Math.min(active, steps.length - 1); i2 >= 0; i2--) {
49711
+ if (((_a2 = steps[i2]) == null ? void 0 : _a2.stage) !== void 0) return i2;
49712
+ }
49713
+ return -1;
49714
+ }
49715
+ function getScrollParent(el) {
49716
+ let p2 = (el == null ? void 0 : el.parentElement) ?? null;
49717
+ while (p2) {
49718
+ const oy = getComputedStyle(p2).overflowY;
49719
+ if (oy === "auto" || oy === "scroll") return p2;
49720
+ p2 = p2.parentElement;
49721
+ }
49722
+ return null;
49723
+ }
49724
+ function useActiveBindingValue(binding) {
49725
+ const subscribe2 = React.useCallback((cb) => {
49726
+ if (!binding) return () => {
49727
+ };
49728
+ return getStore().subscribe(cb);
49729
+ }, [binding]);
49730
+ const getSnapshot2 = React.useCallback(() => binding ? Number(binding.read()) : -1, [binding]);
49731
+ const snapshot = React.useSyncExternalStore(subscribe2, getSnapshot2, getSnapshot2);
49732
+ return binding ? snapshot : void 0;
49733
+ }
49734
+ const StoryChromeRow = React.memo(function StoryChromeRow2({ title, count: count2, active, sticky, onNavigate }) {
49735
+ const meterMode = count2 > 12;
49736
+ return /* @__PURE__ */ jsxRuntime.jsxs(
49737
+ react.Box,
49738
+ {
49739
+ display: "flex",
49740
+ alignItems: "center",
49741
+ gap: "3",
49742
+ paddingX: "4",
49743
+ paddingY: "2",
49744
+ borderBottomWidth: "1px",
49745
+ borderColor: "border.subtle",
49746
+ background: "bg.surface",
49747
+ position: sticky ? "sticky" : "relative",
49748
+ top: sticky ? "0" : void 0,
49749
+ zIndex: sticky ? 3 : void 0,
49750
+ "data-scope": "story-progress",
49751
+ children: [
49752
+ title !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
49753
+ react.Box,
49754
+ {
49755
+ fontFamily: "mono",
49756
+ fontSize: "9.5px",
49757
+ fontWeight: "600",
49758
+ letterSpacing: "0.18em",
49759
+ textTransform: "uppercase",
49760
+ color: "fg.muted",
49761
+ children: title
49762
+ }
49763
+ ),
49764
+ meterMode ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { width: "64px", height: "4px", borderRadius: "full", background: "border.strong", position: "relative", overflow: "hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
49765
+ react.Box,
49766
+ {
49767
+ position: "absolute",
49768
+ insetY: "0",
49769
+ left: "0",
49770
+ width: `${count2 > 0 ? (active + 1) / count2 * 100 : 0}%`,
49771
+ background: "colorPalette.solid",
49772
+ colorPalette: "brand",
49773
+ transition: "width 200ms ease-out"
49774
+ }
49775
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", gap: "1.5", alignItems: "center", children: Array.from({ length: count2 }, (_2, i2) => /* @__PURE__ */ jsxRuntime.jsx(
49776
+ react.Box,
49777
+ {
49778
+ as: "button",
49779
+ "aria-label": `Go to step ${i2 + 1}`,
49780
+ width: "6px",
49781
+ height: "6px",
49782
+ borderRadius: "full",
49783
+ cursor: onNavigate ? "pointer" : "default",
49784
+ background: i2 === active ? "colorPalette.solid" : "border.strong",
49785
+ opacity: i2 < active ? 0.5 : 1,
49786
+ colorPalette: "brand",
49787
+ transition: "background 200ms ease-out",
49788
+ onClick: onNavigate ? () => onNavigate(i2) : void 0
49789
+ },
49790
+ i2
49791
+ )) }),
49792
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { marginLeft: "auto", fontFamily: "mono", fontSize: "11px", color: "fg.subtle", fontVariantNumeric: "tabular-nums", children: [
49793
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", color: "fg", fontWeight: "600", children: active + 1 }),
49794
+ ` / ${count2}`
49795
+ ] }),
49796
+ /* @__PURE__ */ jsxRuntime.jsx(
49797
+ react.Box,
49798
+ {
49799
+ as: "button",
49800
+ "aria-label": "Previous step",
49801
+ display: "inline-flex",
49802
+ alignItems: "center",
49803
+ justifyContent: "center",
49804
+ width: "22px",
49805
+ height: "22px",
49806
+ borderWidth: "1px",
49807
+ borderColor: "border.strong",
49808
+ borderRadius: "sm",
49809
+ background: "bg.surface",
49810
+ color: "fg.muted",
49811
+ fontSize: "11px",
49812
+ cursor: "pointer",
49813
+ _hover: { borderColor: "fg.muted", color: "fg" },
49814
+ onClick: onNavigate ? () => onNavigate(active - 1) : void 0,
49815
+ children: "↑"
49816
+ }
49817
+ ),
49818
+ /* @__PURE__ */ jsxRuntime.jsx(
49819
+ react.Box,
49820
+ {
49821
+ as: "button",
49822
+ "aria-label": "Next step",
49823
+ display: "inline-flex",
49824
+ alignItems: "center",
49825
+ justifyContent: "center",
49826
+ width: "22px",
49827
+ height: "22px",
49828
+ borderWidth: "1px",
49829
+ borderColor: "border.strong",
49830
+ borderRadius: "sm",
49831
+ background: "bg.surface",
49832
+ color: "fg.muted",
49833
+ fontSize: "11px",
49834
+ cursor: "pointer",
49835
+ _hover: { borderColor: "fg.muted", color: "fg" },
49836
+ onClick: onNavigate ? () => onNavigate(active + 1) : void 0,
49837
+ children: "↓"
49838
+ }
49839
+ )
49840
+ ]
49841
+ }
49842
+ );
49843
+ });
49844
+ const StoryStepBlock = React.memo(function StoryStepBlock2({ step, index: index2, total, state, minHeight, storageKey, onActivate }) {
49845
+ const pad2 = (n2) => String(n2).padStart(2, "0");
49846
+ const eyebrowText = step.eyebrow !== void 0 ? `${pad2(index2 + 1)} / ${pad2(total)} · ${step.eyebrow}` : `${pad2(index2 + 1)} / ${pad2(total)}`;
49847
+ return /* @__PURE__ */ jsxRuntime.jsxs(
49848
+ react.Box,
49849
+ {
49850
+ position: "relative",
49851
+ paddingY: "4",
49852
+ paddingLeft: "26px",
49853
+ display: "flex",
49854
+ flexDirection: "column",
49855
+ minHeight,
49856
+ boxSizing: "border-box",
49857
+ opacity: state === "active" ? 1 : 0.45,
49858
+ transition: "opacity 200ms ease-out",
49859
+ cursor: onActivate && state !== "active" ? "pointer" : void 0,
49860
+ onClick: onActivate && state !== "active" ? () => onActivate(index2) : void 0,
49861
+ "data-story-step": step.id,
49862
+ "data-state": state,
49863
+ children: [
49864
+ /* @__PURE__ */ jsxRuntime.jsx(
49865
+ react.Box,
49866
+ {
49867
+ position: "absolute",
49868
+ left: "4px",
49869
+ top: index2 === 0 ? "22px" : "0",
49870
+ bottom: index2 === total - 1 ? void 0 : "0",
49871
+ height: index2 === total - 1 ? "22px" : void 0,
49872
+ width: "2px",
49873
+ background: "border.subtle"
49874
+ }
49875
+ ),
49876
+ /* @__PURE__ */ jsxRuntime.jsx(
49877
+ react.Box,
49878
+ {
49879
+ position: "absolute",
49880
+ left: "0",
49881
+ top: "18px",
49882
+ width: "10px",
49883
+ height: "10px",
49884
+ borderRadius: "full",
49885
+ boxSizing: "border-box",
49886
+ borderWidth: "2px",
49887
+ colorPalette: "brand",
49888
+ borderColor: state === "upcoming" ? "border.strong" : "colorPalette.solid",
49889
+ background: state === "active" ? "colorPalette.solid" : "bg.surface",
49890
+ transition: "all 200ms ease-out"
49891
+ }
49892
+ ),
49893
+ /* @__PURE__ */ jsxRuntime.jsx(
49894
+ react.Box,
49895
+ {
49896
+ fontFamily: "mono",
49897
+ fontSize: "9.5px",
49898
+ fontWeight: "600",
49899
+ letterSpacing: "0.18em",
49900
+ textTransform: "uppercase",
49901
+ colorPalette: "brand",
49902
+ color: state === "active" ? "colorPalette.fg" : "fg.subtle",
49903
+ marginBottom: "1.5",
49904
+ children: eyebrowText
49905
+ }
49906
+ ),
49907
+ step.title !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
49908
+ react.Box,
49909
+ {
49910
+ fontSize: "17px",
49911
+ fontWeight: "600",
49912
+ letterSpacing: "-0.01em",
49913
+ lineHeight: "1.3",
49914
+ color: "fg",
49915
+ marginBottom: "2",
49916
+ children: step.title
49917
+ }
49918
+ ),
49919
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { fontSize: "13px", lineHeight: "1.55", color: "fg.muted", maxWidth: "46ch", flex: "1 1 auto", minHeight: "0", children: step.body.map((child, i2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraComponent, { value: child, storageKey: `${storageKey}.body.${i2}` }, i2)) })
49920
+ ]
49921
+ }
49922
+ );
49923
+ }, (prev, next) => prev.index === next.index && prev.total === next.total && prev.state === next.state && prev.minHeight === next.minHeight && prev.storageKey === next.storageKey && prev.step === next.step);
49924
+ const EastChakraStory = React.memo(function EastChakraStory2({ value, storageKey }) {
49925
+ var _a2, _b, _c;
49926
+ const steps = React.useMemo(() => extractSteps(value.steps), [value.steps]);
49927
+ const total = steps.length;
49928
+ const style = getSomeorUndefined(value.style);
49929
+ const layoutPref = (style ? (_a2 = getSomeorUndefined(style.layout)) == null ? void 0 : _a2.type : void 0) ?? "rail-left";
49930
+ const stageHeight = (style ? getSomeorUndefined(style.stageHeight) : void 0) ?? DEFAULT_STAGE_HEIGHT;
49931
+ const stepLength = (style ? (_b = getSomeorUndefined(style.stepLength)) == null ? void 0 : _b.type : void 0) ?? "default";
49932
+ const runwayVh = STEP_RUNWAY_VH[stepLength] ?? STEP_RUNWAY_VH["default"];
49933
+ const scrollportHeight = style ? getSomeorUndefined(style.height) : void 0;
49934
+ const ownScrollport = scrollportHeight !== void 0 && !isStaticForScrollport(value);
49935
+ const title = getSomeorUndefined(value.title);
49936
+ const staticActiveId = getSomeorUndefined(value.activeStep);
49937
+ const isStatic = staticActiveId !== void 0;
49938
+ const activeBinding = React.useMemo(() => getSomeorUndefined(value.active), [value.active]);
49939
+ const progressBinding = React.useMemo(() => getSomeorUndefined(value.progress), [value.progress]);
49940
+ const onStepEnterFn = React.useMemo(() => getSomeorUndefined(value.onStepEnter), [value.onStepEnter]);
49941
+ const onStepExitFn = React.useMemo(() => getSomeorUndefined(value.onStepExit), [value.onStepExit]);
49942
+ const prefersReducedMotion = usePrefersReducedMotion();
49943
+ const fadeMs = prefersReducedMotion ? 120 : 200;
49944
+ const rootRef = React.useRef(null);
49945
+ const railRef = React.useRef(null);
49946
+ const layoutRef = React.useRef("rail-left");
49947
+ const occlusionBottom = React.useCallback((viewTop) => {
49948
+ const root2 = rootRef.current;
49949
+ let bottom = viewTop;
49950
+ if (!root2) return bottom;
49951
+ const chrome = root2.querySelector('[data-scope="story-progress"]');
49952
+ if (chrome) bottom = Math.max(bottom, chrome.getBoundingClientRect().bottom);
49953
+ if (layoutRef.current === "stacked") {
49954
+ const stage2 = root2.querySelector('[data-scope="story-stage"]');
49955
+ if (stage2) bottom = Math.max(bottom, stage2.getBoundingClientRect().bottom);
49956
+ }
49957
+ return bottom;
49958
+ }, []);
49959
+ const clamp2 = React.useCallback((i2) => Math.max(0, Math.min(total - 1, i2)), [total]);
49960
+ const initialActive = isStatic ? Math.max(0, steps.findIndex((s2) => s2.id === staticActiveId)) : clamp2(activeBinding ? Number(activeBinding.read()) : 0);
49961
+ const [active, setActive] = React.useState(initialActive);
49962
+ const activeRef = React.useRef(active);
49963
+ activeRef.current = active;
49964
+ React.useEffect(() => {
49965
+ if (isStatic) {
49966
+ setActive(Math.max(0, steps.findIndex((s2) => s2.id === staticActiveId)));
49967
+ } else {
49968
+ setActive((prev) => Math.max(0, Math.min(total - 1, prev)));
49969
+ }
49970
+ }, [value, total]);
49971
+ const applyActive = React.useCallback((next) => {
49972
+ var _a3, _b2;
49973
+ const clamped = Math.max(0, Math.min(total - 1, next));
49974
+ const prev = activeRef.current;
49975
+ if (clamped === prev) return;
49976
+ setActive(clamped);
49977
+ const prevId = (_a3 = steps[prev]) == null ? void 0 : _a3.id;
49978
+ const nextId = (_b2 = steps[clamped]) == null ? void 0 : _b2.id;
49979
+ queueMicrotask(() => {
49980
+ if (activeBinding) activeBinding.write(BigInt(clamped));
49981
+ if (onStepExitFn && prevId !== void 0) onStepExitFn(prevId);
49982
+ if (onStepEnterFn && nextId !== void 0) onStepEnterFn(nextId);
49983
+ });
49984
+ }, [total, steps, activeBinding, onStepEnterFn, onStepExitFn]);
49985
+ const resolveScroller = React.useCallback(() => {
49986
+ if (ownScrollport) return rootRef.current;
49987
+ return getScrollParent(rootRef.current);
49988
+ }, [ownScrollport]);
49989
+ const navigateTo = React.useCallback((index2) => {
49990
+ var _a3, _b2;
49991
+ const clamped = Math.max(0, Math.min(total - 1, index2));
49992
+ applyActive(clamped);
49993
+ const stepEl = (_b2 = railRef.current) == null ? void 0 : _b2.querySelector(`[data-story-step="${CSS.escape(((_a3 = steps[clamped]) == null ? void 0 : _a3.id) ?? "")}"]`);
49994
+ if (!stepEl) return;
49995
+ const behavior = prefersReducedMotion ? "auto" : "smooth";
49996
+ const scroller = resolveScroller();
49997
+ const rect = stepEl.getBoundingClientRect();
49998
+ const viewTop = scroller ? scroller.getBoundingClientRect().top : 0;
49999
+ const viewBottom = viewTop + (scroller ? scroller.clientHeight : window.innerHeight);
50000
+ const occ = Math.min(occlusionBottom(viewTop), viewBottom);
50001
+ const navLine = layoutRef.current === "stacked" ? occ + (viewBottom - occ) * NAV_OFFSET : Math.max(occ, viewTop + (viewBottom - viewTop) * NAV_OFFSET);
50002
+ if (scroller) {
50003
+ scroller.scrollBy({ top: rect.top - navLine, behavior });
50004
+ } else {
50005
+ window.scrollBy({ top: rect.top - navLine, behavior });
50006
+ }
50007
+ }, [total, steps, applyActive, prefersReducedMotion, resolveScroller, occlusionBottom]);
50008
+ const bindingValue = useActiveBindingValue(isStatic ? void 0 : activeBinding);
50009
+ React.useEffect(() => {
50010
+ if (bindingValue === void 0) return;
50011
+ if (bindingValue !== activeRef.current) {
50012
+ navigateTo(bindingValue);
50013
+ }
50014
+ }, [bindingValue]);
50015
+ React.useEffect(() => {
50016
+ if (isStatic || total === 0) return;
50017
+ const rail2 = railRef.current;
50018
+ if (!rail2) return;
50019
+ let raf = 0;
50020
+ const measure = () => {
50021
+ raf = 0;
50022
+ const scroller2 = resolveScroller();
50023
+ const viewTop = scroller2 ? scroller2.getBoundingClientRect().top : 0;
50024
+ const viewHeight = scroller2 ? scroller2.clientHeight : window.innerHeight;
50025
+ const viewBottom = viewTop + viewHeight;
50026
+ const occ = Math.min(occlusionBottom(viewTop), viewBottom);
50027
+ const line2 = layoutRef.current === "stacked" ? occ + (viewBottom - occ) * TRIGGER_LINE : Math.max(occ, viewTop + viewHeight * TRIGGER_LINE);
50028
+ const blocks = rail2.querySelectorAll("[data-story-step]");
50029
+ let current = 0;
50030
+ let progress = 0;
50031
+ blocks.forEach((el, i2) => {
50032
+ const rect = el.getBoundingClientRect();
50033
+ if (rect.top <= line2) {
50034
+ current = i2;
50035
+ progress = rect.height > 0 ? (line2 - rect.top) / rect.height : 0;
50036
+ }
50037
+ });
50038
+ applyActive(current);
50039
+ if (progressBinding) {
50040
+ const p2 = Math.max(0, Math.min(1, progress));
50041
+ queueMicrotask(() => progressBinding.write(p2));
50042
+ }
50043
+ };
50044
+ const onScroll = () => {
50045
+ if (raf === 0) raf = requestAnimationFrame(measure);
50046
+ };
50047
+ const scroller = resolveScroller();
50048
+ const target = scroller ?? window;
50049
+ target.addEventListener("scroll", onScroll, { passive: true });
50050
+ window.addEventListener("resize", onScroll, { passive: true });
50051
+ measure();
50052
+ return () => {
50053
+ target.removeEventListener("scroll", onScroll);
50054
+ window.removeEventListener("resize", onScroll);
50055
+ if (raf !== 0) cancelAnimationFrame(raf);
50056
+ };
50057
+ }, [isStatic, total, applyActive, progressBinding, resolveScroller]);
50058
+ const [narrow, setNarrow] = React.useState(false);
50059
+ const [portHeight, setPortHeight] = React.useState(0);
50060
+ React.useEffect(() => {
50061
+ const el = rootRef.current;
50062
+ if (!el) return;
50063
+ const ro = new ResizeObserver(([entry]) => {
50064
+ if (entry) {
50065
+ setNarrow(entry.contentRect.width < STACK_BREAKPOINT);
50066
+ setPortHeight(entry.contentRect.height);
50067
+ }
50068
+ });
50069
+ ro.observe(el);
50070
+ return () => ro.disconnect();
50071
+ }, []);
50072
+ const layout = narrow ? "stacked" : layoutPref;
50073
+ layoutRef.current = layout;
50074
+ const effectiveStageHeight = layout === "stacked" ? `min(${stageHeight}, ${STACKED_STAGE_CAP})` : stageHeight;
50075
+ const [chromePx, setChromePx] = React.useState(0);
50076
+ const [stickyPx, setStickyPx] = React.useState(0);
50077
+ React.useEffect(() => {
50078
+ const root2 = rootRef.current;
50079
+ if (!root2 || layout !== "stacked") {
50080
+ setChromePx(0);
50081
+ setStickyPx(0);
50082
+ return;
50083
+ }
50084
+ const stage2 = root2.querySelector('[data-scope="story-stage"]');
50085
+ const chrome = root2.querySelector('[data-scope="story-progress"]');
50086
+ const update = () => {
50087
+ const ch = chrome ? chrome.getBoundingClientRect().height : 0;
50088
+ const st = stage2 ? stage2.getBoundingClientRect().height : 0;
50089
+ setChromePx(Math.max(0, Math.floor(ch) - 1));
50090
+ setStickyPx(Math.round(ch + st));
50091
+ };
50092
+ const ro = new ResizeObserver(update);
50093
+ if (stage2) ro.observe(stage2);
50094
+ if (chrome) ro.observe(chrome);
50095
+ update();
50096
+ return () => ro.disconnect();
50097
+ }, [layout, total]);
50098
+ const onKeyDown = React.useCallback((e3) => {
50099
+ if (isStatic) return;
50100
+ switch (e3.key) {
50101
+ case "ArrowDown":
50102
+ case "j":
50103
+ navigateTo(activeRef.current + 1);
50104
+ e3.preventDefault();
50105
+ break;
50106
+ case "ArrowUp":
50107
+ case "k":
50108
+ navigateTo(activeRef.current - 1);
50109
+ e3.preventDefault();
50110
+ break;
50111
+ case "Home":
50112
+ navigateTo(0);
50113
+ e3.preventDefault();
50114
+ break;
50115
+ case "End":
50116
+ navigateTo(total - 1);
50117
+ e3.preventDefault();
50118
+ break;
50119
+ }
50120
+ }, [isStatic, navigateTo, total]);
50121
+ const kfOwner = keyframeOwner(steps, active);
50122
+ const chromeHeight = title !== void 0 ? 41 : 0;
50123
+ const stageTop = 16 + chromeHeight;
50124
+ const stage = (
50125
+ // In stacked mode the prose scrolls UNDERNEATH the sticky stage, so
50126
+ // the slot must be opaque (with a hairline rule); in rail layouts it
50127
+ // stays unchromed per the spec — keyframes bring their own framing.
50128
+ /* @__PURE__ */ jsxRuntime.jsx(
50129
+ react.Box,
50130
+ {
50131
+ position: "sticky",
50132
+ top: layout === "stacked" ? `${title !== void 0 ? chromePx : 0}px` : `${stageTop}px`,
50133
+ paddingBottom: "4",
50134
+ "data-scope": "story-stage",
50135
+ background: layout === "stacked" ? "bg.surface" : void 0,
50136
+ borderBottomWidth: layout === "stacked" ? "1px" : void 0,
50137
+ borderColor: layout === "stacked" ? "border.subtle" : void 0,
50138
+ zIndex: layout === "stacked" ? 2 : void 0,
50139
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.Box, { position: "relative", height: effectiveStageHeight, children: steps.map((step, i2) => step.stage !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
50140
+ react.Box,
50141
+ {
50142
+ position: "absolute",
50143
+ inset: "0",
50144
+ opacity: i2 === kfOwner ? 1 : 0,
50145
+ pointerEvents: i2 === kfOwner ? "auto" : "none",
50146
+ transition: `opacity ${fadeMs}ms ease-out`,
50147
+ "data-story-keyframe": step.id,
50148
+ "data-active": i2 === kfOwner ? "true" : "false",
50149
+ children: /* @__PURE__ */ jsxRuntime.jsx(EastChakraComponent, { value: step.stage, storageKey: `${storageKey}.stage.${step.id}` })
50150
+ },
50151
+ step.id
50152
+ )) })
50153
+ }
50154
+ )
50155
+ );
50156
+ const rail = /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref: railRef, paddingTop: "4", "data-scope": "story-rail", children: steps.map((step, i2) => /* @__PURE__ */ jsxRuntime.jsx(
50157
+ StoryStepBlock,
50158
+ {
50159
+ step,
50160
+ index: i2,
50161
+ total,
50162
+ state: i2 === active ? "active" : i2 < active ? "visited" : "upcoming",
50163
+ minHeight: isStatic ? void 0 : ownScrollport ? i2 === total - 1 ? `${Math.max(120, Math.round(
50164
+ (1 - TRIGGER_LINE) * (layout === "stacked" ? Math.max(0, portHeight - stickyPx) : portHeight) + 16
50165
+ ))}px` : `${Math.max(120, Math.round(
50166
+ (layout === "stacked" ? Math.max(0, portHeight - stickyPx) : portHeight - chromeHeight) * (runwayVh / 52)
50167
+ ))}px` : `${runwayVh + (i2 === total - 1 ? 20 : 0)}vh`,
50168
+ storageKey: `${storageKey}.step.${step.id}`,
50169
+ onActivate: isStatic ? void 0 : navigateTo
50170
+ },
50171
+ step.id
50172
+ )) });
50173
+ return /* @__PURE__ */ jsxRuntime.jsxs(
50174
+ react.Box,
50175
+ {
50176
+ ref: rootRef,
50177
+ position: "relative",
50178
+ tabIndex: 0,
50179
+ outline: "none",
50180
+ onKeyDown,
50181
+ "data-scope": "story",
50182
+ "data-active-step": (_c = steps[active]) == null ? void 0 : _c.id,
50183
+ height: ownScrollport ? scrollportHeight : void 0,
50184
+ overflowY: ownScrollport ? "auto" : void 0,
50185
+ overflowX: ownScrollport ? "hidden" : void 0,
50186
+ background: ownScrollport ? "bg.surface" : void 0,
50187
+ children: [
50188
+ title !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
50189
+ StoryChromeRow,
50190
+ {
50191
+ title,
50192
+ count: total,
50193
+ active,
50194
+ sticky: !isStatic,
50195
+ onNavigate: isStatic ? void 0 : navigateTo
50196
+ }
50197
+ ),
50198
+ layout === "stacked" ? /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { children: [
50199
+ stage,
50200
+ rail
50201
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
50202
+ react.Box,
50203
+ {
50204
+ display: "grid",
50205
+ gridTemplateColumns: layout === "rail-right" ? "minmax(0, 1fr) clamp(280px, 34%, 380px)" : "clamp(280px, 34%, 380px) minmax(0, 1fr)",
50206
+ gap: "28px",
50207
+ children: layout === "rail-right" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
50208
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { minWidth: "0", children: stage }),
50209
+ rail
50210
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
50211
+ rail,
50212
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { minWidth: "0", children: stage })
50213
+ ] })
50214
+ }
50215
+ )
50216
+ ]
50217
+ }
50218
+ );
50219
+ }, (prev, next) => storyEqual(prev.value, next.value) && prev.storageKey === next.storageKey);
50220
+ const EastChakraStoryStep = React.memo(function EastChakraStoryStep2({ value, storageKey }) {
50221
+ const step = React.useMemo(() => ({
50222
+ id: value.id,
50223
+ eyebrow: getSomeorUndefined(value.eyebrow),
50224
+ title: getSomeorUndefined(value.title),
50225
+ stage: getSomeorUndefined(value.stage),
50226
+ body: value.body
50227
+ }), [value]);
50228
+ return /* @__PURE__ */ jsxRuntime.jsx(
50229
+ StoryStepBlock,
50230
+ {
50231
+ step,
50232
+ index: 0,
50233
+ total: 1,
50234
+ state: "active",
50235
+ minHeight: void 0,
50236
+ storageKey,
50237
+ onActivate: void 0
50238
+ }
50239
+ );
50240
+ }, (prev, next) => storyStepEqual(prev.value, next.value) && prev.storageKey === next.storageKey);
50241
+ const EastChakraStoryProgress = React.memo(function EastChakraStoryProgress2({ value }) {
50242
+ const count2 = Number(value.count);
50243
+ const binding = React.useMemo(() => getSomeorUndefined(value.active), [value.active]);
50244
+ const bound = useActiveBindingValue(binding);
50245
+ const [internal2, setInternal] = React.useState(0);
50246
+ const active = Math.max(0, Math.min(count2 - 1, bound ?? internal2));
50247
+ const onNavigate = React.useCallback((index2) => {
50248
+ const clamped = Math.max(0, Math.min(count2 - 1, index2));
50249
+ setInternal(clamped);
50250
+ if (binding) {
50251
+ queueMicrotask(() => binding.write(BigInt(clamped)));
50252
+ }
50253
+ }, [count2, binding]);
50254
+ return /* @__PURE__ */ jsxRuntime.jsx(
50255
+ StoryChromeRow,
50256
+ {
50257
+ title: getSomeorUndefined(value.title),
50258
+ count: count2,
50259
+ active,
50260
+ sticky: false,
50261
+ onNavigate
50262
+ }
50263
+ );
50264
+ }, (prev, next) => storyProgressEqual(prev.value, next.value) && prev.storageKey === next.storageKey);
49672
50265
  const segmentGroupEqual = east.equalFor(internal.SegmentGroup.Types.SegmentGroup);
49673
50266
  function toChakraSegmentGroup(value) {
49674
50267
  var _a2, _b, _c;
@@ -64183,6 +64776,9 @@ const EastChakraComponent = React.memo(function EastChakraComponent2({ value, st
64183
64776
  Accordion: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraAccordion, { value: v2, storageKey: childKey(storageKey, "Accordion") }),
64184
64777
  Carousel: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraCarousel, { value: v2, storageKey: childKey(storageKey, "Carousel") }),
64185
64778
  Tabs: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraTabs, { value: v2, storageKey: childKey(storageKey, "Tabs") }),
64779
+ Story: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraStory, { value: v2, storageKey: childKey(storageKey, "Story") }),
64780
+ StoryStep: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraStoryStep, { value: v2, storageKey: childKey(storageKey, "StoryStep") }),
64781
+ StoryProgress: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraStoryProgress, { value: v2, storageKey: childKey(storageKey, "StoryProgress") }),
64186
64782
  SegmentGroup: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraSegmentGroup, { value: v2, storageKey: childKey(storageKey, "SegmentGroup") }),
64187
64783
  Collapsible: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraCollapsible, { value: v2, storageKey: childKey(storageKey, "Collapsible") }),
64188
64784
  Disclosure: (v2) => /* @__PURE__ */ jsxRuntime.jsx(EastChakraDisclosure, { value: v2, storageKey: childKey(storageKey, "Disclosure") }),
@@ -77270,6 +77866,9 @@ exports.EastChakraSplitter = EastChakraSplitter;
77270
77866
  exports.EastChakraStack = EastChakraStack;
77271
77867
  exports.EastChakraStat = EastChakraStat;
77272
77868
  exports.EastChakraStatus = EastChakraStatus;
77869
+ exports.EastChakraStory = EastChakraStory;
77870
+ exports.EastChakraStoryProgress = EastChakraStoryProgress;
77871
+ exports.EastChakraStoryStep = EastChakraStoryStep;
77273
77872
  exports.EastChakraStringInput = EastChakraStringInput;
77274
77873
  exports.EastChakraSwitch = EastChakraSwitch;
77275
77874
  exports.EastChakraTable = EastChakraTable;