hyperframes 0.8.28 → 0.8.30

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.
@@ -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-O3ilbgfR.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-hQAWl6re.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-DnRfAiK2.css">
10
10
  </head>
11
11
  <body>
@@ -15907,10 +15907,10 @@ function patchInlineStyle(html2, elementId2, prop, value) {
15907
15907
  }
15908
15908
  function patchInlineStyleInTag(html2, tag, prop, value) {
15909
15909
  if (!tag) return html2;
15910
- const styleMatch = /\bstyle=(["'])([\s\S]*?)\1/.exec(tag);
15910
+ const styleMatch = /\bstyle=(")([^"]*)"|\bstyle=(')([^']*)'/.exec(tag);
15911
15911
  if (styleMatch) {
15912
- const existingStyle = styleMatch[2];
15913
- const quote = styleMatch[1];
15912
+ const existingStyle = styleMatch[2] ?? styleMatch[4];
15913
+ const quote = styleMatch[1] ?? styleMatch[3];
15914
15914
  const props = /* @__PURE__ */ new Map();
15915
15915
  for (const part of splitInlineStyleDeclarations(existingStyle)) {
15916
15916
  const colon = part.indexOf(":");
@@ -15929,8 +15929,8 @@ function patchInlineStyleInTag(html2, tag, prop, value) {
15929
15929
  return html2.replace(tag, newTag);
15930
15930
  } else {
15931
15931
  if (value === null) return html2;
15932
- const selfClosing = /\s*\/$/.test(tag);
15933
- const base2 = selfClosing ? tag.replace(/\s*\/$/, "") : tag;
15932
+ const selfClosing = tag.endsWith("/");
15933
+ const base2 = selfClosing ? tag.slice(0, -1).trimEnd() : tag;
15934
15934
  const newTag = `${base2} style="${prop}: ${escapeStyleAttributeValue(value, '"')}"${selfClosing ? " /" : ""}`;
15935
15935
  return html2.replace(tag, newTag);
15936
15936
  }
@@ -74843,6 +74843,8 @@ function useExternalFileChangeCoordinator({
74843
74843
  const lastEventIdentityRef = useRef133(null);
74844
74844
  const blockedRef = useRef133(blocked);
74845
74845
  const snapshotWriteTailRef = useRef133(Promise.resolve());
74846
+ const drainingRef = useRef133(false);
74847
+ const pendingPayloadRef = useRef133(null);
74846
74848
  blockedRef.current = blocked;
74847
74849
  useEffect106(() => {
74848
74850
  mountedRef.current = true;
@@ -74910,32 +74912,11 @@ function useExternalFileChangeCoordinator({
74910
74912
  );
74911
74913
  await next;
74912
74914
  }, []);
74913
- const processChange = useCallback125(
74915
+ const drainOnePending = useCallback125(
74914
74916
  // fallow-ignore-next-line complexity
74915
- async (payload, allowDuplicate = false) => {
74917
+ async (payload) => {
74916
74918
  const path = readStudioFileChangePath(payload);
74917
- if (!path || !projectId) return;
74918
- const pendingTimelinePaths = pendingTimelineEditPathRef.current;
74919
- pendingTimelinePaths.delete(path);
74920
- const content = readFileChangeContent(payload);
74921
- const token = readFileChangeWriteToken(payload);
74922
- logReload("file-change", { path, token: token ?? null, hasContent: content != null });
74923
- const identity = eventIdentity(path, payload);
74924
- if (!allowDuplicate && identity != null && identity === lastEventIdentityRef.current) {
74925
- logReload("suppressed", { path, why: "duplicate event" });
74926
- return;
74927
- }
74928
- lastEventIdentityRef.current = identity;
74929
- const ownWriteToken = consumeStudioWriteToken(token);
74930
- const ownContentEcho = content != null && isSelfWriteEcho(path, content);
74931
- if (ownWriteToken || ownContentEcho) {
74932
- onAcceptedPersistedFileChange(path);
74933
- logReload("suppressed", {
74934
- path,
74935
- why: ownWriteToken ? "own write token" : "own content echo"
74936
- });
74937
- return;
74938
- }
74919
+ if (!path) return;
74939
74920
  const generation = ++generationRef.current;
74940
74921
  const result = await drainPendingChanges();
74941
74922
  if (!mountedRef.current || generation !== generationRef.current) return;
@@ -74957,6 +74938,7 @@ function useExternalFileChangeCoordinator({
74957
74938
  reloadAcceptedGeneration(path);
74958
74939
  return;
74959
74940
  }
74941
+ const content = readFileChangeContent(payload);
74960
74942
  if (result.status === "failed") {
74961
74943
  const candidate = getPendingCandidate?.();
74962
74944
  const studioContent = candidate?.path === path ? candidate.content : null;
@@ -75011,9 +74993,8 @@ function useExternalFileChangeCoordinator({
75011
74993
  setBlocked({ status: "conflict", generation, error: result.error, payload });
75012
74994
  },
75013
74995
  [
75014
- projectId,
75015
- pendingTimelineEditPathRef,
75016
74996
  drainPendingChanges,
74997
+ projectId,
75017
74998
  deleteConflictSnapshot,
75018
74999
  getPendingCandidate,
75019
75000
  persistConflictSnapshot,
@@ -75023,6 +75004,50 @@ function useExternalFileChangeCoordinator({
75023
75004
  onAcceptedPersistedFileChange
75024
75005
  ]
75025
75006
  );
75007
+ const startDrainLoop = useCallback125(async () => {
75008
+ if (drainingRef.current) return;
75009
+ drainingRef.current = true;
75010
+ try {
75011
+ while (mountedRef.current) {
75012
+ const pending2 = pendingPayloadRef.current;
75013
+ if (!pending2) break;
75014
+ pendingPayloadRef.current = null;
75015
+ await drainOnePending(pending2.payload);
75016
+ }
75017
+ } finally {
75018
+ drainingRef.current = false;
75019
+ }
75020
+ }, [drainOnePending]);
75021
+ const processChange = useCallback125(
75022
+ // fallow-ignore-next-line complexity
75023
+ (payload) => {
75024
+ const path = readStudioFileChangePath(payload);
75025
+ if (!path || !projectId) return;
75026
+ pendingTimelineEditPathRef.current.delete(path);
75027
+ const content = readFileChangeContent(payload);
75028
+ const token = readFileChangeWriteToken(payload);
75029
+ logReload("file-change", { path, token: token ?? null, hasContent: content != null });
75030
+ const identity = eventIdentity(path, payload);
75031
+ if (identity != null && identity === lastEventIdentityRef.current) {
75032
+ logReload("suppressed", { path, why: "duplicate event" });
75033
+ return;
75034
+ }
75035
+ lastEventIdentityRef.current = identity;
75036
+ const ownWriteToken = consumeStudioWriteToken(token);
75037
+ const ownContentEcho = content != null && isSelfWriteEcho(path, content);
75038
+ if (ownWriteToken || ownContentEcho) {
75039
+ onAcceptedPersistedFileChange(path);
75040
+ logReload("suppressed", {
75041
+ path,
75042
+ why: ownWriteToken ? "own write token" : "own content echo"
75043
+ });
75044
+ return;
75045
+ }
75046
+ pendingPayloadRef.current = { payload };
75047
+ void startDrainLoop();
75048
+ },
75049
+ [projectId, pendingTimelineEditPathRef, startDrainLoop, onAcceptedPersistedFileChange]
75050
+ );
75026
75051
  useEffect106(() => {
75027
75052
  const handler = (payload) => processChange(payload);
75028
75053
  const adapter = testHotAdapter();
@@ -75043,7 +75068,7 @@ function useExternalFileChangeCoordinator({
75043
75068
  if (!current || current.status === "conflict" || current.recovered) return;
75044
75069
  resetSaveQueues?.();
75045
75070
  lastEventIdentityRef.current = null;
75046
- await processChange(current.payload, true);
75071
+ processChange(current.payload);
75047
75072
  }, [processChange, resetSaveQueues]);
75048
75073
  const useExternalFile = useCallback125(
75049
75074
  // fallow-ignore-next-line complexity
@@ -86210,7 +86235,7 @@ function DesignPanelPromoteProvider({
86210
86235
 
86211
86236
  // src/components/editor/colorGradingScopePatch.ts
86212
86237
  var MEDIA_TAG_RE = /<\s*(video|img)\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi;
86213
- var COLOR_GRADING_ATTR_RE = /\sdata-color-grading=(["'])([\s\S]*?)\1/i;
86238
+ var COLOR_GRADING_ATTR_RE = /\sdata-color-grading=(?:"[^"]*"|'[^']*')/i;
86214
86239
  var IGNORED_HTML_RANGE_RE = /<!--[\s\S]*?-->|<(script|style)\b[\s\S]*?<\/\1\s*>/gi;
86215
86240
  function collectIgnoredRanges(html2) {
86216
86241
  const ranges = [];
@@ -90168,11 +90193,11 @@ function parseStyleString(style) {
90168
90193
  function mergeStyleIntoTag(tag, newStyles) {
90169
90194
  if (!newStyles.trim()) return tag;
90170
90195
  const incoming = parseStyleString(newStyles);
90171
- const styleAttrRe = /style=(["'])([\s\S]*?)\1/;
90196
+ const styleAttrRe = /style=(")([^"]*)"|style=(')([^']*)'/;
90172
90197
  const match = tag.match(styleAttrRe);
90173
90198
  if (match) {
90174
- const quote = match[1];
90175
- const existing = parseStyleString(match[2]);
90199
+ const quote = match[1] ?? match[3];
90200
+ const existing = parseStyleString(match[2] ?? match[4]);
90176
90201
  const merged = { ...existing, ...incoming };
90177
90202
  const serialized2 = Object.entries(merged).map(([k, v]) => `${k}: ${v}`).join("; ");
90178
90203
  return tag.replace(styleAttrRe, `style=${quote}${serialized2}${quote}`);