Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
12 changes: 12 additions & 0 deletions packages/web-platform/web-core-wasm/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ This package uses `pnpm` for dependency management and scripts.
- **Install Dependencies**: `pnpm install`
- **Build WASM**: `pnpm build` (This runs the `scripts/build.js` script, which builds both `client` and `encode` features)
- **Test**: `pnpm test` (Uses `vitest` to run tests in `tests/`)
- `tests/encode.spec.ts`: Verifies CSS encoding (build-time).
- `tests/element-apis.spec.ts`: comprehensive tests for `createElementAPI` and DOM interactions.
- `tests/lazy-load.spec.ts`: Verifies the lazy loading mechanism for elements.

### Build Script (`scripts/build.js`)

Expand All @@ -150,6 +153,15 @@ The `scripts/build.js` script handles the complex build process:
- **`wasm.ts`**: Handles the loading of the WASM module. It supports `WebAssembly.compileStreaming` in browsers and falls back for other environments. It exports `wasmInstance` and `wasmModule`.
- **`DecodedStyle`**: A wrapper class around the WASM `DecodedStyleData` struct. It provides a convenient API for accessing decoded style information in TypeScript, handling `Uint8Array` decoding and string caching.

### Main Thread Runtime (`ts/client/mainthread`)

The main thread runtime creates the environment for Lynx views to run in the browser.

- **`TemplateManager.ts`**: Manages the loading, decoding, and caching of templates. It offloads CPU-intensive decoding tasks to a Web Worker (`decode.worker.js`) to keep the main thread responsive. It handles various template sections (configurations, style info, custom sections) and orchestrates the worker lifecycle.
- **`LynxView.ts`**: Defines the `<lynx-view>` custom element. It serves as the entry point for embedding Lynx cards, managing properties like `url`, `initData`, and `globalProps`. It uses `TemplateManager` to fetch bundles and creates `LynxViewInstance` to render content.
- **`LynxViewInstance.ts`**: Represents a single instance of a Lynx view. It manages the lifecycle of the view, handles data updates, and interacts with the Wasm core to render the component tree.
- **`elementAPIs/createElementAPI.ts`**: Bridges the JavaScript runtime with the Wasm `MainThreadWasmContext`. It provides a comprehensive set of APIs (`__CreateView`, `__SetAttribute`, `__AppendElement`, etc.) for direct DOM manipulation and interaction with the Wasm core. It also handles the integration with the lazy loading mechanism ensuring elements are loaded on demand.

### Encode (`ts/encode`)

- **`encodeCSS.ts`**: Provides the `encodeCSS` function, which takes a map of CSS ASTs (from `@lynx-js/css-serializer`) and encodes them into a `Uint8Array` using the `encode` feature of the WASM module. This is used by build tools to serialize CSS.
Expand Down
9 changes: 9 additions & 0 deletions packages/web-platform/web-core-wasm/css/in_shadow.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import url("./linear.css");
@import url("@lynx-js/web-elements/elements.css");
[lynx-default-display-linear="false"] * {
--lynx-display: flex;
--lynx-display-toggle: var(--lynx-display-flex);
}
[lynx-default-overflow-visible="true"] x-view {
overflow: visible;
}
119 changes: 119 additions & 0 deletions packages/web-platform/web-core-wasm/css/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
// 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.
*/

lynx-view {
contain: strict;
display: none;
}

lynx-view[width="auto"] {
--lynx-view-width: 100%;
width: var(--lynx-view-width);
inline-size: var(--lynx-view-width);
}

lynx-view[height="auto"], lynx-view[width="auto"] {
contain: content;
}

lynx-view::part(page) {
height: 100%;
width: 100%;
}

@property --lynx-display {
syntax: "linear | flex";
inherits: false;
initial-value: linear;
}
@property --lynx-linear-weight-sum {
syntax: "<number>";
inherits: false;
initial-value: 1;
}
@property --lynx-linear-weight {
syntax: "<number>";
inherits: false;
initial-value: 0;
}
@property --justify-content-column {
syntax: "flex-start|flex-end|center|space-between|space-around";
inherits: false;
initial-value: flex-start;
}
@property --justify-content-column-reverse {
syntax: "flex-start|flex-end|center|space-between|space-around";
inherits: false;
initial-value: flex-start;
}
@property --justify-content-row {
syntax: "flex-start|flex-end|center|space-between|space-around";
inherits: false;
initial-value: flex-start;
}
@property --justify-content-row-reverse {
syntax: "flex-start|flex-end|center|space-between|space-around";
inherits: false;
initial-value: flex-start;
}
@property --align-self-row {
syntax: "start|end|center|stretch|auto";
inherits: false;
initial-value: auto;
}
@property --align-self-column {
syntax: "start|end|center|stretch|auto";
inherits: false;
initial-value: auto;
}
@property --lynx-linear-weight-basis {
syntax: "auto|<number>|<length>";
inherits: false;
initial-value: auto;
}
@property --lynx-linear-orientation {
syntax: "<custom-ident>";
inherits: false;
initial-value: vertical;
}

@property --flex-direction {
syntax: "*";
inherits: false;
}
@property --flex-wrap {
syntax: "*";
inherits: false;
}
@property --flex-grow {
syntax: "<number>";
inherits: false;
initial-value: 0;
}
@property --flex-shrink {
syntax: "<number>";
inherits: false;
initial-value: 1;
}
@property --flex-basis {
syntax: "*";
inherits: false;
initial-value: auto;
}
@property --flex-value {
syntax: "*";
inherits: false;
}
@property --flex {
syntax: "*";
inherits: false;
}

