Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fix-rpx-unit-inline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@lynx-js/web-core": patch
---

fix: tokenizing inline style values correctly to support rpx and ppx unit conversion

This fixes an issue where the `transform_inline_style_key_value_vec` API bypassed the CSS tokenizer, preventing dimension units like `rpx` or `ppx` from being successfully transformed into `calc` strings when specified via inline styles.
5 changes: 5 additions & 0 deletions .changeset/transform-ppx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@lynx-js/web-core": patch
---

feat: add `ppx` unit support for CSS, transforming to `calc(... * var(--ppx-unit))` directly.
24 changes: 24 additions & 0 deletions packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,30 @@ test.describe('reactlynx3 tests', () => {
await expect(target).toHaveCSS('width', '10px');
});

test('basic-rpx-unit-js-value', 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-ppx-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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { root } from '@lynx-js/react';

function App() {
return (
<view
id='target'
style={{
height: '20ppx',
width: '20ppx',
background: 'pink',
}}
/>
);
}

root.render(<App></App>);
Original file line number Diff line number Diff line change
@@ -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 (
<view
id='target'
style={{
height: `${10 + 10}rpx`,
width: '20rpx',
background: 'pink',
}}
/>
);
}

root.render(<App></App>);
6 changes: 3 additions & 3 deletions packages/web-platform/web-core/binary/client/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawS

