diff --git a/.changeset/transform-rpx.md b/.changeset/transform-rpx.md new file mode 100644 index 0000000000..25d137b26f --- /dev/null +++ b/.changeset/transform-rpx.md @@ -0,0 +1,46 @@ +--- +"@lynx-js/web-core": minor +--- + +Added support for `rpx` unit + +**This is a breaking change** + +The following Styles has been added to `web-core` + +```css +lynx-view { + width: 100%; + container-name: lynx-view; + container-type: inline-size; + --rpx-unit: 1cqw; +} +``` + +Check MDN for the details about these styles: + +- https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/container-name +- https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/container-type +- https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Container_queries + +### how it works? + +For the following code + +```html + +``` + +it will be transformed to + +```html + +``` + +Therefore you could use any `` value to replace the unit, for example: + +```html + +``` + +By default, the --rpx-unit value is `1cqw` diff --git a/.changeset/transform-vw-vh-support.md b/.changeset/transform-vw-vh-support.md new file mode 100644 index 0000000000..be9996a3c5 --- /dev/null +++ b/.changeset/transform-vw-vh-support.md @@ -0,0 +1,25 @@ +--- +"@lynx-js/web-core": minor +--- + +Added support for transform `vw` and `vh` unit + +Add `transform-vw` and `transform-vh` attributes and properties on ``. + +For the following code + +```html + +``` + +If the `transform-vw` is enabled ``, it will be transformed to + +```html + +``` + +Therefore you could use any `` value to replace the unit, for example: + +```html + +``` diff --git a/packages/web-platform/web-core-e2e/shell-project/devMiddleware.ts b/packages/web-platform/web-core-e2e/shell-project/devMiddleware.ts index 7b06572d34..151b7d724b 100644 --- a/packages/web-platform/web-core-e2e/shell-project/devMiddleware.ts +++ b/packages/web-platform/web-core-e2e/shell-project/devMiddleware.ts @@ -63,6 +63,8 @@ export async function ssrMiddleware( {}, // initData {}, // globalProps {}, // initI18nResources + false, + false, viewAttributes, ); diff --git a/packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts b/packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts index abb4372f3c..47582d386e 100644 --- a/packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts +++ b/packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts @@ -375,6 +375,45 @@ test.describe('reactlynx3 tests', () => { 'rgb(255, 255, 0)', ); // yellow }); + test('basic-rpx-unit', async ({ page }, { title }) => { + await goto(page, title); + await wait(100); + const lynxView = await page.locator('lynx-view'); + await lynxView.evaluate((node) => { + node.style.width = '50px'; + }); + const target = await page.locator('#target'); + await expect(target).toHaveCSS('height', '10px'); // 20cqw, 50 / 100 * 20 = 10px + await expect(target).toHaveCSS('width', '10px'); + }); + + test('basic-vw-vh-unit', async ({ page }, { title }) => { + await goto(page, title); + await wait(100); + const lynxView = await page.locator('lynx-view'); + await lynxView.evaluate((node: any) => { + node.style.setProperty('--vh-unit', '10px'); + node.style.setProperty('--vw-unit', '10px'); + node.transformVW = true; + node.transformVH = true; + node.reload(); + }); + await wait(500); // Wait for the reload to rebuild the CSS properly + + const target = await page.locator('#target'); + await expect(target).toHaveCSS('width', '500px'); + await expect(target).toHaveCSS('height', '500px'); + + // Now disable switches and assert it breaks out of the container dimension limits + await lynxView.evaluate((node: any) => { + node.transformVW = false; + node.transformVH = false; + node.reload(); + }); + await wait(500); // Wait for the reload to rebuild the CSS properly + await expect(target).not.toHaveCSS('width', '25px'); + await expect(target).not.toHaveCSS('height', '50px'); + }); test('basic-image', async ({ page }, { title }) => { await goto(page, title); await wait(100); diff --git a/packages/web-platform/web-core-e2e/tests/reactlynx/basic-rpx-unit/index.jsx b/packages/web-platform/web-core-e2e/tests/reactlynx/basic-rpx-unit/index.jsx new file mode 100644 index 0000000000..465e999001 --- /dev/null +++ b/packages/web-platform/web-core-e2e/tests/reactlynx/basic-rpx-unit/index.jsx @@ -0,0 +1,19 @@ +// Copyright 2023 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { root } from '@lynx-js/react'; + +function App() { + return ( + + ); +} + +root.render(); diff --git a/packages/web-platform/web-core-e2e/tests/reactlynx/basic-vw-vh-unit/index.jsx b/packages/web-platform/web-core-e2e/tests/reactlynx/basic-vw-vh-unit/index.jsx new file mode 100644 index 0000000000..b396803800 --- /dev/null +++ b/packages/web-platform/web-core-e2e/tests/reactlynx/basic-vw-vh-unit/index.jsx @@ -0,0 +1,21 @@ +// Copyright 2023 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { root } from '@lynx-js/react'; + +function App() { + return ( + <> + + + ); +} + +root.render(); diff --git a/packages/web-platform/web-core/binary/client/client.d.ts b/packages/web-platform/web-core/binary/client/client.d.ts index f7b49b5d0b..3100d4c78b 100644 --- a/packages/web-platform/web-core/binary/client/client.d.ts +++ b/packages/web-platform/web-core/binary/client/client.d.ts @@ -160,17 +160,17 @@ export class StyleSheetResource { */ export function add_inline_style_raw_string_key(dom: HTMLElement, key: string, value?: string | null): void; -export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean): Uint8Array; +export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean, transform_vw: boolean, transform_vh: boolean): Uint8Array; -export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name?: string | null): Uint8Array; +export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name: string | null | undefined, transform_vw: boolean, transform_vh: boolean): Uint8Array; export function get_font_face_content(buffer: Uint8Array): string; -export function get_inline_styles_in_key_value_vec(dom: HTMLElement, k_v_vec: string[]): void; +export function get_inline_styles_in_key_value_vec(dom: HTMLElement, k_v_vec: string[], transform_vw: boolean, transform_vh: boolean): void; export function get_style_content(buffer: Uint8Array): string; -export function set_inline_styles_in_str(dom: HTMLElement, styles: string): boolean; +export function set_inline_styles_in_str(dom: HTMLElement, styles: string, transform_vw: boolean, transform_vh: boolean): boolean; export function set_inline_styles_number_key(dom: HTMLElement, key: number, value?: string | null): void; @@ -192,10 +192,10 @@ export interface InitOutput { readonly __wbg_set_eventinfo_event_type: (a: number, b: number, c: number) => void; readonly __wbg_stylesheetresource_free: (a: number, b: number) => void; readonly add_inline_style_raw_string_key: (a: any, b: number, c: number, d: number, e: number) => void; - readonly decode_style_info: (a: any, b: number, c: number, d: number) => [number, number, number]; - readonly encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number) => [number, number, number]; + readonly decode_style_info: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; + readonly encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; readonly get_font_face_content: (a: any) => [number, number, number, number]; - readonly get_inline_styles_in_key_value_vec: (a: any, b: number, c: number) => void; + readonly get_inline_styles_in_key_value_vec: (a: any, b: number, c: number, d: number, e: number) => void; readonly get_style_content: (a: any) => [number, number, number, number]; readonly mainthreadwasmcontext_add_cross_thread_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void; readonly mainthreadwasmcontext_add_dataset: (a: number, b: number, c: any, d: any) => [number, number]; @@ -232,7 +232,7 @@ export interface InitOutput { readonly ruleprelude_new: () => number; readonly ruleprelude_push_selector: (a: number, b: number) => void; readonly selector_push_one_selector_section: (a: number, b: number, c: number, d: number, e: number) => [number, number]; - readonly set_inline_styles_in_str: (a: any, b: number, c: number) => number; + readonly set_inline_styles_in_str: (a: any, b: number, c: number, d: number, e: number) => number; readonly set_inline_styles_number_key: (a: any, b: number, c: number, d: number) => void; readonly stylesheetresource_new: (a: any, b: any) => [number, number, number]; readonly selector_new: () => number; diff --git a/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts b/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts index cf988009f1..74ec77f513 100644 --- a/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts +++ b/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts @@ -15,10 +15,10 @@ export const __wbg_set_eventinfo_event_name: (a: number, b: number, c: number) = export const __wbg_set_eventinfo_event_type: (a: number, b: number, c: number) => void; export const __wbg_stylesheetresource_free: (a: number, b: number) => void; export const add_inline_style_raw_string_key: (a: any, b: number, c: number, d: number, e: number) => void; -export const decode_style_info: (a: any, b: number, c: number, d: number) => [number, number, number]; -export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number) => [number, number, number]; +export const decode_style_info: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; +export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; export const get_font_face_content: (a: any) => [number, number, number, number]; -export const get_inline_styles_in_key_value_vec: (a: any, b: number, c: number) => void; +export const get_inline_styles_in_key_value_vec: (a: any, b: number, c: number, d: number, e: number) => void; export const get_style_content: (a: any) => [number, number, number, number]; export const mainthreadwasmcontext_add_cross_thread_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void; export const mainthreadwasmcontext_add_dataset: (a: number, b: number, c: any, d: any) => [number, number]; @@ -55,7 +55,7 @@ export const rule_set_prelude: (a: number, b: number) => void; export const ruleprelude_new: () => number; export const ruleprelude_push_selector: (a: number, b: number) => void; export const selector_push_one_selector_section: (a: number, b: number, c: number, d: number, e: number) => [number, number]; -export const set_inline_styles_in_str: (a: any, b: number, c: number) => number; +export const set_inline_styles_in_str: (a: any, b: number, c: number, d: number, e: number) => number; export const set_inline_styles_number_key: (a: any, b: number, c: number, d: number) => void; export const stylesheetresource_new: (a: any, b: any) => [number, number, number]; export const selector_new: () => number; diff --git a/packages/web-platform/web-core/binary/client_legacy/client.d.ts b/packages/web-platform/web-core/binary/client_legacy/client.d.ts index a3ff317fb4..bd1e5937ee 100644 --- a/packages/web-platform/web-core/binary/client_legacy/client.d.ts +++ b/packages/web-platform/web-core/binary/client_legacy/client.d.ts @@ -160,17 +160,17 @@ export class StyleSheetResource { */ export function add_inline_style_raw_string_key(dom: HTMLElement, key: string, value?: string | null): void; -export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean): Uint8Array; +export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean, transform_vw: boolean, transform_vh: boolean): Uint8Array; -export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name?: string | null): Uint8Array; +export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name: string | null | undefined, transform_vw: boolean, transform_vh: boolean): Uint8Array; export function get_font_face_content(buffer: Uint8Array): string; -export function get_inline_styles_in_key_value_vec(dom: HTMLElement, k_v_vec: string[]): void; +export function get_inline_styles_in_key_value_vec(dom: HTMLElement, k_v_vec: string[], transform_vw: boolean, transform_vh: boolean): void; export function get_style_content(buffer: Uint8Array): string; -export function set_inline_styles_in_str(dom: HTMLElement, styles: string): boolean; +export function set_inline_styles_in_str(dom: HTMLElement, styles: string, transform_vw: boolean, transform_vh: boolean): boolean; export function set_inline_styles_number_key(dom: HTMLElement, key: number, value?: string | null): void; @@ -192,10 +192,10 @@ export interface InitOutput { readonly __wbg_set_eventinfo_event_type: (a: number, b: number, c: number) => void; readonly __wbg_stylesheetresource_free: (a: number, b: number) => void; readonly add_inline_style_raw_string_key: (a: number, b: number, c: number, d: number, e: number) => void; - readonly decode_style_info: (a: number, b: number, c: number, d: number, e: number) => void; - readonly encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number) => void; + readonly decode_style_info: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; + readonly encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; readonly get_font_face_content: (a: number, b: number) => void; - readonly get_inline_styles_in_key_value_vec: (a: number, b: number, c: number) => void; + readonly get_inline_styles_in_key_value_vec: (a: number, b: number, c: number, d: number, e: number) => void; readonly get_style_content: (a: number, b: number) => void; readonly mainthreadwasmcontext_add_cross_thread_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void; readonly mainthreadwasmcontext_add_dataset: (a: number, b: number, c: number, d: number, e: number) => void; @@ -232,7 +232,7 @@ export interface InitOutput { readonly ruleprelude_new: () => number; readonly ruleprelude_push_selector: (a: number, b: number) => void; readonly selector_push_one_selector_section: (a: number, b: number, c: number, d: number, e: number, f: number) => void; - readonly set_inline_styles_in_str: (a: number, b: number, c: number) => number; + readonly set_inline_styles_in_str: (a: number, b: number, c: number, d: number, e: number) => number; readonly set_inline_styles_number_key: (a: number, b: number, c: number, d: number) => void; readonly stylesheetresource_new: (a: number, b: number, c: number) => void; readonly selector_new: () => number; diff --git a/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts b/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts index 961e45132a..796a125ae4 100644 --- a/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts +++ b/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts @@ -15,10 +15,10 @@ export const __wbg_set_eventinfo_event_name: (a: number, b: number, c: number) = export const __wbg_set_eventinfo_event_type: (a: number, b: number, c: number) => void; export const __wbg_stylesheetresource_free: (a: number, b: number) => void; export const add_inline_style_raw_string_key: (a: number, b: number, c: number, d: number, e: number) => void; -export const decode_style_info: (a: number, b: number, c: number, d: number, e: number) => void; -export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number) => void; +export const decode_style_info: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; +export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; export const get_font_face_content: (a: number, b: number) => void; -export const get_inline_styles_in_key_value_vec: (a: number, b: number, c: number) => void; +export const get_inline_styles_in_key_value_vec: (a: number, b: number, c: number, d: number, e: number) => void; export const get_style_content: (a: number, b: number) => void; export const mainthreadwasmcontext_add_cross_thread_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void; export const mainthreadwasmcontext_add_dataset: (a: number, b: number, c: number, d: number, e: number) => void; @@ -55,7 +55,7 @@ export const rule_set_prelude: (a: number, b: number) => void; export const ruleprelude_new: () => number; export const ruleprelude_push_selector: (a: number, b: number) => void; export const selector_push_one_selector_section: (a: number, b: number, c: number, d: number, e: number, f: number) => void; -export const set_inline_styles_in_str: (a: number, b: number, c: number) => number; +export const set_inline_styles_in_str: (a: number, b: number, c: number, d: number, e: number) => number; export const set_inline_styles_number_key: (a: number, b: number, c: number, d: number) => void; export const stylesheetresource_new: (a: number, b: number, c: number) => void; export const selector_new: () => number; diff --git a/packages/web-platform/web-core/binary/encode/encode.d.ts b/packages/web-platform/web-core/binary/encode/encode.d.ts index b789cb0c47..6844850a6a 100644 --- a/packages/web-platform/web-core/binary/encode/encode.d.ts +++ b/packages/web-platform/web-core/binary/encode/encode.d.ts @@ -109,9 +109,9 @@ export class StyleInfoDecoder { [Symbol.dispose](): void; } -export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean): Uint8Array; +export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean, transform_vw: boolean, transform_vh: boolean): Uint8Array; -export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name?: string | null): Uint8Array; +export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name: string | null | undefined, transform_vw: boolean, transform_vh: boolean): Uint8Array; export function get_font_face_content(buffer: Uint8Array): string; diff --git a/packages/web-platform/web-core/binary/encode/encode_bg.wasm.d.ts b/packages/web-platform/web-core/binary/encode/encode_bg.wasm.d.ts index 19d5cf6c20..b6a0949cde 100644 --- a/packages/web-platform/web-core/binary/encode/encode_bg.wasm.d.ts +++ b/packages/web-platform/web-core/binary/encode/encode_bg.wasm.d.ts @@ -6,8 +6,8 @@ export const __wbg_rule_free: (a: number, b: number) => void; export const __wbg_ruleprelude_free: (a: number, b: number) => void; export const __wbg_selector_free: (a: number, b: number) => void; export const __wbg_styleinfodecoder_free: (a: number, b: number) => void; -export const decode_style_info: (a: any, b: number, c: number, d: number) => [number, number, number]; -export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number) => [number, number, number]; +export const decode_style_info: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; +export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; export const get_font_face_content: (a: any) => [number, number, number, number]; export const get_style_content: (a: any) => [number, number, number, number]; export const rawstyleinfo_append_import: (a: number, b: number, c: number) => void; diff --git a/packages/web-platform/web-core/binary/server/server.d.ts b/packages/web-platform/web-core/binary/server/server.d.ts index 146cffcb8f..14a1668d1d 100644 --- a/packages/web-platform/web-core/binary/server/server.d.ts +++ b/packages/web-platform/web-core/binary/server/server.d.ts @@ -16,7 +16,7 @@ export class MainThreadServerContext { get_parent(child_id: number): number | undefined; get_tag(element_id: number): string | undefined; insert_before(parent_id: number, child_id: number, ref_id?: number | null): void; - constructor(view_attributes: string, enable_css_selector: boolean); + constructor(view_attributes: string, enable_css_selector: boolean, transform_vw: boolean, transform_vh: boolean); push_style_sheet(resource: StyleSheetResource, entry_name?: string | null): void; remove_attribute(element_id: number, key: string): void; remove_child(parent_id: number, child_id: number): void; @@ -130,9 +130,9 @@ export class StyleSheetResource { constructor(buffer: Uint8Array, _document: any); } -export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean): Uint8Array; +export function decode_style_info(buffer: Uint8Array, entry_name: string | null | undefined, config_enable_css_selector: boolean, transform_vw: boolean, transform_vh: boolean): Uint8Array; -export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name?: string | null): Uint8Array; +export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawStyleInfo, config_enable_css_selector: boolean, entry_name: string | null | undefined, transform_vw: boolean, transform_vh: boolean): Uint8Array; export function get_font_face_content(buffer: Uint8Array): string; diff --git a/packages/web-platform/web-core/binary/server/server_bg.wasm.d.ts b/packages/web-platform/web-core/binary/server/server_bg.wasm.d.ts index e153154765..da92a2cb97 100644 --- a/packages/web-platform/web-core/binary/server/server_bg.wasm.d.ts +++ b/packages/web-platform/web-core/binary/server/server_bg.wasm.d.ts @@ -7,8 +7,8 @@ export const __wbg_rule_free: (a: number, b: number) => void; export const __wbg_ruleprelude_free: (a: number, b: number) => void; export const __wbg_selector_free: (a: number, b: number) => void; export const __wbg_stylesheetresource_free: (a: number, b: number) => void; -export const decode_style_info: (a: any, b: number, c: number, d: number) => [number, number, number]; -export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number) => [number, number, number]; +export const decode_style_info: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; +export const encode_legacy_json_generated_raw_style_info: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number]; export const get_font_face_content: (a: any) => [number, number, number, number]; export const get_style_content: (a: any) => [number, number, number, number]; export const init_server_in_shadow_css: (a: number, b: number) => void; @@ -24,7 +24,7 @@ export const mainthreadservercontext_get_page_css: (a: number) => [number, numbe export const mainthreadservercontext_get_parent: (a: number, b: number) => number; export const mainthreadservercontext_get_tag: (a: number, b: number) => [number, number]; export const mainthreadservercontext_insert_before: (a: number, b: number, c: number, d: number) => void; -export const mainthreadservercontext_new: (a: number, b: number, c: number) => number; +export const mainthreadservercontext_new: (a: number, b: number, c: number, d: number, e: number) => number; export const mainthreadservercontext_push_style_sheet: (a: number, b: number, c: number, d: number) => [number, number]; export const mainthreadservercontext_remove_attribute: (a: number, b: number, c: number, d: number) => void; export const mainthreadservercontext_remove_child: (a: number, b: number, c: number) => void; diff --git a/packages/web-platform/web-core/css/index.css b/packages/web-platform/web-core/css/index.css index 36e52192f1..b5df3b8109 100644 --- a/packages/web-platform/web-core/css/index.css +++ b/packages/web-platform/web-core/css/index.css @@ -7,6 +7,12 @@ lynx-view { contain: strict; display: none; + width: 100%; + container-name: lynx-view; + container-type: inline-size; + --rpx-unit: 1cqw; + --vw-unit: 1vw; + --vh-unit: 1vh; } lynx-view[ssr] { @@ -27,6 +33,24 @@ lynx-view[width="auto"] { lynx-view::part(page) { height: 100%; width: 100%; + --rpx-unit: inherit; + --vw-unit: inherit; + --vh-unit: inherit; +} + +@property --rpx-unit { + syntax: ""; + inherits: true; +} + +@property --vw-unit { + syntax: ""; + inherits: true; +} + +@property --vh-unit { + syntax: ""; + inherits: true; } @property --lynx-display { diff --git a/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs b/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs index ce19d5f64f..b9dbed2bb4 100644 --- a/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs +++ b/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs @@ -105,8 +105,19 @@ pub fn set_inline_styles_number_key(dom: &web_sys::HtmlElement, key: usize, valu } } #[wasm_bindgen] -pub fn set_inline_styles_in_str(dom: &web_sys::HtmlElement, styles: String) -> bool { - let transformed_style_str = transform_inline_style_string(&styles); +pub fn set_inline_styles_in_str( + dom: &web_sys::HtmlElement, + styles: String, + transform_vw: bool, + transform_vh: bool, +) -> bool { + let transformed_style_str = transform_inline_style_string( + &styles, + &crate::style_transformer::token_transformer::TransformerConfig { + transform_vw, + transform_vh, + }, + ); // we compare the transformed style string with the original one // The reason is copy utf-8 string from wasm to js is expensive if transformed_style_str == styles { @@ -117,7 +128,18 @@ pub fn set_inline_styles_in_str(dom: &web_sys::HtmlElement, styles: String) -> b } #[wasm_bindgen] -pub fn get_inline_styles_in_key_value_vec(dom: &web_sys::HtmlElement, k_v_vec: Vec) { - let transformed_style_str = transform_inline_style_key_value_vec(k_v_vec); +pub fn get_inline_styles_in_key_value_vec( + dom: &web_sys::HtmlElement, + k_v_vec: Vec, + transform_vw: bool, + transform_vh: bool, +) { + let transformed_style_str = transform_inline_style_key_value_vec( + k_v_vec, + &crate::style_transformer::token_transformer::TransformerConfig { + transform_vw, + transform_vh, + }, + ); let _ = dom.set_attribute("style", &transformed_style_str); } diff --git a/packages/web-platform/web-core/src/main_thread/server/main_thread_server_context.rs b/packages/web-platform/web-core/src/main_thread/server/main_thread_server_context.rs index b982d39b52..1ffa43088c 100644 --- a/packages/web-platform/web-core/src/main_thread/server/main_thread_server_context.rs +++ b/packages/web-platform/web-core/src/main_thread/server/main_thread_server_context.rs @@ -32,17 +32,26 @@ pub struct MainThreadServerContext { style_manager: StyleManagerServer, view_attributes: String, enable_css_selector: bool, + transform_vw: bool, + transform_vh: bool, } #[wasm_bindgen] impl MainThreadServerContext { #[wasm_bindgen(constructor)] - pub fn new(view_attributes: String, enable_css_selector: bool) -> Self { + pub fn new( + view_attributes: String, + enable_css_selector: bool, + transform_vw: bool, + transform_vh: bool, + ) -> Self { Self { elements: Vec::new(), style_manager: StyleManagerServer::new(), view_attributes, enable_css_selector, + transform_vw, + transform_vh, } } @@ -258,7 +267,13 @@ impl MainThreadServerContext { pub fn set_attribute(&mut self, element_id: usize, key: String, value: String) { if let Some(Some(element)) = self.elements.get_mut(element_id) { if key == "style" { - let transformed = transform_inline_style_string(&value); + let transformed = transform_inline_style_string( + &value, + &crate::style_transformer::token_transformer::TransformerConfig { + transform_vw: self.transform_vw, + transform_vh: self.transform_vh, + }, + ); element.set_attribute(key, transformed); } else { element.set_attribute(key, value); @@ -309,7 +324,13 @@ impl MainThreadServerContext { } pub fn set_inline_styles_in_str(&mut self, element_id: usize, styles: String) -> bool { - let transformed_style_str = transform_inline_style_string(&styles); + let transformed_style_str = transform_inline_style_string( + &styles, + &crate::style_transformer::token_transformer::TransformerConfig { + transform_vw: self.transform_vw, + transform_vh: self.transform_vh, + }, + ); if transformed_style_str == styles { return false; } @@ -320,7 +341,13 @@ impl MainThreadServerContext { } pub fn get_inline_styles_in_key_value_vec(&mut self, element_id: usize, k_v_vec: Vec) { - let transformed_style_str = transform_inline_style_key_value_vec(k_v_vec); + let transformed_style_str = transform_inline_style_key_value_vec( + k_v_vec, + &crate::style_transformer::token_transformer::TransformerConfig { + transform_vw: self.transform_vw, + transform_vh: self.transform_vh, + }, + ); if let Some(Some(element)) = self.elements.get_mut(element_id) { element.set_attribute("style".to_string(), transformed_style_str); } @@ -497,7 +524,7 @@ mod tests { #[test] fn test_html_generation() { - let mut ctx = MainThreadServerContext::new("".to_string(), true); + let mut ctx = MainThreadServerContext::new("".to_string(), true, false, false); // Create
let div_id = ctx.create_element("div".to_string(), None, None, None); @@ -528,7 +555,7 @@ mod tests { #[test] fn test_set_style_empty_value() { - let mut ctx = MainThreadServerContext::new("".to_string(), true); + let mut ctx = MainThreadServerContext::new("".to_string(), true, false, false); let div_id = ctx.create_element("div".to_string(), None, None, None); // This should not panic diff --git a/packages/web-platform/web-core/src/style_transformer/inline_style.rs b/packages/web-platform/web-core/src/style_transformer/inline_style.rs index 99cd498ad1..d88257d594 100644 --- a/packages/web-platform/web-core/src/style_transformer/inline_style.rs +++ b/packages/web-platform/web-core/src/style_transformer/inline_style.rs @@ -4,7 +4,9 @@ * LICENSE file in the root directory of this source tree. */ use super::transformer::StyleTransformer; +use crate::style_transformer::token_transformer::TransformerConfig; use crate::style_transformer::transformer::Generator; + #[cfg(any(feature = "client", feature = "server"))] use crate::utils::hyphenate_style_name::hyphenate_style_name; struct InlineStyleGenerator { @@ -18,21 +20,37 @@ impl Generator for InlineStyleGenerator { self.string_buffer.push_str(&value); } } -pub(crate) fn transform_inline_style_string(source: &str) -> String { + +pub(crate) fn transform_inline_style_string(source: &str, config: &TransformerConfig) -> String { let mut generator = InlineStyleGenerator { string_buffer: String::with_capacity(source.len() + 16), }; - let transformer = &mut StyleTransformer::new(&mut generator); + let transformer = &mut StyleTransformer::new( + &mut generator, + TransformerConfig { + transform_vw: config.transform_vw, + transform_vh: config.transform_vh, + }, + ); transformer.parse(source); generator.string_buffer } #[cfg(any(feature = "client", feature = "server"))] -pub(crate) fn transform_inline_style_key_value_vec(source: Vec) -> String { +pub(crate) fn transform_inline_style_key_value_vec( + source: Vec, + config: &TransformerConfig, +) -> String { let mut generator = InlineStyleGenerator { string_buffer: String::new(), }; - let transformer = &mut StyleTransformer::new(&mut generator); + let transformer = &mut StyleTransformer::new( + &mut generator, + TransformerConfig { + transform_vw: config.transform_vw, + transform_vh: config.transform_vh, + }, + ); // the even value of source should be processed by hyphenate_style_name // iterate 2 values at a time @@ -56,14 +74,14 @@ mod tests { #[test] fn basic_one_simple_decl() { let source = "height:1px;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "height:1px;"); } #[test] fn transform_basic() { let source = "height:1px;display:linear;flex-direction:row;width:100px;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "height:1px;--lynx-display-toggle:var(--lynx-display-linear);--lynx-display:linear;display:flex;--flex-direction:row;width:100px;" @@ -73,14 +91,14 @@ mod tests { #[test] fn transform_with_blank() { let source = "flex-direction:row;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex-direction:row;"); } #[test] fn test_replace_rule_display_linear_blank_after_colon() { let source = "display: linear;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-display-toggle:var(--lynx-display-linear);--lynx-display:linear;display:flex;" @@ -90,7 +108,7 @@ mod tests { #[test] fn test_replace_rule_linear_orientation() { let source = "linear-direction:row;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-linear-orientation:horizontal;--lynx-linear-orientation-toggle:var(--lynx-linear-orientation-horizontal);" @@ -100,7 +118,7 @@ mod tests { #[test] fn test_replace_rule_display_linear_important() { let source = "display: linear !important;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-display-toggle:var(--lynx-display-linear) !important;--lynx-display:linear !important;display:flex !important;" @@ -110,7 +128,7 @@ mod tests { #[test] fn transform_color_normal() { let source = "color:blue;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-text-bg-color:initial;-webkit-background-clip:initial;background-clip:initial;color:blue;" @@ -120,7 +138,7 @@ mod tests { #[test] fn transform_color_normal_with_blank() { let source = " color : blue ;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-text-bg-color:initial;-webkit-background-clip:initial;background-clip:initial;color:blue;" @@ -130,7 +148,7 @@ mod tests { #[test] fn transform_color_normal_important() { let source = " color : blue !important ;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-text-bg-color:initial !important;-webkit-background-clip:initial !important;background-clip:initial !important;color:blue !important;" @@ -140,7 +158,7 @@ mod tests { #[test] fn transform_color_linear_gradient() { let source = " color : linear-gradient(pink, blue) ;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "color:transparent;-webkit-background-clip:text;background-clip:text;--lynx-text-bg-color:linear-gradient(pink, blue);" @@ -150,7 +168,7 @@ mod tests { #[test] fn transform_color_linear_gradient_important() { let source = " color : linear-gradient(pink, blue) !important ;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "color:transparent !important;-webkit-background-clip:text !important;background-clip:text !important;--lynx-text-bg-color:linear-gradient(pink, blue) !important;" @@ -160,7 +178,7 @@ mod tests { #[test] fn transform_color_with_font_size() { let source = "font-size: 24px; color: blue"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "font-size:24px;--lynx-text-bg-color:initial;-webkit-background-clip:initial;background-clip:initial;color:blue;" @@ -170,55 +188,55 @@ mod tests { #[test] fn flex_1() { let source = "flex:1;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex:1;"); } #[test] fn flex_1_percent() { let source = "flex:1%;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex:1%;"); } #[test] fn flex_2_3() { let source = "flex:2 3;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex:2 3;"); } #[test] fn flex_2_3_percentage() { let source = "flex:2 3%;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex:2 3%;"); } #[test] fn flex_2_3_px() { let source = "flex:2 3px;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex:2 3px;"); } #[test] fn flex_3_4_5_percentage() { let source = "flex:3 4 5%;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--flex:3 4 5%;"); } #[test] fn flex_1_extra() { let source = "width:100px; flex:none; width:100px;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "width:100px;--flex:none;width:100px;"); } #[test] fn complex_1() { let source = "linear-direction:row;linear-weight: 0;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-linear-orientation:horizontal;--lynx-linear-orientation-toggle:var(--lynx-linear-orientation-horizontal);--lynx-linear-weight:0;" @@ -228,14 +246,14 @@ mod tests { #[test] fn linear_weight_0() { let source = "linear-weight: 0;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--lynx-linear-weight:0;"); } #[test] fn linear_weight_1() { let source = "linear-weight: 1;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!( result, "--lynx-linear-weight:1;--lynx-linear-weight-basis:0;" @@ -245,14 +263,14 @@ mod tests { #[test] fn linear_layout_gravity() { let source = "linear-layout-gravity: right;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--align-self-row:auto;--align-self-column:end;"); } #[test] fn linear_layout_gravity_start() { let source = "linear-layout-gravity: start;"; - let result = transform_inline_style_string(source); + let result = transform_inline_style_string(source, &TransformerConfig::default()); assert_eq!(result, "--align-self-row:start;--align-self-column:start;"); } } diff --git a/packages/web-platform/web-core/src/style_transformer/mod.rs b/packages/web-platform/web-core/src/style_transformer/mod.rs index 33ae907add..5ea82f942d 100644 --- a/packages/web-platform/web-core/src/style_transformer/mod.rs +++ b/packages/web-platform/web-core/src/style_transformer/mod.rs @@ -15,7 +15,7 @@ #[cfg(any(feature = "client", feature = "server"))] mod inline_style; mod rules; -mod token_transformer; +pub mod token_transformer; mod transformer; #[cfg(any(feature = "client", feature = "server"))] pub(crate) use inline_style::transform_inline_style_key_value_vec; diff --git a/packages/web-platform/web-core/src/style_transformer/token_transformer.rs b/packages/web-platform/web-core/src/style_transformer/token_transformer.rs index 973714a33e..9d77743cb8 100644 --- a/packages/web-platform/web-core/src/style_transformer/token_transformer.rs +++ b/packages/web-platform/web-core/src/style_transformer/token_transformer.rs @@ -7,12 +7,22 @@ use crate::css_tokenizer::token_types::*; use std::borrow::Cow; +#[derive(Default)] +pub struct TransformerConfig { + pub transform_vw: bool, + pub transform_vh: bool, +} + /** * Transform one token according to specific rules. * Rule list: * 1. If the token is a DIMENSION_TOKEN with "rpx" unit, convert it to a calc(value * var(--rpx-unit)); */ -pub(crate) fn transform_one_token<'a>(token_type: u8, token_value: &'a str) -> (u8, Cow<'a, str>) { +pub(crate) fn transform_one_token<'a>( + token_type: u8, + token_value: &'a str, + config: &TransformerConfig, +) -> (u8, Cow<'a, str>) { match token_type { DIMENSION_TOKEN => { if token_value.len() > 3 && token_value.to_ascii_lowercase().ends_with("rpx") { @@ -22,6 +32,26 @@ pub(crate) fn transform_one_token<'a>(token_type: u8, token_value: &'a str) -> ( Cow::Owned(format!("calc({value} * var(--rpx-unit))")), ); } + if config.transform_vw + && token_value.len() > 2 + && token_value.to_ascii_lowercase().ends_with("vw") + { + let value = &token_value[..token_value.len() - 2]; + return ( + token_type, + Cow::Owned(format!("calc({value} * var(--vw-unit))")), + ); + } + if config.transform_vh + && token_value.len() > 2 + && token_value.to_ascii_lowercase().ends_with("vh") + { + let value = &token_value[..token_value.len() - 2]; + return ( + token_type, + Cow::Owned(format!("calc({value} * var(--vh-unit))")), + ); + } (token_type, Cow::Borrowed(token_value)) } _ => (token_type, Cow::Borrowed(token_value)), @@ -34,31 +64,82 @@ mod tests { #[test] fn test_transform_rpx() { - let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100rpx"); + let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100rpx", &TransformerConfig::default()); assert_eq!(tv, "calc(100 * var(--rpx-unit))"); } #[test] fn test_transform_rpx_float() { - let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100.5rpx"); + let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100.5rpx", &TransformerConfig::default()); assert_eq!(tv, "calc(100.5 * var(--rpx-unit))"); } #[test] fn test_transform_px() { - let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100px"); + let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100px", &TransformerConfig::default()); assert_eq!(tv, "100px"); } #[test] fn test_transform_rpx_case_insensitive() { - let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100RPX"); + let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100RPX", &TransformerConfig::default()); assert_eq!(tv, "calc(100 * var(--rpx-unit))"); } + #[test] + fn test_transform_vw() { + let (_, tv) = transform_one_token( + DIMENSION_TOKEN, + "100.5vw", + &TransformerConfig { + transform_vw: true, + ..Default::default() + }, + ); + assert_eq!(tv, "calc(100.5 * var(--vw-unit))"); + } + + #[test] + fn test_transform_vw_disabled() { + let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100.5vw", &TransformerConfig::default()); + assert_eq!(tv, "100.5vw"); + } + + #[test] + fn test_transform_vh() { + let (_, tv) = transform_one_token( + DIMENSION_TOKEN, + "100vh", + &TransformerConfig { + transform_vh: true, + ..Default::default() + }, + ); + assert_eq!(tv, "calc(100 * var(--vh-unit))"); + } + + #[test] + fn test_transform_vh_disabled() { + let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100vh", &TransformerConfig::default()); + assert_eq!(tv, "100vh"); + } + + #[test] + fn test_transform_vw_case_insensitive() { + let (_, tv) = transform_one_token( + DIMENSION_TOKEN, + "50VW", + &TransformerConfig { + transform_vw: true, + ..Default::default() + }, + ); + assert_eq!(tv, "calc(50 * var(--vw-unit))"); + } + #[test] fn test_transform_other_token() { - let (_, tv) = transform_one_token(IDENT_TOKEN, "red"); + let (_, tv) = transform_one_token(IDENT_TOKEN, "red", &TransformerConfig::default()); assert_eq!(tv, "red"); } } diff --git a/packages/web-platform/web-core/src/style_transformer/transformer.rs b/packages/web-platform/web-core/src/style_transformer/transformer.rs index 71198461a6..4bee679c0d 100644 --- a/packages/web-platform/web-core/src/style_transformer/transformer.rs +++ b/packages/web-platform/web-core/src/style_transformer/transformer.rs @@ -3,7 +3,7 @@ * Licensed under the Apache License Version 2.0 that can be found in the * LICENSE file in the root directory of this source tree. */ -use super::token_transformer::transform_one_token; +use super::token_transformer::{transform_one_token, TransformerConfig}; #[cfg(any(feature = "client", feature = "server", test))] use crate::css_tokenizer::tokenize; use crate::css_tokenizer::{ @@ -17,6 +17,7 @@ use super::rules::query_transform_rules; pub struct StyleTransformer<'a, T: Generator> { generator: &'a mut T, + config: TransformerConfig, status: usize, current_property_id: Option, @@ -32,7 +33,7 @@ pub trait Generator { impl<'a, T: Generator> Parser for StyleTransformer<'a, T> { fn on_token(&mut self, token_type: u8, token_value: &str) { - let (token_type, token_value) = transform_one_token(token_type, token_value); + let (token_type, token_value) = transform_one_token(token_type, token_value, &self.config); //https://drafts.csswg.org/css-syntax-3/#consume-declaration // on_token(type, start, offset); /* @@ -127,9 +128,10 @@ impl<'a, T: Generator> Parser for StyleTransformer<'a, T> { } } impl<'a, T: Generator> StyleTransformer<'a, T> { - pub fn new(generator: &'a mut T) -> Self { + pub fn new(generator: &'a mut T, config: TransformerConfig) -> Self { StyleTransformer { generator, + config, status: 0, current_property_id: None, current_value: String::with_capacity(8), @@ -197,7 +199,7 @@ impl<'a, T: Generator> StyleTransformer<'a, T> { .value_token_list .iter() .map(|t| { - let (_, token_value) = transform_one_token(t.token_type, &t.value); + let (_, token_value) = transform_one_token(t.token_type, &t.value, &self.config); token_value }) .collect(), @@ -220,6 +222,8 @@ fn generate_one_declaration( #[cfg(test)] mod tests { + use crate::style_transformer::token_transformer::TransformerConfig; + use super::Generator; struct TestTransformer { @@ -237,10 +241,14 @@ mod tests { } fn parse_css(css: &str) -> (TestTransformer, &str) { + parse_css_with_config(css, Default::default()) + } + + fn parse_css_with_config(css: &str, config: TransformerConfig) -> (TestTransformer, &str) { let mut test_transformer = TestTransformer { declarations: Vec::new(), }; - let mut style_transformer = super::StyleTransformer::new(&mut test_transformer); + let mut style_transformer = super::StyleTransformer::new(&mut test_transformer, config); style_transformer.parse(css); (test_transformer, css) } @@ -307,6 +315,52 @@ mod tests { assert_eq!(transformer.declarations.len(), 0); } + #[test] + fn test_vw_transformation() { + let (transformer, _) = parse_css_with_config( + "width: 100vw;", + TransformerConfig { + transform_vw: true, + ..Default::default() + }, + ); + assert_eq!(transformer.declarations.len(), 1); + assert_eq!( + transformer.declarations[0], + "width:calc(100 * var(--vw-unit));" + ); + } + + #[test] + fn test_vw_transformation_disabled() { + let (transformer, _) = parse_css("width: 100vw;"); + assert_eq!(transformer.declarations.len(), 1); + assert_eq!(transformer.declarations[0], "width:100vw;"); + } + + #[test] + fn test_vh_transformation() { + let (transformer, _) = parse_css_with_config( + "height: 100vh;", + TransformerConfig { + transform_vh: true, + ..Default::default() + }, + ); + assert_eq!(transformer.declarations.len(), 1); + assert_eq!( + transformer.declarations[0], + "height:calc(100 * var(--vh-unit));" + ); + } + + #[test] + fn test_vh_transformation_disabled() { + let (transformer, _) = parse_css("height: 100vh;"); + assert_eq!(transformer.declarations.len(), 1); + assert_eq!(transformer.declarations[0], "height:100vh;"); + } + #[test] fn test_complex_values() { let (transformer, _) = parse_css("background: url(image.png) no-repeat center;"); diff --git a/packages/web-platform/web-core/src/template/template_sections/style_info/decoded_style_data.rs b/packages/web-platform/web-core/src/template/template_sections/style_info/decoded_style_data.rs index 435393586d..cbaa320d70 100644 --- a/packages/web-platform/web-core/src/template/template_sections/style_info/decoded_style_data.rs +++ b/packages/web-platform/web-core/src/template/template_sections/style_info/decoded_style_data.rs @@ -46,13 +46,21 @@ pub fn decode_style_info( buffer: js_sys::Uint8Array, entry_name: Option, config_enable_css_selector: bool, + transform_vw: bool, + transform_vh: bool, ) -> Result { let buf = buffer.to_vec(); let data = unsafe { rkyv::from_bytes_unchecked::(&buf) } .map_err(|e| wasm_bindgen::JsError::new(&format!("Failed to decode RawStyleInfo: {e:?}")))?; - let decode_data: DecodedStyleData = - StyleInfoDecoder::new(data, entry_name, config_enable_css_selector)?.into(); + let decode_data: DecodedStyleData = StyleInfoDecoder::new( + data, + entry_name, + config_enable_css_selector, + transform_vw, + transform_vh, + )? + .into(); let serialized = rkyv::to_bytes::<_, 1024>(&decode_data).map_err(|e| { wasm_bindgen::JsError::new(&format!("Failed to encode DecodedStyleData: {e:?}")) @@ -66,9 +74,17 @@ pub fn encode_legacy_json_generated_raw_style_info( raw_style_info: RawStyleInfo, config_enable_css_selector: bool, entry_name: Option, + transform_vw: bool, + transform_vh: bool, ) -> Result { - let decode_data: DecodedStyleData = - StyleInfoDecoder::new(raw_style_info, entry_name, config_enable_css_selector)?.into(); + let decode_data: DecodedStyleData = StyleInfoDecoder::new( + raw_style_info, + entry_name, + config_enable_css_selector, + transform_vw, + transform_vh, + )? + .into(); let serialized = rkyv::to_bytes::<_, 1024>(&decode_data).map_err(|e| { wasm_bindgen::JsError::new(&format!("Failed to encode DecodedStyleData: {e:?}")) })?; diff --git a/packages/web-platform/web-core/src/template/template_sections/style_info/raw_style_info.rs b/packages/web-platform/web-core/src/template/template_sections/style_info/raw_style_info.rs index 22677972ce..4dc4d92c95 100644 --- a/packages/web-platform/web-core/src/template/template_sections/style_info/raw_style_info.rs +++ b/packages/web-platform/web-core/src/template/template_sections/style_info/raw_style_info.rs @@ -141,7 +141,7 @@ impl RawStyleInfo { */ #[cfg(feature = "encode")] pub fn encode(&mut self) -> Result { - let decoded_style_info = StyleInfoDecoder::new(self.clone(), None, true)?; + let decoded_style_info = StyleInfoDecoder::new(self.clone(), None, true, false, false)?; self.style_content_str_size_hint = decoded_style_info.style_content.len(); let serialized = rkyv::to_bytes::<_, 1024>(self) .map_err(|e| JsError::new(&format!("Failed to encode RawStyleInfo: {e:?}")))?; diff --git a/packages/web-platform/web-core/src/template/template_sections/style_info/style_info_decoder.rs b/packages/web-platform/web-core/src/template/template_sections/style_info/style_info_decoder.rs index c1d0fe452c..eceeee5e42 100644 --- a/packages/web-platform/web-core/src/template/template_sections/style_info/style_info_decoder.rs +++ b/packages/web-platform/web-core/src/template/template_sections/style_info/style_info_decoder.rs @@ -26,6 +26,8 @@ pub struct StyleInfoDecoder { is_processing_font_face: bool, temp_child_rules_buffer: String, config_enable_css_selector: bool, + transform_vw: bool, + transform_vh: bool, entry_name: Option, css_og_current_processing_css_ids: Option>, css_og_current_processing_class_selector_names: Option>, @@ -36,6 +38,8 @@ impl StyleInfoDecoder { raw_style_info: RawStyleInfo, entry_name: Option, config_enable_css_selector: bool, + transform_vw: bool, + transform_vh: bool, ) -> Result { let flattened_style_info: FlattenedStyleInfo = raw_style_info.into(); let mut decoded_style_info = StyleInfoDecoder { @@ -49,6 +53,8 @@ impl StyleInfoDecoder { }, entry_name, config_enable_css_selector, + transform_vw, + transform_vh, is_processing_font_face: false, css_og_current_processing_css_ids: None, css_og_current_processing_class_selector_names: None, @@ -277,7 +283,13 @@ impl StyleInfoDecoder { &mut self.style_content }) .push('{'); - let mut transformer = StyleTransformer::new(self); + let mut transformer = StyleTransformer::new( + self, + crate::style_transformer::token_transformer::TransformerConfig { + transform_vw: self.transform_vw, + transform_vh: self.transform_vh, + }, + ); for decl in declaration_block.declarations.into_iter() { transformer.on_half_parsed_declaration(decl); @@ -365,7 +377,14 @@ mod test { config_enable_css_selector: bool, entry_name: Option, ) -> StyleInfoDecoder { - StyleInfoDecoder::new(raw_style_info, entry_name, config_enable_css_selector).unwrap() + StyleInfoDecoder::new( + raw_style_info, + entry_name, + config_enable_css_selector, + false, + false, + ) + .unwrap() } #[test] @@ -892,8 +911,8 @@ mod tests_roundtrip { let decoded_raw = unsafe { rkyv::from_bytes_unchecked::(&buf) } .expect("RawStyleInfo decode should succeed"); - let decoder = - StyleInfoDecoder::new(decoded_raw, None, true).expect("StyleInfoDecoder should succeed"); + let decoder = StyleInfoDecoder::new(decoded_raw, None, true, false, false) + .expect("StyleInfoDecoder should succeed"); let decoded_string = decoder.style_content; assert!(decoded_string.contains(".card > x-view:where([l-css-id=\"1\"]):not([l-e-name])")); @@ -943,8 +962,8 @@ mod tests_roundtrip { let decoded_raw = unsafe { rkyv::from_bytes_unchecked::(&buf) } .expect("RawStyleInfo decode should succeed"); - let decoder = - StyleInfoDecoder::new(decoded_raw, None, true).expect("StyleInfoDecoder should succeed"); + let decoder = StyleInfoDecoder::new(decoded_raw, None, true, false, false) + .expect("StyleInfoDecoder should succeed"); let decoded_string = decoder.style_content; // Note: Custom properties (unknown properties) lose their name in the new optimizations. diff --git a/packages/web-platform/web-core/tests/element-apis.spec.ts b/packages/web-platform/web-core/tests/element-apis.spec.ts index 143b6fc166..0b68cecbfd 100644 --- a/packages/web-platform/web-core/tests/element-apis.spec.ts +++ b/packages/web-platform/web-core/tests/element-apis.spec.ts @@ -401,6 +401,89 @@ describe('Element APIs', () => { expect(targetStyle).toContain('30px'); expect(targetStyle).toContain('10px'); }); + test('__SetInlineStyles with rpx', () => { + const root = mtsGlobalThis.__CreatePage('page', 0); + let target = mtsGlobalThis.__CreateView(0); + mtsGlobalThis.__SetID(target, 'target'); + mtsGlobalThis.__SetInlineStyles(target, 'margin: 10rpx; width: 50.5rpx;'); + mtsGlobalThis.__AppendElement(root, target); + mtsGlobalThis.__FlushElementTree(); + const targetDom = rootDom.querySelector('#target') as HTMLElement; + const targetStyle = targetDom.getAttribute('style'); + expect(targetStyle).toContain('calc(10 * var(--rpx-unit))'); + expect(targetStyle).toContain('calc(50.5 * var(--rpx-unit))'); + }); + + test('__SetInlineStyles with vw and vh when enabled', () => { + const mtsGlobalThisUnits = createElementAPI( + rootDom, + mtsBinding, + true, + true, + true, + true, // transformVW + true, // transformVH + ); + const root = mtsGlobalThisUnits.__CreatePage('page', 0); + let target = mtsGlobalThisUnits.__CreateView(0); + mtsGlobalThisUnits.__SetID(target, 'target'); + mtsGlobalThisUnits.__SetInlineStyles(target, 'width: 50vw; height: 100vh;'); + mtsGlobalThisUnits.__AppendElement(root, target); + mtsGlobalThisUnits.__FlushElementTree(); + const targetDom = rootDom.querySelector('#target') as HTMLElement; + const targetStyle = targetDom.getAttribute('style'); + expect(targetStyle).toContain('calc(50 * var(--vw-unit))'); + expect(targetStyle).toContain('calc(100 * var(--vh-unit))'); + }); + + test('__SetInlineStyles with object and vw/vh when enabled', () => { + const mtsGlobalThisUnits = createElementAPI( + rootDom, + mtsBinding, + true, + true, + true, + true, // transformVW + true, // transformVH + ); + const root = mtsGlobalThisUnits.__CreatePage('page', 0); + let target = mtsGlobalThisUnits.__CreateView(0); + mtsGlobalThisUnits.__SetID(target, 'target'); + mtsGlobalThisUnits.__SetInlineStyles(target, { + width: '50vw', + height: '100vh', + }); + mtsGlobalThisUnits.__AppendElement(root, target); + mtsGlobalThisUnits.__FlushElementTree(); + const targetDom = rootDom.querySelector('#target') as HTMLElement; + const targetStyle = targetDom.getAttribute('style'); + expect(targetStyle).toBe('width:50vw;height:100vh;'); + }); + + test('__SetAttribute style with rpx, vw, vh', () => { + const mtsGlobalThisUnits = createElementAPI( + rootDom, + mtsBinding, + true, + true, + true, + true, // transformVW + true, // transformVH + ); + const root = mtsGlobalThisUnits.__CreatePage('page', 0); + let target = mtsGlobalThisUnits.__CreateView(0); + mtsGlobalThisUnits.__SetID(target, 'target'); + mtsGlobalThisUnits.__SetAttribute( + target, + 'style', + 'width: 50vw; height: 100vh; margin: 10rpx;', + ); + mtsGlobalThisUnits.__AppendElement(root, target); + mtsGlobalThisUnits.__FlushElementTree(); + const targetDom = rootDom.querySelector('#target') as HTMLElement; + const targetStyle = targetDom.getAttribute('style'); + expect(targetStyle).toBe('width: 50vw; height: 100vh; margin: 10rpx;'); + }); test('__GetConfig__AddConfig', () => { let root = mtsGlobalThis.__CreatePage('page', 0); @@ -1339,6 +1422,73 @@ describe('Element APIs', () => { }); describe('Server Element APIs SSR Propagation', () => { + test('ssr __SetInlineStyles and __SetAttribute style transformations', () => { + const binding: SSRBinding = { ssrResult: '' }; + const config = { + enableCSSSelector: true, + defaultOverflowVisible: false, + defaultDisplayLinear: true, + transformVW: true, + transformVH: true, + }; + const { globalThisAPIs: api, wasmContext: wasmCtx } = + createServerElementAPI(binding, undefined, '', config); + + const root = api.__CreatePage('page', 0); + + const view1 = api.__CreateElement('view', api.__GetElementUniqueID(root)); + api.__SetAttribute( + view1, + 'style', + 'width: 50vw; height: 100vh; margin: 10rpx;', + ); + api.__AppendElement(root, view1); + + const view2 = api.__CreateElement('view', api.__GetElementUniqueID(root)); + api.__SetInlineStyles( + view2, + 'width: 50vw; height: 100vh; margin: 10rpx;', + ); + api.__AppendElement(root, view2); + + const view3 = api.__CreateElement('view', api.__GetElementUniqueID(root)); + api.__SetInlineStyles(view3, { + width: '50vw', + height: '100vh', + margin: '10rpx', + }); + api.__AppendElement(root, view3); + + api.__FlushElementTree(); + + const html1 = wasmCtx.generate_html(api.__GetElementUniqueID(view1)); + expect(html1).toContain('calc(50 * var(--vw-unit))'); + expect(html1).toContain('calc(100 * var(--vh-unit))'); + expect(html1).toContain('calc(10 * var(--rpx-unit))'); + + const html2 = wasmCtx.generate_html(api.__GetElementUniqueID(view2)); + expect(html2).toContain('calc(50 * var(--vw-unit))'); + expect(html2).toContain('calc(100 * var(--vh-unit))'); + expect(html2).toContain('calc(10 * var(--rpx-unit))'); + + const html3 = wasmCtx.generate_html(api.__GetElementUniqueID(view3)); + expect(html3).toContain('style="width:50vw;height:100vh;margin:10rpx;"'); + + const view4 = api.__CreateElement('view', api.__GetElementUniqueID(root)); + api.__SetAttribute( + view4, + 'style', + 'width: 50vw; height: 100vh; margin: 10rpx;', + ); + api.__AppendElement(root, view4); + api.__FlushElementTree(); + + const html4 = wasmCtx.generate_html(api.__GetElementUniqueID(view4)); + expect(html4).toContain('calc(50 * var(--vw-unit))'); + expect(html4).toContain('calc(100 * var(--vh-unit))'); + expect(html4).toContain('calc(10 * var(--rpx-unit))'); + }); + test('create element infer css id from parent component in SSR', () => { const binding: SSRBinding = { ssrResult: '', diff --git a/packages/web-platform/web-core/tests/template-manager.spec.ts b/packages/web-platform/web-core/tests/template-manager.spec.ts index 6bf10be98e..8da1ff4ce6 100644 --- a/packages/web-platform/web-core/tests/template-manager.spec.ts +++ b/packages/web-platform/web-core/tests/template-manager.spec.ts @@ -85,6 +85,8 @@ describe('Template Manager', () => { await templateManager.fetchBundle( templateUrl, Promise.resolve(mockLynxViewInstance), + false, + false, ); // Verify data using getCustomSection @@ -121,6 +123,8 @@ describe('Template Manager', () => { templateManager.fetchBundle( templateUrl, Promise.resolve(mockLynxViewInstance), + false, + false, ), ) .rejects.toThrow('Unsupported version: 2'); @@ -163,6 +167,8 @@ describe('Template Manager', () => { await templateManager.fetchBundle( 'http://example.com/template', Promise.resolve(mockLynxViewInstance), + false, + false, ); // Verify data using getCustomSection @@ -217,6 +223,8 @@ describe('Template Manager', () => { templateManager.fetchBundle( templateUrl, Promise.resolve(mockLynxViewInstance), + false, + false, ), ).rejects.toThrow('Stream failed'); @@ -248,6 +256,8 @@ describe('Template Manager', () => { await templateManager.fetchBundle( templateUrl, Promise.resolve(mockLynxViewInstance), + false, + false, overrideConfig as any, ); @@ -321,6 +331,8 @@ describe('Template Manager', () => { await templateManager.fetchBundle( templateUrl, Promise.resolve(mockLynxViewInstance), + false, + false, ); // Verify config @@ -370,6 +382,8 @@ describe('Template Manager', () => { await templateManager.fetchBundle( templateUrl, Promise.resolve(mockLynxViewInstance), + false, + false, ); // Verify config has appType = lazy and isLazy = true diff --git a/packages/web-platform/web-core/ts/client/decodeWorker/cssLoader.ts b/packages/web-platform/web-core/ts/client/decodeWorker/cssLoader.ts index 747a98f2e5..a88dafe470 100644 --- a/packages/web-platform/web-core/ts/client/decodeWorker/cssLoader.ts +++ b/packages/web-platform/web-core/ts/client/decodeWorker/cssLoader.ts @@ -18,6 +18,8 @@ type StyleInfo = Record; export function loadStyleFromJSON( styleInfo: StyleInfo, configEnableCSSSelector: boolean, + transformVW: boolean, + transformVH: boolean, entryName?: string, ): Uint8Array { const rawStyleInfo = new wasmInstance.RawStyleInfo(); @@ -101,6 +103,8 @@ export function loadStyleFromJSON( rawStyleInfo, configEnableCSSSelector, entryName, + transformVW, + transformVH, ); } diff --git a/packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts b/packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts index 34bc814bc4..7fc4914cab 100644 --- a/packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts +++ b/packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts @@ -106,7 +106,7 @@ self.onmessage = async ( wasmInstance.initSync({ module: wasmModule }); wasmModuleLoadedResolve(); } else if (data.type === 'load') { - const { url, fetchUrl, overrideConfig } = data; + const { url, fetchUrl, overrideConfig, transformVW, transformVH } = data; try { const response = await fetch(fetchUrl, { headers: { @@ -117,7 +117,7 @@ self.onmessage = async ( throw new Error(`Failed to fetch template: ${response.statusText}`); } const reader = response.body.getReader(); - await handleStream(url, reader, overrideConfig); + await handleStream(url, reader, transformVW, transformVH, overrideConfig); postMessage({ type: 'done', url } as MainMessage); } catch (error) { postMessage( @@ -129,6 +129,8 @@ self.onmessage = async ( async function handleStream( url: string, reader: ReadableStreamDefaultReader, + transformVW: boolean, + transformVH: boolean, overrideConfig?: Partial, ) { const streamReader = new StreamReader(reader); @@ -146,7 +148,7 @@ async function handleStream( const decoder = new TextDecoder(); const jsonStr = decoder.decode(headerBytes) + decoder.decode(rest); const json = JSON.parse(jsonStr); - await handleJSON(json, url, overrideConfig); + await handleJSON(json, url, transformVW, transformVH, overrideConfig); return; } @@ -223,6 +225,8 @@ async function handleStream( content, config['isLazy'] === 'true' ? url : undefined, config['enableCSSSelector'] === 'true', + transformVW, + transformVH, ); postMessage( { @@ -307,6 +311,8 @@ async function handleStream( async function handleJSON( json: any, url: string, + transformVW: boolean, + transformVH: boolean, overrideConfig?: Partial, ) { // Configurations @@ -342,6 +348,8 @@ async function handleJSON( const buffer = loadStyleFromJSON( json.styleInfo, config['enableCSSSelector'] === 'true', + transformVW, + transformVH, config['isLazy'] === 'true' ? url : undefined, ); postMessage( diff --git a/packages/web-platform/web-core/ts/client/decodeWorker/types.ts b/packages/web-platform/web-core/ts/client/decodeWorker/types.ts index 89fc957d21..a442481d99 100644 --- a/packages/web-platform/web-core/ts/client/decodeWorker/types.ts +++ b/packages/web-platform/web-core/ts/client/decodeWorker/types.ts @@ -13,6 +13,8 @@ export interface InitMessage extends DecodeWorkerMessage { export interface LoadTemplateMessage extends DecodeWorkerMessage { type: 'load'; fetchUrl: string; + transformVW: boolean; + transformVH: boolean; overrideConfig?: Record; } diff --git a/packages/web-platform/web-core/ts/client/mainthread/LynxView.ts b/packages/web-platform/web-core/ts/client/mainthread/LynxView.ts index 74660c5528..9a97d16e2b 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/LynxView.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/LynxView.ts @@ -87,6 +87,8 @@ export class LynxViewElement extends HTMLElement { 'global-props', 'init-data', 'browser-config', + 'transform-vw', + 'transform-vh', ]; /** * @private @@ -139,6 +141,42 @@ export class LynxViewElement extends HTMLElement { } } + #transformVW: boolean = false; + /** + * @public + * @property transformVW + * Enable evaluating vw subset to the current LynxView container width + */ + get transformVW(): boolean { + return this.#transformVW; + } + set transformVW(val: boolean) { + this.#transformVW = val; + if (val) { + this.setAttribute('transform-vw', ''); + } else { + this.removeAttribute('transform-vw'); + } + } + + #transformVH: boolean = false; + /** + * @public + * @property transformVH + * Enable evaluating vh subset to the current LynxView container height + */ + get transformVH(): boolean { + return this.#transformVH; + } + set transformVH(val: boolean) { + this.#transformVH = val; + if (val) { + this.setAttribute('transform-vh', ''); + } else { + this.removeAttribute('transform-vh'); + } + } + constructor() { super(); if (!this.onNativeModulesCall) { @@ -343,6 +381,12 @@ export class LynxViewElement extends HTMLElement { case 'init-data': this.#initData = JSON.parse(newValue); break; + case 'transform-vw': + this.transformVW = newValue !== 'false' && newValue !== null; + break; + case 'transform-vh': + this.transformVH = newValue !== 'false' && newValue !== null; + break; } } } @@ -427,10 +471,18 @@ export class LynxViewElement extends HTMLElement { this.nativeModulesMap, this.napiModulesMap, this.#initI18nResources, + this.transformVW, + this.transformVH, this.browserConfig, ); }); - templateManager.fetchBundle(this.#url, lynxViewInstance); + templateManager.fetchBundle( + this.#url, + lynxViewInstance, + this.transformVW, + this.transformVH, + undefined, // overrideConfig + ); const lynxGroupId = this.lynxGroupId; this.#instance = await lynxViewInstance; @@ -453,6 +505,8 @@ export class LynxViewElement extends HTMLElement { */ connectedCallback() { this.#upgradeProperty('browserConfig'); + this.#upgradeProperty('transformVW'); + this.#upgradeProperty('transformVH'); if (this.url) { this.#url = this.url; } diff --git a/packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts b/packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts index 2d403de9e5..d93b8c51d6 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts @@ -84,6 +84,8 @@ export class LynxViewInstance implements AsyncDisposable { nativeModulesMap: NativeModulesMap = {}, napiModulesMap: NapiModulesMap = {}, initI18nResources?: InitI18nResources, + private readonly transformVW: boolean = false, + private readonly transformVH: boolean = false, browserConfig?: Record, ) { this.systemInfo = createSystemInfo(browserConfig); @@ -128,6 +130,8 @@ export class LynxViewInstance implements AsyncDisposable { enableCSSSelector, defaultDisplayLinear, defaultOverflowVisible, + this.transformVW, + this.transformVH, ), createMainThreadGlobalAPIs( this, @@ -224,9 +228,15 @@ export class LynxViewInstance implements AsyncDisposable { if (this.#queryComponentCache.has(url)) { return this.#queryComponentCache.get(url)!; } - const promise = templateManager.fetchBundle(url, Promise.resolve(this), { - enableCSSSelector: this.#pageConfig!['enableCSSSelector'], - }) + const promise = templateManager.fetchBundle( + url, + Promise.resolve(this), + this.transformVW, + this.transformVH, + { + enableCSSSelector: this.#pageConfig!['enableCSSSelector'], + }, + ) .then(async () => { const urlMap = this.lepusCodeUrls.get(url); const rootUrl = urlMap?.['root']; diff --git a/packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts b/packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts index 03ceb139d1..13ca29afbf 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts @@ -45,6 +45,8 @@ export class TemplateManager { public fetchBundle( url: string, lynxViewInstancePromise: Promise, + transformVW: boolean, + transformVH: boolean, overrideConfig?: Record, ): Promise { if (this.#templates.has(url) && !overrideConfig) { @@ -60,13 +62,21 @@ export class TemplateManager { })(); } else { this.createTemplate(url); - return this.#load(url, lynxViewInstancePromise, overrideConfig); + return this.#load( + url, + lynxViewInstancePromise, + transformVW, + transformVH, + overrideConfig, + ); } } async #load( url: string, lynxViewInstancePromise: Promise, + transformVW: boolean, + transformVH: boolean, overrideConfig?: Partial, ): Promise { const currentTime = performance.now() + performance.timeOrigin; @@ -85,6 +95,8 @@ export class TemplateManager { type: 'load', url, fetchUrl: (new URL(url, location.href)).toString(), + transformVW, + transformVH, overrideConfig, }; this.#worker!.postMessage(msg); diff --git a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts index 271be8d8c2..f1190e9130 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts @@ -63,6 +63,8 @@ export function createElementAPI( config_enable_css_selector: boolean, config_default_display_linear: boolean, config_default_overflow_visible: boolean, + transform_vw: boolean, + transform_vh: boolean, ): ElementPAPIs { const wasmContext = new MainThreadWasmContext( rootDom, @@ -289,6 +291,8 @@ export function createElementAPI( !set_inline_styles_in_str( element, value, + transform_vw, + transform_vh, ) ) { element.setAttribute('style', value); @@ -305,6 +309,8 @@ export function createElementAPI( get_inline_styles_in_key_value_vec( element, vec, + transform_vw, + transform_vh, ); } } diff --git a/packages/web-platform/web-core/ts/server/decode.ts b/packages/web-platform/web-core/ts/server/decode.ts index c2bece55a2..f929b72cc9 100644 --- a/packages/web-platform/web-core/ts/server/decode.ts +++ b/packages/web-platform/web-core/ts/server/decode.ts @@ -14,7 +14,11 @@ export interface DecodedTemplate { customSections?: Record; } -export function decodeTemplate(buffer: Uint8Array): DecodedTemplate { +export function decodeTemplate( + buffer: Uint8Array, + transformVW: boolean, + transformVH: boolean, +): DecodedTemplate { if (buffer.length < 8) { throw new Error('Buffer too short for Magic Header'); } @@ -83,6 +87,8 @@ export function decodeTemplate(buffer: Uint8Array): DecodedTemplate { content, config['isLazy'] === 'true' ? '' : undefined, // URL is not available in synchronous decode usually, or passed as arg? The user req says "uint8array as params decode directly". Assuming URL is empty or unneeded for sync server decode unless specified. config['enableCSSSelector'] === 'true', + transformVW, + transformVH, ); styleInfo = buffer; break; diff --git a/packages/web-platform/web-core/ts/server/deploy.ts b/packages/web-platform/web-core/ts/server/deploy.ts index 9aa67469ef..9c5e28bf78 100644 --- a/packages/web-platform/web-core/ts/server/deploy.ts +++ b/packages/web-platform/web-core/ts/server/deploy.ts @@ -12,9 +12,11 @@ export function executeTemplate( initData: Cloneable, globalProps: Cloneable, _initI18nResources: InitI18nResources, + transformVW: boolean, + transformVH: boolean, viewAttributes?: string, ): string | undefined { - const result = decodeTemplate(templateBuffer); + const result = decodeTemplate(templateBuffer, transformVW, transformVH); const config = result.config; const binding: SSRBinding = { ssrResult: '' }; @@ -26,6 +28,8 @@ export function executeTemplate( enableCSSSelector: config['enableCSSSelector'] === 'true', defaultOverflowVisible: config['defaultOverflowVisible'] === 'true', defaultDisplayLinear: config['defaultDisplayLinear'] !== 'false', // Default to true if not present or 'true' + transformVW: transformVW, + transformVH: transformVH, }, ); diff --git a/packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts b/packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts index bb7179816b..b0e5a7c53a 100644 --- a/packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts +++ b/packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts @@ -96,11 +96,15 @@ export function createElementAPI( enableCSSSelector: boolean; defaultOverflowVisible: boolean; defaultDisplayLinear: boolean; + transformVW: boolean; + transformVH: boolean; }, ): { globalThisAPIs: ElementPAPIs; wasmContext: MainThreadServerContext } { const wasmContext = new MainThreadServerContext( viewAttributes, config.enableCSSSelector, + config.transformVW, + config.transformVH, ); if (styleInfo) { const resource = new StyleSheetResource(styleInfo, undefined);