fix: update rpx unit calculation and support container-based viewport…#2469
fix: update rpx unit calculation and support container-based viewport…#2469PupilTong merged 2 commits intolynx-family:mainfrom
Conversation
🦋 Changeset detectedLatest commit: c792e40 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📝 WalkthroughWalkthroughUpdated CSS unit defaults to container-query units ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
4931feb to
68029ae
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts (1)
395-398: These assertions no longer cover the new default--rpx-unit.Overriding
--rpx-unitto1cqwin both cases only tests the manual override path; it no longer exercises the defaultcalc(1cqw / 750)introduced inpackages/web-platform/web-core/css/index.cssLines 13-16. Please keep at least one case on the default path so this regression stays covered.Also applies to: 408-410
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts` around lines 395 - 398, The test currently overrides the CSS variable using lynxView.evaluate and node.style.setProperty('--rpx-unit', '1cqw'), which means it only exercises the manual override path; change one of the test cases so it does not set --rpx-unit (remove the node.style.setProperty call) or add a separate evaluation that leaves the variable unset so the default calc(1cqw / 750) path in packages/web-platform/web-core/css/index.css is exercised; keep the other case that explicitly sets '--rpx-unit' to verify the override behavior, referencing the lynxView.evaluate block and the node.style.width assignment to locate where to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.changeset/red-pears-kiss.md:
- Line 5: Update the user-facing release note text so it uses proper grammar:
change the sentence "transformVH not work with cqw unit as the base length" to a
clearer phrasing such as "transformVH does not work with cqw unit as the base
length" (or similar) in the generated changelog entry for transformVH so the
changelog reads correctly.
In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts`:
- Around line 460-463: The test sets CSS on a DOM node using node.style.weight
which is invalid; update the styling to use node.style.width instead so the
intended width is applied (keep the other properties node.style.height,
node.style.minHeight, node.style.minWidth unchanged) in the reactlynx.spec.ts
test where the styles are assigned.
In `@packages/web-platform/web-core/css/index.css`:
- Around line 19-20: The new rule setting container-type: size on
lynx-view[transform-vh] forces size containment and prevents contain: content
from acting as an escape hatch; update the CSS so transform-vh does not apply
size containment when the element is intended to auto-size (e.g., change the
selector to lynx-view[transform-vh]:not([height="auto"]):not([width="auto"]) or
add an alternative rule that omits container-type for
lynx-view[height="auto"][transform-vh] and
lynx-view[width="auto"][transform-vh]), and add a regression test that verifies
lynx-view[height="auto"][transform-vh] can grow with its contents.
---
Nitpick comments:
In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts`:
- Around line 395-398: The test currently overrides the CSS variable using
lynxView.evaluate and node.style.setProperty('--rpx-unit', '1cqw'), which means
it only exercises the manual override path; change one of the test cases so it
does not set --rpx-unit (remove the node.style.setProperty call) or add a
separate evaluation that leaves the variable unset so the default calc(1cqw /
750) path in packages/web-platform/web-core/css/index.css is exercised; keep the
other case that explicitly sets '--rpx-unit' to verify the override behavior,
referencing the lynxView.evaluate block and the node.style.width assignment to
locate where to change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a4c499dd-359c-4e43-bec0-8ff2e47fab46
📒 Files selected for processing (4)
.changeset/red-pears-kiss.md.changeset/warm-zoos-prove.mdpackages/web-platform/web-core-e2e/tests/reactlynx.spec.tspackages/web-platform/web-core/css/index.css
React External#531 Bundle Size — 580.35KiB (0%).c792e40(current) vs 3118b10 main#524(baseline) Bundle metrics
|
| Current #531 |
Baseline #524 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
3 |
3 |
|
17 |
17 |
|
5 |
5 |
|
8.59% |
8.59% |
|
0 |
0 |
|
0 |
0 |
Bundle analysis report Branch PupilTong:p/hw/fix-cqh-vh Project dashboard
Generated by RelativeCI Documentation Report issue
React MTF Example#547 Bundle Size — 193.94KiB (0%).c792e40(current) vs 3118b10 main#540(baseline) Bundle metrics
|
| Current #547 |
Baseline #540 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
3 |
3 |
|
173 |
173 |
|
66 |
66 |
|
43.94% |
43.94% |
|
2 |
2 |
|
0 |
0 |
Bundle size by type no changes
| Current #547 |
Baseline #540 |
|
|---|---|---|
111.23KiB |
111.23KiB |
|
82.71KiB |
82.71KiB |
Bundle analysis report Branch PupilTong:p/hw/fix-cqh-vh Project dashboard
Generated by RelativeCI Documentation Report issue
Web Explorer#8988 Bundle Size — 898.4KiB (~+0.01%).c792e40(current) vs 3118b10 main#8981(baseline) Bundle metrics
Bundle size by type
Bundle analysis report Branch PupilTong:p/hw/fix-cqh-vh Project dashboard Generated by RelativeCI Documentation Report issue |
React Example#7414 Bundle Size — 223.33KiB (0%).c792e40(current) vs 3118b10 main#7407(baseline) Bundle metrics
|
| Current #7414 |
Baseline #7407 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
4 |
4 |
|
179 |
179 |
|
69 |
69 |
|
44.48% |
44.48% |
|
2 |
2 |
|
0 |
0 |
Bundle size by type no changes
| Current #7414 |
Baseline #7407 |
|
|---|---|---|
145.76KiB |
145.76KiB |
|
77.58KiB |
77.58KiB |
Bundle analysis report Branch PupilTong:p/hw/fix-cqh-vh Project dashboard
Generated by RelativeCI Documentation Report issue
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts (1)
457-463:⚠️ Potential issue | 🟠 MajorUse
widthinstead of invalidstyle.weight.Line 461 assigns
node.style.weight, which is ignored byCSSStyleDeclaration. That can leave width uncontrolled and make the250pxassertions unstable.Proposed fix
await lynxView.evaluate((node: any) => { node.transformVW = true; node.transformVH = true; node.style.height = '500px'; - node.style.weight = '500px'; + node.style.width = '500px'; node.style.minHeight = '500px'; node.style.minWidth = '500px'; node.style.setProperty('--vh-unit', '1cqh'); node.style.setProperty('--vw-unit', '1cqw'); node.reload(); });#!/bin/bash # Verify no invalid CSSStyleDeclaration `style.weight` writes remain in this test file rg -nP '\bstyle\.weight\s*=' packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts # Expected result after fix: # - no matches🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts` around lines 457 - 463, The test mistakenly sets an invalid CSS property node.style.weight inside the lynxView.evaluate block; replace any assignments to node.style.weight with node.style.width (e.g., in the evaluate callback where transformVW/VH are set and height/minHeight/minWidth are assigned) so the test actually controls element width and removes the invalid CSS write that breaks assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts`:
- Around line 457-463: The test mistakenly sets an invalid CSS property
node.style.weight inside the lynxView.evaluate block; replace any assignments to
node.style.weight with node.style.width (e.g., in the evaluate callback where
transformVW/VH are set and height/minHeight/minWidth are assigned) so the test
actually controls element width and removes the invalid CSS write that breaks
assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 40741142-6f7b-4e5a-aff8-90f77df19b3f
📒 Files selected for processing (4)
.changeset/red-pears-kiss.md.changeset/warm-zoos-prove.mdpackages/web-platform/web-core-e2e/tests/reactlynx.spec.tspackages/web-platform/web-core/css/index.css
✅ Files skipped from review due to trivial changes (2)
- .changeset/red-pears-kiss.md
- .changeset/warm-zoos-prove.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web-platform/web-core/css/index.css
Merging this PR will improve performance by 16.81%
Performance Changes
Comparing Footnotes
|
### Problem The web example preview embeds Lynx content inside a `<lynx-view>` container. Unit conversion for `rpx` / `vh` / `vw` could end up behaving like “browser viewport based” instead of “preview container based”, causing layout/scale differences compared to mobile expectations. ### What changed - Enabled container query sizing on the `<lynx-view>` host via `containerType: 'size'`. - Defined container-relative unit hooks via CSS custom properties on the host: - `--vh-unit: 1cqh` - `--vw-unit: 1cqw` - `--rpx-unit: calc(100cqw / 750)` (750 design width baseline) - Added a small TypeScript helper type to allow `--*` custom properties on `style` without errors, and moved the style object to a module-level constant to avoid re-creating it on each render. ### Result Web preview sizing becomes container-relative and closer to mobile behavior for `rpx` scaling and `vh/vw`-driven layouts. ### Verification - `pnpm -s typecheck` ### Related - Relates to lynx-family/lynx-stack#2469
… units for transformVH
68029ae to
c792e40
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts (1)
395-410:⚠️ Potential issue | 🟡 MinorKeep one rpx assertion on the default unit value.
Both updated rpx cases override
--rpx-unitto1cqw, so they no longer catch regressions in the new default--rpx-unit: calc(1cqw / 7.5)frompackages/web-platform/web-core/css/index.css. Please leave at least one case using the default, or add a separate default-coverage assertion.Example adjustment for a default-unit assertion
const lynxView = await page.locator('lynx-view'); await lynxView.evaluate((node) => { - node.style.width = '50px'; - node.style.setProperty('--rpx-unit', '1cqw'); + node.style.width = '750px'; }); const target = await page.locator('#target'); - await expect(target).toHaveCSS('height', '10px'); // 20cqw, 50 / 100 * 20 = 10px - await expect(target).toHaveCSS('width', '10px'); + await expect(target).toHaveCSS('height', '20px'); // 20rpx with default calc(1cqw / 7.5) + await expect(target).toHaveCSS('width', '20px');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts` around lines 395 - 410, The two rpx tests both set --rpx-unit to '1cqw', so they no longer validate the default unit; update the tests so at least one assertion checks behavior with the default --rpx-unit (either remove the node.style.setProperty('--rpx-unit', ...) call from one of the tests like 'basic-rpx-unit-js-value' or add a new assertion/test that leaves --rpx-unit untouched), then assert the expected height/width on the same locator (target) to cover the default calc(1cqw / 7.5) value; adjust only the test setup for lynxView.evaluate and keep the existing expect(target).toHaveCSS checks for that default-case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts`:
- Around line 395-410: The two rpx tests both set --rpx-unit to '1cqw', so they
no longer validate the default unit; update the tests so at least one assertion
checks behavior with the default --rpx-unit (either remove the
node.style.setProperty('--rpx-unit', ...) call from one of the tests like
'basic-rpx-unit-js-value' or add a new assertion/test that leaves --rpx-unit
untouched), then assert the expected height/width on the same locator (target)
to cover the default calc(1cqw / 7.5) value; adjust only the test setup for
lynxView.evaluate and keep the existing expect(target).toHaveCSS checks for that
default-case.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: dcb7173b-f685-4260-b701-de965687cec4
📒 Files selected for processing (4)
.changeset/red-pears-kiss.md.changeset/warm-zoos-prove.mdpackages/web-platform/web-core-e2e/tests/reactlynx.spec.tspackages/web-platform/web-core/css/index.css
✅ Files skipped from review due to trivial changes (2)
- .changeset/warm-zoos-prove.md
- .changeset/red-pears-kiss.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web-platform/web-core/css/index.css
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @lynx-js/react@0.120.0 ### Minor Changes - Bump `@lynx-js/internal-preact` from `10.28.4-dfff9aa` to `10.29.1-20260424024911-12b794f` ([diff](lynx-family/internal-preact@10.28.4-dfff9aa...10.29.1-20260424024911-12b794f)). ([#2512](#2512)) Fixes wrong DOM order when a keyed child moves to a different `$N` slot across a re-render. Cross-slot moves now land at the correct slot position instead of being appended past stable siblings. - Refactor preact to support multi-slots children and reduce the number and depth of snapshot. ([#1764](#1764)) ### Patch Changes - Fix stale callback-local references when transforming JSX inside `children={array.map(...)}` prop expressions. ([#2524](#2524)) - Fix ref callbacks not being cleaned up or re-applied correctly when the ref at the same element slot changes across rerenders that happen before hydration (e.g. a `useEffect` triggering `setState` during the initial background render). ([#2500](#2500)) - fix: reduce redundant updates for main-thread handlers and gestures ([#2188](#2188)) - Updates are faster when the main-thread event handler or gesture object is stable across rerenders (fewer unnecessary native updates). - Spread props rerenders that don't semantically change the handler/gesture no longer trigger redundant updates. - Removing a gesture from spread props reliably clears the gesture state on the target element. - Fix hydration edge cases by tolerating serialized snapshot nodes with missing `values` ([#2481](#2481)) - Keep ReactLynx Testing Library imports aligned with the contained snapshot runtime paths. ([#2498](#2498)) ## @lynx-js/template-webpack-plugin@0.11.0 ### Minor Changes - Add CSS source map support and source-mapped template encode diagnostics. ([#2483](#2483)) ### Patch Changes - fix: genStyleInfo should also preserve CSS variable fallback values when encoding web-core stylesheets so declarations like `var(--token, rgba(...))` are emitted with their fallback intact. ([#2502](#2502)) - Updated dependencies \[[`e179680`](e179680), [`8352530`](8352530), [`30f0277`](30f0277), [`887b8aa`](887b8aa), [`1d4abfc`](1d4abfc), [`25e196b`](25e196b), [`fb7bc84`](fb7bc84), [`9e149c4`](9e149c4), [`30f0277`](30f0277), [`9e149c4`](9e149c4)]: - @lynx-js/css-serializer@0.1.6 - @lynx-js/web-core@0.20.3 ## @lynx-js/i18next-translation-dedupe@0.0.1 ### Patch Changes - Introduce `@lynx-js/i18next-translation-dedupe` package to avoid bundling i18next translations twice in Lynx apps. ([#2482](#2482)) The package reads translations extracted by `rsbuild-plugin-i18next-extractor`, skips the extractor's default rendered asset, and writes the translations into the Lynx bundle custom section: ```json { "customSections": { "i18next-translations": { "content": { "en-US": { "hello": "Hello" }, "zh-CN": { "hello": "你好" } } } } } ``` ## @lynx-js/docs-mcp-server@0.2.2 ### Patch Changes - Fix Windows startup error. ([#2474](#2474)) ## @lynx-js/react-umd@0.120.0 ### Patch Changes - Support compile main-thread script to bytecode in external bundle ([#2459](#2459)) ## @lynx-js/rspeedy@0.14.3 ### Patch Changes - add a `sourceMap.css` option to emit CSS sourcemaps. ([#2442](#2442)) By default, `sourceMap.css` is false. You can set it to true to emit CSS sourcemaps. ```js import { defineConfig } from "@lynx-js/rspeedy"; export default defineConfig({ output: { sourceMap: { css: true, }, }, }); ``` - bump rsdoctor to 1.5.6 ([#2410](#2410)) - Enable CSS source maps by default in Rspeedy output config. ([#2483](#2483)) - Prefer physical routable IPv4 addresses over tunnel and link-local interfaces when resolving the dev host IP for generated preview and bundle URLs. ([#2409](#2409)) - Updated dependencies \[]: - @lynx-js/web-rsbuild-server-middleware@0.20.3 ## @lynx-js/lynx-bundle-rslib-config@0.3.2 ### Patch Changes - Support compile main-thread script to bytecode in external bundle ([#2459](#2459)) - Updated dependencies \[[`e179680`](e179680)]: - @lynx-js/css-serializer@0.1.6 ## @lynx-js/react-rsbuild-plugin@0.16.1 ### Patch Changes - Respect `dev.hmr: false` when installing React Refresh integrations so disabled HMR no longer injects the refresh loader or plugin. ([#2487](#2487)) - Fix stale callback-local references when transforming JSX inside `children={array.map(...)}` prop expressions. ([#2524](#2524)) - Supports @lynx-js/react 0.120.0 ([#1764](#1764)) - Updated dependencies \[[`e179680`](e179680), [`13655ac`](13655ac), [`f15494b`](f15494b), [`e179680`](e179680), [`e179680`](e179680)]: - @lynx-js/template-webpack-plugin@0.11.0 - @lynx-js/css-extract-webpack-plugin@0.7.1 - @lynx-js/react-webpack-plugin@0.9.2 - @lynx-js/react-alias-rsbuild-plugin@0.16.1 - @lynx-js/use-sync-external-store@1.5.0 - @lynx-js/react-refresh-webpack-plugin@0.3.5 ## @lynx-js/css-serializer@0.1.6 ### Patch Changes - Add CSS source map support and source-mapped template encode diagnostics. ([#2483](#2483)) ## @lynx-js/web-core@0.20.3 ### Patch Changes - fix: `__AddClass` triggers style updates when `enableCSSSelector` is `false` ([#2515](#2515)) `__AddClass` was missing the expected call to `update_css_og_style` when CSS selectors are disabled (`enableCSSSelector: false`). With this fix, dynamically adding a class correctly delegates style population from the template AST into the DOM, mirroring the behavior of `__SetClasses`. Added behavioral unit test and end-to-end playwright validations using dynamically generated JSON AST `styleInfo` mocks. - fix(web-core): skip setting lynxEntryNameAttribute for **Card** and use constants for server element APIs ([#2510](#2510)) - Fix componentCSSID behavior for SSR and main thread by calculating element css_id from parent component correctly. ([#2495](#2495)) - fix: avoid panic in dispatch_event_by_path when element data cannot be retrieved ([#2508](#2508)) - fix: filter out -1 uniqueId in commonEventHandler ([#2493](#2493)) - feat: add x-markdown support ([#2412](#2412)) Add opt-in support for the `x-markdown` element on Lynx Web, including Markdown rendering together with its related styling, interaction, animation, truncation, range rendering, and effect capabilities exposed through the component API. Update the `web-core`, `web-core-wasm`, and `web-mainthread-apis` runtime paths to use the shared property-or-attribute setter from `web-constants`, so custom elements such as `x-markdown` can receive structured property values correctly instead of being forced through string-only attribute updates. ```javascript import "@lynx-js/web-elements/XMarkdown"; ``` - fix: transformVH not work with cqw unit as the base length ([#2469](#2469)) - fix: add cardType resolution for legacy json lynx bundle ([#2510](#2510)) - fix: the default value of rpx is supposed to be 1/750 cqw ([#2469](#2469)) - Updated dependencies \[[`e179680`](e179680), [`647334c`](647334c), [`fb7bc84`](fb7bc84), [`9454dc4`](9454dc4), [`bdec498`](bdec498), [`b0247f9`](b0247f9), [`eec539a`](eec539a)]: - @lynx-js/css-serializer@0.1.6 - @lynx-js/web-elements@0.12.1 - @lynx-js/web-worker-rpc@0.20.3 ## @lynx-js/web-elements@0.12.1 ### Patch Changes - fix: XMarkdown slot created should not have prefix ([#2520](#2520)) - feat: add x-markdown support ([#2412](#2412)) Add opt-in support for the `x-markdown` element on Lynx Web, including Markdown rendering together with its related styling, interaction, animation, truncation, range rendering, and effect capabilities exposed through the component API. Update the `web-core`, `web-core-wasm`, and `web-mainthread-apis` runtime paths to use the shared property-or-attribute setter from `web-constants`, so custom elements such as `x-markdown` can receive structured property values correctly instead of being forced through string-only attribute updates. ```javascript import "@lynx-js/web-elements/XMarkdown"; ``` - fix: x-markdown inline view injection no longer queries light DOM children when the content attribute changes. Consumers must now pre-set `slot="{id}"` on the child element they want to project into `inlineview://{id}`. ([#2516](#2516)) - fix: list cannot drag-scroll inside x-foldview-slot-ng ([#2507](#2507)) Cause: `touchstart` used `elementsFromPoint(pageX, pageY)` (expects `clientX/clientY`), so hit-testing can miss the real inner scroller (e.g. `x-list` shadow `#content`) when the document is scrolled. Fix: use `elementsFromPoint(clientX, clientY)` + `event.composedPath()` for Shadow DOM, and keep `previousPageX` updated during `touchmove`. - fix: line-height of markdown-style should be added `px` ([#2509](#2509)) - fix: list `bindscrolltolower` may not trigger because the lower threshold ([#2484](#2484)) sentinel had no effective size or offset, causing the bottom `IntersectionObserver` to miss the list boundary ## @lynx-js/web-explorer@0.0.17 ### Patch Changes - bump rsdoctor to 1.5.6 ([#2410](#2410)) ## @lynx-js/css-extract-webpack-plugin@0.7.1 ### Patch Changes - Fix CSS source map line offsets when wrapping extracted CSS with cssId metadata. ([#2514](#2514)) - Support `@lynx-js/template-webpack-plugin` v0.11.0. ([#2483](#2483)) ## @lynx-js/react-webpack-plugin@0.9.2 ### Patch Changes - Support `@lynx-js/template-webpack-plugin` v0.11.0. ([#2483](#2483)) ## create-rspeedy@0.14.3 ## @lynx-js/react-alias-rsbuild-plugin@0.16.1 ## upgrade-rspeedy@0.14.3 ## @lynx-js/web-rsbuild-server-middleware@0.20.3 ## @lynx-js/web-worker-rpc@0.20.3 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
… units for transformVH
Summary by CodeRabbit
Bug Fixes
Style
Tests
Checklist