export function get_font_face_content(buffer: Uint8Array): string;

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_key_value_vec(dom: HTMLElement, k_v_vec: string[], transform_vw: boolean, transform_vh: boolean): void;

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;
Expand All @@ -195,7 +195,6 @@ export interface InitOutput {
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, 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];
Expand Down Expand Up @@ -232,6 +231,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_key_value_vec: (a: any, b: number, c: number, d: number, e: number) => void;
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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export const add_inline_style_raw_string_key: (a: any, b: number, c: number, d:
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, 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];
Expand Down Expand Up @@ -55,6 +54,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_key_value_vec: (a: any, b: number, c: number, d: number, e: number) => void;
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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ export function encode_legacy_json_generated_raw_style_info(raw_style_info: RawS

export function get_font_face_content(buffer: Uint8Array): string;

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_key_value_vec(dom: HTMLElement, k_v_vec: string[], transform_vw: boolean, transform_vh: boolean): void;

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;
Expand All @@ -195,7 +195,6 @@ export interface InitOutput {
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, 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;
Expand Down Expand Up @@ -232,6 +231,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_key_value_vec: (a: number, b: number, c: number, d: number, e: number) => void;
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export const add_inline_style_raw_string_key: (a: number, b: number, c: number,
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, 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;
Expand Down Expand Up @@ -55,6 +54,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_key_value_vec: (a: number, b: number, c: number, d: number, e: number) => void;
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;
Expand Down
7 changes: 7 additions & 0 deletions packages/web-platform/web-core/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ lynx-view {
container-name: lynx-view;
container-type: inline-size;
--rpx-unit: 1cqw;
--ppx-unit: 1cqw;
--vw-unit: 1vw;
--vh-unit: 1vh;
}
Expand All @@ -34,6 +35,7 @@ lynx-view::part(page) {
height: 100%;
width: 100%;
--rpx-unit: inherit;
--ppx-unit: inherit;
--vw-unit: inherit;
--vh-unit: inherit;
}
Expand All @@ -43,6 +45,11 @@ lynx-view::part(page) {
inherits: true;
}

@property --ppx-unit {
syntax: "<length>";
inherits: true;
}

@property --vw-unit {
syntax: "<length>";
inherits: true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub fn set_inline_styles_in_str(
}

#[wasm_bindgen]
pub fn get_inline_styles_in_key_value_vec(
pub fn set_inline_styles_in_key_value_vec(
dom: &web_sys::HtmlElement,
k_v_vec: Vec<String>,
transform_vw: bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ pub(crate) fn transform_inline_style_key_value_vec(
key = value;
} else {
let name = hyphenate_style_name(&key);
transformer.on_declaration_parsed(name.into(), value, false);
use crate::css_tokenizer::tokenize::Parser;
transformer.on_token(crate::css_tokenizer::token_types::IDENT_TOKEN, &name);
transformer.on_token(crate::css_tokenizer::token_types::COLON_TOKEN, ":");
crate::css_tokenizer::tokenize::tokenize(&value, transformer);
transformer.on_token(crate::css_tokenizer::token_types::SEMICOLON_TOKEN, ";");
}
}

Expand Down Expand Up @@ -273,4 +277,13 @@ mod tests {
let result = transform_inline_style_string(source, &TransformerConfig::default());
assert_eq!(result, "--align-self-row:start;--align-self-column:start;");
}

#[test]
fn rpx_unit_in_key_value_vec() {
let result = transform_inline_style_key_value_vec(
vec!["height".to_string(), "100rpx".to_string()],
&TransformerConfig::default(),
);
assert_eq!(result, "height:calc(100 * var(--rpx-unit));");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,38 @@ pub(crate) fn transform_one_token<'a>(
) -> (u8, Cow<'a, str>) {
match token_type {
DIMENSION_TOKEN => {
if token_value.len() > 3 && token_value.to_ascii_lowercase().ends_with("rpx") {
let value = &token_value[..token_value.len() - 3];
return (
token_type,
Cow::Owned(format!("calc({value} * var(--rpx-unit))")),
);
let len = token_value.len();
if len > 3 {
let suffix = &token_value[len - 3..];
if suffix.eq_ignore_ascii_case("rpx") {
let value = &token_value[..len - 3];
return (
token_type,
Cow::Owned(format!("calc({value} * var(--rpx-unit))")),
);
} else if suffix.eq_ignore_ascii_case("ppx") {
let value = &token_value[..len - 3];
return (
token_type,
Cow::Owned(format!("calc({value} * var(--ppx-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))")),
);
if len > 2 {
let suffix = &token_value[len - 2..];
if config.transform_vw && suffix.eq_ignore_ascii_case("vw") {
let value = &token_value[..len - 2];
return (
token_type,
Cow::Owned(format!("calc({value} * var(--vw-unit))")),
);
} else if config.transform_vh && suffix.eq_ignore_ascii_case("vh") {
let value = &token_value[..len - 2];
return (
token_type,
Cow::Owned(format!("calc({value} * var(--vh-unit))")),
);
}
}
(token_type, Cow::Borrowed(token_value))
}
Expand Down Expand Up @@ -86,6 +92,18 @@ mod tests {
assert_eq!(tv, "calc(100 * var(--rpx-unit))");
}

#[test]
fn test_transform_ppx() {
let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100ppx", &TransformerConfig::default());
assert_eq!(tv, "calc(100 * var(--ppx-unit))");
}

#[test]
fn test_transform_ppx_case_insensitive() {
let (_, tv) = transform_one_token(DIMENSION_TOKEN, "100PPX", &TransformerConfig::default());
assert_eq!(tv, "calc(100 * var(--ppx-unit))");
}

#[test]
fn test_transform_vw() {
let (_, tv) = transform_one_token(
Expand Down
1 change: 1 addition & 0 deletions packages/web-platform/web-core/test_transformer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use std::borrow::Cow;
21 changes: 18 additions & 3 deletions packages/web-platform/web-core/tests/element-apis.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,19 @@ describe('Element APIs', () => {
expect(targetStyle).toContain('calc(50.5 * var(--rpx-unit))');
});

test('__SetInlineStyles with ppx', () => {
const root = mtsGlobalThis.__CreatePage('page', 0);
let target = mtsGlobalThis.__CreateView(0);
mtsGlobalThis.__SetID(target, 'target');
mtsGlobalThis.__SetInlineStyles(target, 'margin: 10ppx; width: 50.5ppx;');
mtsGlobalThis.__AppendElement(root, target);
mtsGlobalThis.__FlushElementTree();
const targetDom = rootDom.querySelector('#target') as HTMLElement;
const targetStyle = targetDom.getAttribute('style');
expect(targetStyle).toContain('calc(10 * var(--ppx-unit))');
expect(targetStyle).toContain('calc(50.5 * var(--ppx-unit))');
});

test('__SetInlineStyles with vw and vh when enabled', () => {
const mtsGlobalThisUnits = createElementAPI(
rootDom,
Expand Down Expand Up @@ -460,7 +473,7 @@ describe('Element APIs', () => {
expect(targetStyle).toBe('width:50vw;height:100vh;');
});

test('__SetAttribute style with rpx, vw, vh', () => {
test('__SetAttribute style with rpx, ppx, vw, vh', () => {
const mtsGlobalThisUnits = createElementAPI(
rootDom,
mtsBinding,
Expand All @@ -476,13 +489,15 @@ describe('Element APIs', () => {
mtsGlobalThisUnits.__SetAttribute(
target,
'style',
'width: 50vw; height: 100vh; margin: 10rpx;',
'width: 50vw; height: 100vh; margin: 10rpx; padding: 5ppx;',
);
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;');
expect(targetStyle).toBe(
'width: 50vw; height: 100vh; margin: 10rpx; padding: 5ppx;',
);
Comment thread
PupilTong marked this conversation as resolved.
});

test('__GetConfig__AddConfig', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const {
add_inline_style_raw_string_key,
set_inline_styles_number_key,
set_inline_styles_in_str,
get_inline_styles_in_key_value_vec,
set_inline_styles_in_key_value_vec,
} = wasmInstance;

export function createElementAPI(
Expand Down Expand Up @@ -306,7 +306,7 @@ export function createElementAPI(
vec.push(k, v.toString());
}
}
get_inline_styles_in_key_value_vec(
set_inline_styles_in_key_value_vec(
element,
vec,
transform_vw,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@
vec.push(k, v.toString());
}
}
wasmContext.get_inline_styles_in_key_value_vec(
wasmContext.set_inline_styles_in_key_value_vec(

Check failure on line 437 in packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Property 'set_inline_styles_in_key_value_vec' does not exist on type 'MainThreadServerContext'. Did you mean 'get_inline_styles_in_key_value_vec'?

Check failure on line 437 in packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts

View workflow job for this annotation

GitHub Actions / build / Build (Ubuntu)

Property 'set_inline_styles_in_key_value_vec' does not exist on type 'MainThreadServerContext'. Did you mean 'get_inline_styles_in_key_value_vec'?

Check failure on line 437 in packages/web-platform/web-core/ts/server/elementAPIs/createElementAPI.ts

View workflow job for this annotation

GitHub Actions / build / Build (Windows)

Property 'set_inline_styles_in_key_value_vec' does not exist on type 'MainThreadServerContext'. Did you mean 'get_inline_styles_in_key_value_vec'?
uniqueId,
vec,
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand Down
Loading