@hyperframes/studio 0.8.7 → 0.8.9

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.
Files changed (31) hide show
  1. package/dist/assets/{hyperframes-player-bDcU464i.js → hyperframes-player-OP68oEBG.js} +1 -1
  2. package/dist/assets/{index-CUXnyoIa.js → index-57oMsXQN.js} +111 -111
  3. package/dist/assets/{index-MSOSP1-J.js → index-BIdEpMGS.js} +1 -1
  4. package/dist/assets/{index-FkAs3zRu.js → index-D1Sa69m2.js} +1 -1
  5. package/dist/index.d.ts +10 -1
  6. package/dist/index.html +1 -1
  7. package/dist/index.js +40 -35
  8. package/dist/index.js.map +1 -1
  9. package/package.json +7 -7
  10. package/src/components/editor/CanvasContextMenu.test.tsx +1 -1
  11. package/src/components/editor/CanvasContextMenu.tsx +1 -1
  12. package/src/components/editor/PropertyPanelFlat.tsx +1 -5
  13. package/src/components/editor/TimelineFxPopover.test.tsx +89 -0
  14. package/src/components/editor/TimelineFxPopover.tsx +49 -15
  15. package/src/hooks/timelineTrackVisibility.test.ts +31 -0
  16. package/src/hooks/timelineTrackVisibility.ts +20 -4
  17. package/src/player/components/AutomationSelectionMenu.tsx +1 -1
  18. package/src/player/components/ClipContextMenu.tsx +1 -1
  19. package/src/player/components/KeyframeDiamondContextMenu.tsx +1 -1
  20. package/src/player/components/Timeline.test.ts +1 -1
  21. package/src/player/components/TimelineFxButton.tsx +1 -1
  22. package/src/player/components/TimelineGroupHeader.test.tsx +76 -0
  23. package/src/player/components/TimelineGroupHeader.tsx +8 -4
  24. package/src/player/components/TimelineLanes.test.tsx +3 -1
  25. package/src/player/components/TimelineTrackHeader.test.tsx +2 -1
  26. package/src/player/components/TimelineTrackPlainHeader.test.tsx +161 -0
  27. package/src/player/components/TimelineTrackPlainHeader.tsx +17 -10
  28. package/src/player/components/TrackGapContextMenu.tsx +1 -1
  29. package/src/player/components/timelineCallbacks.ts +14 -1
  30. package/src/player/components/useTimelineTrackDerivations.test.ts +103 -0
  31. package/src/player/components/useTimelineTrackDerivations.ts +4 -11
@@ -1,4 +1,4 @@
1
- import{n as Qi}from"./index-CUXnyoIa.js";/*!
1
+ import{n as Qi}from"./index-57oMsXQN.js";/*!
2
2
  * Copyright (c) 2026-present, Vanilagy and contributors
3
3
  *
4
4
  * This Source Code Form is subject to the terms of the Mozilla Public
@@ -1 +1 @@
1
- import{g as P}from"./index-CUXnyoIa.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
1
+ import{g as P}from"./index-57oMsXQN.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
package/dist/index.d.ts CHANGED
@@ -655,7 +655,16 @@ interface TimelineEditCallbacks {
655
655
  }>, options?: {
656
656
  coalesceKey?: string;
657
657
  }) => Promise<void> | void;
658
- onToggleTrackHidden?: (track: number, hidden: boolean) => Promise<void> | void;
658
+ /**
659
+ * `displayNumber` is the row the CLICKED control announced. It travels with
660
+ * the click because the header and the undo-history label derive the row from
661
+ * two different orderings: the header's comes from the group-aware row list
662
+ * (synthetic anchor rows, members pulled contiguous), the history's from a
663
+ * plain ascending sort of element-bearing keys. Once a group exists those
664
+ * disagree, so the same click said "Mute track 2" and recorded "Mute track 1".
665
+ * Passing the rendered number keeps one answer instead of two derivations.
666
+ */
667
+ onToggleTrackHidden?: (track: number, hidden: boolean, displayNumber?: number | null) => Promise<void> | void;
659
668
  /** B7's bus strip: live-write the group's own attribute while dragging. */
