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