@property --linear-justify-content {
syntax: "flex-start|flex-end|center|space-between|space-around";
inherits: false;
initial-value: flex-start;
}
167 changes: 167 additions & 0 deletions packages/web-platform/web-core-wasm/css/linear.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
div * {
display: flex;
box-sizing: border-box;
border-width: 0px;
position: relative;
overflow: clip;
min-width: 0;
min-height: 0;
border-style: solid;
scrollbar-width: none;
}

x-view::--webkit-scrollbar {
display: none;
}

/**
* only enable this toggle logic for those container elements
*/
div * {
/*
--lynx-display-toggle is compile-time generated.
*/
--lynx-display-toggle: var(--lynx-display-linear);
--lynx-display-linear: var(--lynx-display-toggle,);
--lynx-display-flex: var(--lynx-display-toggle,);
/*
--lynx-linear-orientation-toggle is compile-time generated.
*/
--lynx-linear-orientation-toggle: var(--lynx-linear-orientation-vertical);
--lynx-linear-orientation-horizontal: var(--lynx-linear-orientation-toggle,);
--lynx-linear-orientation-vertical: var(--lynx-linear-orientation-toggle,);
--lynx-linear-orientation-horizontal-reverse: var(
--lynx-linear-orientation-toggle,
);
--lynx-linear-orientation-vertical-reverse: var(
--lynx-linear-orientation-toggle,
);

--linear-flex-direction: var(--lynx-linear-orientation-horizontal, row) var(
--lynx-linear-orientation-vertical,
column
) var(--lynx-linear-orientation-horizontal-reverse, row-reverse) var(
--lynx-linear-orientation-vertical-reverse,
column-reverse
);
--linear-justify-content: var(
--lynx-linear-orientation-horizontal,
var(--justify-content-row)
) var(--lynx-linear-orientation-vertical, var(--justify-content-column)) var(
--lynx-linear-orientation-horizontal-reverse,
var(--justify-content-row-reverse)
) var(
--lynx-linear-orientation-vertical-reverse,
var(--justify-content-column-reverse)
);
}
div * {
flex-wrap: var(--lynx-display-linear, nowrap)
var(
--lynx-display-flex,
var(--flex-wrap)
);
flex-direction: var(--lynx-display-linear, var(--linear-flex-direction))
var(
--lynx-display-flex,
var(--flex-direction)
);
justify-content: var(--lynx-display-linear, var(--linear-justify-content));
}

/** For @container
*
* when the chromuim version is less than 116.0.5806.0, the following code will crash:
* ```
* <style>
#container {
--lynx-display: flex;
}

#target {
background-color: red;
width: 400px;
height: 400px;
}

@container style(--lynx-display: flex) {
#target {
background-color: green;
}
}
</style>
<div id="container">
<div id="target"></div>
</div>
<script>
const target = document.getElementById('container');
container.style.setProperty('display', 'none');
setTimeout(() => {
target.style.removeProperty('display');
}, 10);
</script>
* ```
* it fixed in 116.0.5806.0, detail: https://issues.chromium.org/issues/40270007
*
* so we limit this feature to chrome 117, safari 18, firefox no:
* rex unit: chrome 111, safari 17.2, firefox no
* https://developer.mozilla.org/en-US/docs/Web/CSS/length
* transition-behavior:allow-discrete: chrome 117, safari 18, firefox 125
* https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior
* https://caniuse.com/mdn-css_properties_display_is_transitionable
*
* update this once firefox supports this.
*
* If you want to be fully compatible with chrome below 117, you need to use a plugin @lynx-js/web-elements-compat.
*/
@supports (content-visibility: auto) and
(transition-behavior: allow-discrete) and (width: 1rex) {
@container style(--lynx-display: linear) {
div * {
/*
`--lynx-linear-weight-sum`
0 -> 1
<value> -> <value>
*/
flex-shrink: 0;
/* The following `calc` and `clamp` logic ensures that if
`--lynx-linear-weight-sum` is zero, it defaults to 1. This prevents
division by zero and ensures consistent behavior. */
flex-grow: calc(
var(--lynx-linear-weight) /
calc(
var(--lynx-linear-weight-sum) +
(
1 - clamp(0, var(--lynx-linear-weight-sum) * 999999, 1)
)
)
);
flex-basis: var(--lynx-linear-weight-basis);
}
}

@container not style(--lynx-display: linear) {
div * {
flex: var(
--flex,
var(--flex-grow) var(--flex-shrink) var(--flex-basis)
);
}
}

@container style(--lynx-display: linear) and
(style(--lynx-linear-orientation: vertical) or
style(--lynx-linear-orientation: vertical-reverse)) {
div * {
align-self: var(--align-self-column);
}
}

@container style(--lynx-display: linear) and
(style(--lynx-linear-orientation: horizontal) or
style(--lynx-linear-orientation: horizontal-reverse)) {
div * {
align-self: var(--align-self-row);
}
}
}
6 changes: 5 additions & 1 deletion packages/web-platform/web-core-wasm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
"last 1 chrome version"
]
},
"dependencies": {
"@lynx-js/web-elements": "workspace:*",
"@lynx-js/web-worker-rpc": "workspace:*",
"hyphenate-style-name": "^1.1.0"
},
"devDependencies": {
"@lynx-js/css-serializer": "workspace:*",
"@lynx-js/lynx-core": "0.1.3",
Expand All @@ -51,7 +56,6 @@
"fb-dotslash": "^0.5.8",
"jsdom": "^27.4.0",
"tslib": "^2.8.1",
"vite-plugin-wasm": "^3.5.0",
"wasm-feature-detect": "^1.8.0"
},
"peerDependencies": {
Expand Down
Loading
Loading