660
669
  onSetAudioGroupAttributeLive?: (groupId: string, attr: string, value: string | null) => void;
661
670
  /** ...and persist one undo entry on release. */
package/dist/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-CUXnyoIa.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-57oMsXQN.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-Ba9zbpT9.css">
10
10
  </head>
11
11
  <body>
package/dist/index.js CHANGED
@@ -1704,9 +1704,6 @@ function resolveCanary(name) {
1704
1704
  decisions.set(name, decision);
1705
1705
  return decision;
1706
1706
  }
1707
- function isCanaryEnabled(name) {
1708
- return resolveCanary(name).enabled;
1709
- }
1710
1707
  function canaryEventProperties() {
1711
1708
  return canaryFeatureProperties(
1712
1709
  CANARIES.map((c) => {
@@ -11658,7 +11655,7 @@ var AutomationSelectionMenu = memo11(function AutomationSelectionMenu2({
11658
11655
  "div",
11659
11656
  {
11660
11657
  ref: menuRef,
11661
- className: "hf-automation-menu fixed z-50 min-w-[140px] rounded border border-panel-border-input bg-panel-bg-2 py-1 shadow-lg",
11658
+ className: "hf-automation-menu fixed z-[200] min-w-[140px] rounded border border-panel-border-input bg-panel-bg-2 py-1 shadow-lg",
11662
11659
  style: { left: adjustedX, top: adjustedY },
11663
11660
  children: [
11664
11661
  AUTOMATION_SHAPES.map((shape) => /* @__PURE__ */ jsx28(
@@ -13178,7 +13175,7 @@ function trackDisplaySuffix(displayNumber) {
13178
13175
  // src/player/components/TimelineTrackPlainHeader.tsx
13179
13176
  import { Fragment as Fragment12, jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
13180
13177
  function visibilityButtonLabel(showAsMute, hidden, suffix) {
13181
- if (showAsMute) return hidden ? "Muted" : "Mute";
13178
+ if (showAsMute) return hidden ? `Unmute track${suffix}` : `Mute track${suffix}`;
13182
13179
  return hidden ? `Show track${suffix}` : `Hide track${suffix}`;
13183
13180
  }
13184
13181
  function visibilityButtonIcon(showAsMute, hidden) {
@@ -13195,7 +13192,7 @@ function VisibilityButton({
13195
13192
  }) {
13196
13193
  if (!visible) return /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", className: "h-6 w-6 shrink-0" });
13197
13194
  const suffix = trackDisplaySuffix(trackDisplayNumber2);
13198
- const showAsMute = Boolean(isAudioTrack) && isCanaryEnabled("audio-track-mute");
13195
+ const showAsMute = Boolean(isAudioTrack);
13199
13196
  const label = visibilityButtonLabel(showAsMute, hidden, suffix);
13200
13197
  return /* @__PURE__ */ jsx35(
13201
13198
  "button",
@@ -13207,7 +13204,7 @@ function VisibilityButton({
13207
13204
  onPointerDown: (event) => event.stopPropagation(),
13208
13205
  onClick: (event) => {
13209
13206
  event.stopPropagation();
13210
- void onToggle?.(trackNumber, !hidden);
13207
+ void onToggle?.(trackNumber, !hidden, trackDisplayNumber2);
13211
13208
  },
13212
13209
  children: visibilityButtonIcon(showAsMute, hidden)
13213
13210
  }
@@ -13231,7 +13228,7 @@ function PlainTrackHeader({
13231
13228
  showTrackLabel && /* @__PURE__ */ jsx35(
13232
13229
  "span",
13233
13230
  {
13234
- className: `min-w-0 flex-1 truncate text-[11px] ${isAudioTrack && (isTrackHidden || isGroupMuted) && isCanaryEnabled("audio-track-mute") ? "line-through" : ""}`,
13231
+ className: `min-w-0 flex-1 truncate text-[11px] ${isAudioTrack && (isTrackHidden || isGroupMuted) ? "line-through" : ""}`,
13235
13232
  title: isGroupMuted && !isTrackHidden ? `${trackLabel} (group muted)` : trackLabel,
13236
13233
  children: trackLabel
13237
13234
  }
@@ -13248,7 +13245,7 @@ function PlainTrackHeader({
13248
13245
  onToggle: onToggleTrackHidden
13249
13246
  }
13250
13247
  ),
13251
- isAudioTrack && isCanaryEnabled("audio-track-mute") && onToggleSolo && /* @__PURE__ */ jsx35(TimelineSoloButton, { isSoloed, onToggle: onToggleSolo })
13248
+ isAudioTrack && onToggleSolo && /* @__PURE__ */ jsx35(TimelineSoloButton, { isSoloed, onToggle: onToggleSolo })
13252
13249
  ] });
13253
13250
  }
13254
13251
 
@@ -13546,18 +13543,30 @@ function useFxAudition(chain, onChainPreview, onAuditionTransport) {
13546
13543
  import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
13547
13544
  var POPOVER_WIDTH = 260;
13548
13545
  var VIEWPORT_MARGIN2 = 8;
13546
+ var MIN_POPOVER_HEIGHT = 160;
13549
13547
  function clampedStyle(anchorRect) {
13550
13548
  const left = Math.min(
13551
13549
  Math.max(anchorRect.left, VIEWPORT_MARGIN2),
13552
13550
  Math.max(VIEWPORT_MARGIN2, window.innerWidth - POPOVER_WIDTH - VIEWPORT_MARGIN2)
13553
13551
  );
13554
13552
  const spaceBelow = window.innerHeight - anchorRect.bottom;
13555
- const openUpward = spaceBelow < 260 && anchorRect.top > spaceBelow;
13553
+ const spaceAbove = anchorRect.top;
13554
+ const openUpward = spaceBelow < 260 && spaceAbove > spaceBelow;
13555
+ const available = (openUpward ? spaceAbove : spaceBelow) - VIEWPORT_MARGIN2 - 4;
13556
+ const height = Math.min(
13557
+ Math.max(MIN_POPOVER_HEIGHT, available),
13558
+ window.innerHeight - VIEWPORT_MARGIN2 * 2
13559
+ );
13560
+ const inset = (desired) => Math.max(
13561
+ VIEWPORT_MARGIN2,
13562
+ Math.min(desired, Math.max(VIEWPORT_MARGIN2, window.innerHeight - height - VIEWPORT_MARGIN2))
13563
+ );
13556
13564
  return {
13557
13565
  position: "fixed",
13558
13566
  left,
13559
13567
  width: POPOVER_WIDTH,
13560
- ...openUpward ? { bottom: window.innerHeight - anchorRect.top + 4 } : { top: anchorRect.bottom + 4 }
13568
+ maxHeight: height,
13569
+ ...openUpward ? { bottom: inset(window.innerHeight - anchorRect.top + 4) } : { top: inset(anchorRect.bottom + 4) }
13561
13570
  };
13562
13571
  }
13563
13572
  function TimelineFxPopover({
@@ -13598,20 +13607,20 @@ function TimelineFxPopover({
13598
13607
  ref: rootRef,
13599
13608
  role: "dialog",
13600
13609
  "aria-label": "Effects",
13601
- className: "z-50 rounded-md border border-white/10 bg-[#1b1b1f] p-2 shadow-xl",
13610
+ className: "z-[200] flex flex-col overflow-hidden rounded-md border border-white/10 bg-[#1b1b1f] p-2 shadow-xl",
13602
13611
  style: clampedStyle(anchorRect),
13603
13612
  onKeyDown,
13604
13613
  onPointerDown: (event) => event.stopPropagation(),
13605
13614
  children: [
13606
- /* @__PURE__ */ jsx37(
13615
+ /* @__PURE__ */ jsx37("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx37(
13607
13616
  FxPresetMenu,
13608
13617
  {
13609
13618
  trackKind,
13610
13619
  onPick: applyPreset,
13611
13620
  onAudition: onChainPreview ? (id) => audition(id ? (base2) => applyPresetToChain(base2, id, trackKind) ?? base2 : null) : void 0
13612
13621
  }
13613
- ),
13614
- /* @__PURE__ */ jsxs25("div", { className: "mt-2 flex items-center justify-between border-t border-white/10 pt-2 text-[10px] text-white/55", children: [
13622
+ ) }),
13623
+ /* @__PURE__ */ jsxs25("div", { className: "mt-2 flex shrink-0 items-center justify-between border-t border-white/10 pt-2 text-[10px] text-white/55", children: [
13615
13624
  /* @__PURE__ */ jsx37(
13616
13625
  "button",
13617
13626
  {
@@ -13685,7 +13694,7 @@ function TimelineFxButton(props) {
13685
13694
  {
13686
13695
  role: "dialog",
13687
13696
  "aria-label": "Group these clips to add effects",
13688
- className: "z-50 w-56 rounded-md border border-white/10 bg-[#1b1b1f] p-2.5 text-[11px] text-white/75 shadow-xl",
13697
+ className: "z-[200] w-56 rounded-md border border-white/10 bg-[#1b1b1f] p-2.5 text-[11px] text-white/75 shadow-xl",
13689
13698
  style: { position: "fixed", left: anchorRect.left, top: anchorRect.bottom + 4 },
13690
13699
  onPointerDown: (event) => event.stopPropagation(),
13691
13700
  children: [
@@ -14454,13 +14463,13 @@ function TimelineGroupHeader({
14454
14463
  "aria-expanded": isExpanded,
14455
14464
  "aria-label": `${isExpanded ? "Hide" : "Show"} ${label} tracks`,
14456
14465
  title: `${isExpanded ? "Hide" : "Show"} tracks`,
14457
- className: `flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 text-[11px] focus-visible:outline focus-visible:outline-1 focus-visible:outline-[#3CE6AC] ${isExpanded ? "text-white" : "text-white/55 hover:text-white"}`,
14466
+ className: `flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 font-mono text-[13px] focus-visible:outline focus-visible:outline-1 focus-visible:outline-[#3CE6AC] ${isExpanded ? "text-white" : "text-white/55 hover:text-white"}`,
14458
14467
  onPointerDown: (event) => event.stopPropagation(),
14459
14468
  onClick: (event) => {
14460
14469
  event.stopPropagation();
14461
14470
  onToggleExpanded();
14462
14471
  },
14463
- children: /* @__PURE__ */ jsx42("span", { "aria-hidden": "true", style: { transform: isExpanded ? "rotate(90deg)" : void 0 }, children: "\u25B8" })
14472
+ children: /* @__PURE__ */ jsx42("span", { "aria-hidden": "true", children: isExpanded ? "\u25BE" : "\u25B8" })
14464
14473
  }
14465
14474
  ),
14466
14475
  /* @__PURE__ */ jsx42("span", { "aria-hidden": "true", className: "shrink-0 text-[12px] leading-none text-white/50", children: "\u25A4" }),
@@ -14915,16 +14924,10 @@ function useTimelineTrackDerivations(expandedElements) {
14915
14924
  }
14916
14925
  return Array.from(map.entries()).sort(([a], [b]) => a - b);
14917
14926
  }, [expandedElements]);
14918
- const { tracks, groups, trackGroupOf } = useMemo12(() => {
14919
- if (!isCanaryEnabled("audio-groups")) {
14920
- return {
14921
- tracks: rawTracks,
14922
- groups: [],
14923
- trackGroupOf: /* @__PURE__ */ new Map()
14924
- };
14925
- }
14926
- return groupTimelineTracks(rawTracks);
14927
- }, [rawTracks]);
14927
+ const { tracks, groups, trackGroupOf } = useMemo12(
14928
+ () => groupTimelineTracks(rawTracks),
14929
+ [rawTracks]
14930
+ );
14928
14931
  const trackStyles = useMemo12(() => {
14929
14932
  const map = /* @__PURE__ */ new Map();
14930
14933
  for (const [trackNum, els] of tracks) {
@@ -19998,7 +20001,7 @@ function KeyframeDiamondContextMenu({
19998
20001
  ref: menuRef,
19999
20002
  role: "menu",
20000
20003
  "aria-label": "Keyframe actions",
20001
- className: "fixed z-50 bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px] overflow-y-auto",
20004
+ className: "fixed z-[200] bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px] overflow-y-auto",
20002
20005
  style: { left: adjustedX, top: adjustedY, maxHeight: `calc(100vh - ${adjustedY + 8}px)` },
20003
20006
  children: [
20004
20007
  onMoveToPlayhead && /* @__PURE__ */ jsx50(
@@ -20107,7 +20110,7 @@ var ClipContextMenu = memo14(function ClipContextMenu2({
20107
20110
  ref: menuRef,
20108
20111
  role: "menu",
20109
20112
  "aria-label": "Clip actions",
20110
- className: "fixed z-50 bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]",
20113
+ className: "fixed z-[200] bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]",
20111
20114
  style: { left: adjustedX, top: adjustedY },
20112
20115
  children: [
20113
20116
  splitLabel && /* @__PURE__ */ jsxs38(Fragment16, { children: [
@@ -20185,7 +20188,7 @@ var TrackGapContextMenu = memo15(function TrackGapContextMenu2({
20185
20188
  "div",
20186
20189
  {
20187
20190
  ref: menuRef,
20188
- className: "fixed z-50 bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]",
20191
+ className: "fixed z-[200] bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]",
20189
20192
  style: { left: adjustedX, top: adjustedY },
20190
20193
  onPointerLeave: () => onHoverAction(null),
20191
20194
  children: [
@@ -32662,7 +32665,7 @@ var CanvasContextMenu = memo23(function CanvasContextMenu2({
32662
32665
  "div",
32663
32666
  {
32664
32667
  ref: menuRef,
32665
- className: "fixed z-50 bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]",
32668
+ className: "fixed z-[200] bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]",
32666
32669
  style: { left: adjustedX, top: adjustedY },
32667
32670
  onPointerDown: stopBubble,
32668
32671
  onMouseDown: stopBubble,
@@ -57387,7 +57390,7 @@ function PropertyPanelFlat({
57387
57390
  });
57388
57391
  }
57389
57392
  }
57390
- if (sections.audioFx && isCanaryEnabled("audio-fx-rack")) {
57393
+ if (sections.audioFx) {
57391
57394
  groups.push({
57392
57395
  id: "audio-fx",
57393
57396
  title: "Audio FX",
@@ -63437,6 +63440,7 @@ async function toggleTimelineTrackHidden({
63437
63440
  timelineElements,
63438
63441
  track: track2,
63439
63442
  hidden,
63443
+ displayNumber,
63440
63444
  previewIframe,
63441
63445
  writeProjectFile,
63442
63446
  recordEdit,
@@ -63444,7 +63448,7 @@ async function toggleTimelineTrackHidden({
63444
63448
  pendingTimelineEditPathRef
63445
63449
  }) {
63446
63450
  const suffix = trackDisplaySuffix(
63447
- trackDisplayNumber(timelineTrackOrder(timelineElements), track2)
63451
+ displayNumber ?? trackDisplayNumber(timelineTrackOrder(timelineElements), track2)
63448
63452
  );
63449
63453
  const trackElements = timelineElements.filter((element) => element.track === track2);
63450
63454
  const isAudioOnlyTrack = trackElements.length > 0 && trackElements.every(isAudioTimelineElement);
@@ -63574,7 +63578,7 @@ function useTimelineTrackVisibilityEditing({
63574
63578
  }) {
63575
63579
  const expandedElements = useExpandedTimelineElements();
63576
63580
  return useCallback94(
63577
- async (track2, hidden) => {
63581
+ async (track2, hidden, displayNumber) => {
63578
63582
  if (isRecordingRef?.current) {
63579
63583
  showToast("Cannot edit timeline while recording", "error");
63580
63584
  return;
@@ -63588,6 +63592,7 @@ function useTimelineTrackVisibilityEditing({
63588
63592
  timelineElements: expandedElements,
63589
63593
  track: track2,
63590
63594
  hidden,
63595
+ displayNumber,
63591
63596
  previewIframe: previewIframeRef.current,
63592
63597
  writeProjectFile,
63593
63598
  recordEdit,