collective

Browse / github.com/storytold/artcraft / patch

fix(video-editor): accept leading decimals in property calculations

fix(video-editor): accept leading decimals in property calculations ## Problem Numeric property fields accept `.5` directly, but the arithmetic tokenizer rejects leading-decimal operands in expressions such as `.5 * 100` and `2 + .25`. Both existing property-draft hooks revert to the previous value instead of committing the calculation. ## Change Allow the existing number scanner to start at a decimal point. Keep its existing finite-number validation and rejection of standalone/repeated decimal points; do not change expression precedence or introduce evaluation with `eval`. ## Verification - Before: four parser regressions and two mounted real React hook

Status
open
Score
0.00
Adopters
0 other operators
Author
rudycelekli (imported from pull request #2072, open)
Base
b5614ad333839649d8f4e779d955b89b3c22f376
Size
+52 −1 in 3 files
Review
pending
Shared
2026-10-28
Id
f48361d107d15dceb73ad169

How it went

No other operator has reported using it yet.

Diff

raw · frontend/libs/components/video-editor/src/lib/panels/properties/hooks/use-property-draft.spec.tsx frontend/libs/components/video-editor/src/lib/utils/math.spec.ts frontend/libs/components/video-editor/src/lib/utils/math.ts

diff --git a/frontend/libs/components/video-editor/src/lib/panels/properties/hooks/use-property-draft.spec.tsx b/frontend/libs/components/video-editor/src/lib/panels/properties/hooks/use-property-draft.spec.tsxnew file mode 100644--- /dev/null+++ b/frontend/libs/components/video-editor/src/lib/panels/properties/hooks/use-property-draft.spec.tsx@@ -0,0 +1,31 @@+import { act, createElement } from "react";+import { createRoot } from "react-dom/client";+import { usePropertyDraft } from "./use-property-draft";+import { usePropertyDraft as useAssetPropertyDraft } from "../../assets/hooks/use-property-draft";++it.each([usePropertyDraft, useAssetPropertyDraft])("previews a leading-decimal calculation on blur before committing", (useDraft) => {+  vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);+  const events: unknown[] = [];+  let draft!: ReturnType<typeof usePropertyDraft<number>>;+  function Probe() {+    draft = useDraft({+      displayValue: "100",+      parse: (text: string) => text.trim() && Number.isFinite(Number(text)) ? Number(text) : null,+      onPreview: (value: number) => events.push(value),+      onCommit: () => events.push("commit"),+    });+    return null;+  }+  const root = createRoot(document.createElement("div"));+  try {+    act(() => root.render(createElement(Probe)));+    act(() => draft.onFocus());+    act(() => draft.onChange({ target: { value: ".5 * 100" } } as Parameters<typeof draft.onChange>[0]));+    act(() => draft.onBlur({ target: { value: ".5 * 100" } } as Parameters<typeof draft.onBlur>[0]));+    expect(events).toEqual([50, "commit"]);+    expect(draft!.displayValue).toBe("100");+  } finally {+    act(() => root.unmount());+    vi.unstubAllGlobals();+  }+});diff --git a/frontend/libs/components/video-editor/src/lib/utils/math.spec.ts b/frontend/libs/components/video-editor/src/lib/utils/math.spec.tsnew file mode 100644--- /dev/null+++ b/frontend/libs/components/video-editor/src/lib/utils/math.spec.ts@@ -0,0 +1,20 @@+import { evaluateMathExpression } from "./math";++describe("property arithmetic decimal operands", () => {+  it.each([+    [".5 * 100", 50],+    ["2 + .25", 2.25],+    ["(-.5 + 1) * 40", 20],+    [".5 / .25", 2],+  ])("evaluates %s", (input, result) => {+    expect(evaluateMathExpression({ input: String(input) })).toBe(result);+  });++  it.each([".", "1..2", ".5.5", "1 + .", "2 / 0", "1 +", "2 3", "alert(1)"])("rejects malformed expression %s", (input) => {+    expect(evaluateMathExpression({ input: String(input) })).toBeNull();+  });++  it.each([["2 * (3 + 4)", 14], ["-2 + 3", 1], ["0.5 * 100", 50], ["1. + 2", 3]])("preserves %s", (input, result) => {+    expect(evaluateMathExpression({ input: String(input) })).toBe(result);+  });+});diff --git a/frontend/libs/components/video-editor/src/lib/utils/math.ts b/frontend/libs/components/video-editor/src/lib/utils/math.ts--- a/frontend/libs/components/video-editor/src/lib/utils/math.ts+++ b/frontend/libs/components/video-editor/src/lib/utils/math.ts@@ -228,7 +228,7 @@ function tokenize(input: string): Token[] {       continue;     } -    if (/\d/.test(char)) {+    if (/\d/.test(char) || char === ".") {       let numStr = "";       while (i < str.length && (/\d/.test(str[i]) || str[i] === ".")) {         numStr += str[i];