# Lynx > Accessibility (A11y) refers to the design concept of building accessibility through technical means to ensure that mobile applications can be equally accessed by all kinds of people. --- # Source: https://lynxjs.org/guide/inclusion/accessibility.md # Accessibility Accessibility (A11y) refers to the design concept of building accessibility through technical means to ensure that mobile applications can be equally accessed by all kinds of people. Its core goal is to break down usage barriers, allowing users with different physical conditions, perceptual abilities, and cognitive levels to smoothly obtain information and services. Mainstream mobile platforms provide a complete accessibility support system: iOS and Android not only natively integrate APIs for users with disabilities but also come equipped with standardized assistive technology toolchains, such as screen readers (VoiceOver / TalkBack) designed specifically for visually impaired users. On this basis, the Lynx framework encapsulates cross-platform accessibility interfaces, enabling developers to integrate accessibility features in their apps and build an information-accessible mobile ecosystem. :::info Different platforms have distinct designs and norms regarding accessibility; therefore, implementation and experience with Lynx may vary across platforms. ::: ## Default Accessibility Behavior Only one accessibility element can be successfully accessed and focused by screen readers (VoiceOver on iOS and TalkBack on Android). However, `` and `` are default accessibility elements and can be recognized without any further action. **This is an example below: accessibility** **Entry:** `src/Default.tsx` **Bundle:** `dist/main.lynx.bundle` | Web: `dist/main.web.bundle` ```tsx {4-5} export const Default = ({ src }: { src: string }) => { return ( Hello world ); }; ``` ## Tagging Accessibility Elements Sometimes, you might want to control the size of accessibility elements or aggregate some accessibility information, requiring control over which elements are accessibility nodes. Use [`accessibility-element`](/api/elements/built-in/view.md#accessibility-element) to tag an element as an accessibility element; nested elements are allowed. In the example below, there will be only one accessibility focus point and it will be read as "Hello world". **This is an example below: accessibility** **Entry:** `src/Customized.tsx` **Bundle:** `dist/main.lynx.bundle` | Web: `dist/main.web.bundle` ```tsx {5,8,9} export const Customized = ({ src }: { src: string }) => { return ( Hello world ); }; ``` :::info On `` and ``, this property is set to `true` by default. ::: ## Specifying the Characteristics and Content of Accessibility Elements Use [`accessibility-trait`](/api/elements/built-in/view.md#accessibility-trait) to mark the characteristics of an accessibility element, which can be any of image, button, or text. Use [`accessibility-label`](/api/elements/built-in/view.md#accessibility-label) to adjust the content that screen readers will read for an accessibility element. :::info On ``, the default is to read the content of the text. ::: In the example below, the elements will be read as "Hello lynx" and "I am an image displaying the Lynx icon," respectively. **This is an example below: accessibility** **Entry:** `src/LabelAndTraits.tsx` **Bundle:** `dist/main.lynx.bundle` | Web: `dist/main.web.bundle` ```tsx {6,7,16,17} export const LabelAndTraits = ({ src }: { src: string }) => { return ( Hello world ); }; ``` ## Adjusting the Reading Order of Accessibility Elements iOS and Android systems default to arranging accessibility elements from top to bottom and left to right so they can be accessed sequentially by screen readers. Use [`accessibility-elements`](/api/elements/built-in/view.md#accessibility-elements) to manually adjust this order. Note that each id should be separated by a comma. Furthermore, if a parent node sets the [`accessibility-elements`](/api/elements/built-in/view.md#accessibility-elements) property, only child nodes specified by the [`accessibility-elements`](/api/elements/built-in/view.md#accessibility-elements) attribute can be accessed, while other child nodes cannot be focused. In the example below, the order of accessibility elements will be adjusted, and they will be read as "Lynx" and "Hello" sequentially. **This is an example below: accessibility** **Entry:** `src/ReOrder.tsx` **Bundle:** `dist/main.lynx.bundle` | Web: `dist/main.web.bundle` ```tsx {3,5,6} export const ReOrder = ({ src }: { src: string }) => { return ( Hello Lynx ); }; ``` ## Listening to Focus Changes of Accessibility Elements When the focus of accessibility elements changes, a global event `activeElement` notifies the information of the newly focused node. ```tsx export default class App extends Component { componentDidMount() { // Listen for focus changes this.getJSModule('GlobalEventEmitter').addListener( 'activeElement', this.handleActiveElement, this, ); } handleActiveElement(info: any) { this.setState({ activeElementJsonStr: JSON.stringify(info), }); } } ``` ## Actively Focusing on an Accessibility Element Use [`requestAccessibilityFocus`](/api/elements/built-in/view.md#requestaccessibilityfocus) to provide the capability to actively focus on an accessibility element. ```ts lynx .createSelectorQuery() .select('#customId') .invoke({ method: 'requestAccessibilityFocus', params: {}, success: function (res) { console.log(res); }, fail: function (res) { console.log(res); }, }) .exec(); ``` ## Make Screen Readers Announce Specified Text Content Use [`accessibilityAnnounce`](/api/lynx-api/lynx/lynx-accessibility-announce.md#accessibilityAnnounce) to make screen readers announce the specified text content, helping visually impaired users perceive interface state changes or operation results. ```jsx lynx.accessibilityAnnounce( { content: 'hello lynx', }, (res) => { console.log('test: ' + JSON.stringify(res)); }, ); ``` --- # Source: https://lynxjs.org/ai/agentsmd.md # `AGENTS.md` for Lynx The [`AGENTS.md`](https://agents.md) file is similar to `README.md`, but it's for agents. In this document, you'll learn how to add a suitable `AGENTS.md` for your Lynx project, ensuring your agents can perform at their best within your Lynx project. ## Creating a New Project We've included `AGENTS.md` in the initial project template. You can refer to [Quick Start](/guide/start/quick-start.md#create-a-new-lynx-project) to create a new Lynx project. The project's root directory will contain a pre-written `AGENTS.md` file. ## Adding `AGENTS.md` to an Existing Project For Lynx projects, you can start with this file and then modify it according to your project needs: - [`AGENTS.md` in Lynx Template Project](https://github.com/lynx-family/lynx-stack/blob/main/packages/rspeedy/create-rspeedy/template-common/AGENTS.md) ## Modifying the existing `AGENTS.md` Below is an example; please add the "Read in Advance" section to your project's `AGENTS.md`: :::info No Magic Spell This section isn't a magic spell; it works because: 1. It provides the agent with the LLM-friendly Lynx website: [llms.txt](https://lynxjs.org/llms.txt). 2. It explicitly emphasizes the importance of reading [llms.txt](https://lynxjs.org/llms.txt) in `AGENTS.md` to agents. ::: ```markdown # My Awesome Project ## Read in Advance Read the docs below in advance to help you understand the library or frameworks this project depends on. - Lynx: [llms.txt](https://lynxjs.org/llms.txt). While dealing with a Lynx task, an agent **MUST** read this doc because it is an entry point of all available docs about Lynx. ## Build Instructions ## Test Instructions ``` ## Using `AGENTS.md` in a Monorepo In a monorepo, you can add an `AGENTS.md` file to each subproject to provide specific guidance and information to agents for each subproject. This helps ensure that agents can optimize and adapt to the needs and characteristics of their respective sub-projects. However, you can use `AGENTS.md` in the monorepo root directory as a global guideline file, providing general information and guiding principles. For example: ```bash $ tree . ├── AGENTS.md # the global AGENTS.md ├── README.md └── packages ├── web │ ├── AGENTS.md # the AGENTS.md for web project │ ├── package-a │ │ └── AGENTS.md │ └── package-b │ └── AGENTS.md └── lynx ├── AGENTS.md # the AGENTS.md for lynx project ├── package-c │ └── AGENTS.md └── package-d └── AGENTS.md # the AGENTS.md for d subproject ``` In this example, you should place Lynx-specific guidance and information in `packages/lynx/AGENTS.md`. For example, when agents process tasks under package-d, they should first refer to `packages/lynx/package-d/AGENTS.md`, then `packages/lynx/AGENTS.md`, and finally the `AGENTS.md` in the root directory. Organizing the `AGENTS.md` files in a tree structure avoids repetitive writing of the same information and ensures that agents can access the most relevant and up-to-date guidance. However, developers should ensure that the information in the various `AGENTS.md` files does not conflict with each other to avoid causing abnormal agent behavior. ## Using `llms.txt` as `AGENTS.md` If agents are not reading the Lynx documentation as required, consider inlining or overwriting the contents of `llms.txt` into `AGENTS.md`. ```bash curl https://lynxjs.org/llms.txt > packages/lynx/AGENTS.md ``` It is recommended to use this method only for public `AGENTS.md` files to avoid duplicate content across multiple files and to override customized instructions for specific subprojects. If you want to keep `llms.txt` up-to-date, you can add the above command to the prepare script in your package.json (or root package.json for monorepo). Remember to gitignore the generated `AGENTS.md` file to avoid committing it to version control. ## Troubleshooting ### Agents Not Reading Lynx Documentation as Required Ensure that the "Read in Advance" section is correctly added to `AGENTS.md`, explicitly stating that agents must read [llms.txt](https://lynxjs.org/llms.txt). If the problem persists, consider inlining the contents of `llms.txt` directly into `AGENTS.md`, as shown in the example above. --- # Source: https://lynxjs.org/guide/styling/animation.md # Motion Lynx offers extensive motion capabilities, allowing developers to create more modern, smooth, and intuitive user interfaces. Utilizing these features, developers can produce stunning transition effects and natural motion feedback, thereby enhancing user experience. ## Add transitions for layout and style changes. If you need to smoothly apply new property values when the layout or style changes, you can use transitions. Transitions provide a way to control the speed of animation changes when altering CSS properties. Instead of having changes take effect immediately, you can have the changes happen gradually over a period of time. For example, when you change an element's color from white to black, normally the change happens instantaneously. With transitions enabled, the change takes place over an interval that follows an easing curve, all of which can be customized. Transitions are automatically triggered, non-repetitive, and easy to use. They can be defined using the shorthand [`transition`](/api/css/properties/transition.md) to set animation properties and duration, or you can specify them individually with [`transition-property`](/api/css/properties/transition-property.md) and [`transition-duration`](/api/css/properties/transition-duration.md), among others. ### Implement Collapse and Expand Effect for List Items You can use transitions to add an animation effect for expanding and collapsing a list item in a list: **This is an example below: animation** **Entry:** `src/transition_toggle` **Bundle:** `dist/toggle_transition_demo.lynx.bundle` | Web: `dist/toggle_transition_demo.web.bundle` ```tsx import { root, useState } from "@lynx-js/react"; import type { ReactNode } from "@lynx-js/react"; import "./index.scss"; const AccordionItem = ({ title, content }: { title: ReactNode; content: ReactNode }) => { const [isActive, setIsActive] = useState(false); const toggleItem = () => { setIsActive(!isActive); }; return ( {title} {content} ); }; const Accordion = () => { const items = [ { title: "Item 1", content: "This is the content of item 1. ".repeat(10), }, { title: "Item 2", content: "This is the content of item 2. ".repeat(10), }, { title: "Item 3", content: "This is the content of item 3. ".repeat(10), }, ]; return ( {items.map((item, index) => )} ); }; root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` ## Achieve stunning effects with keyframes. If you need multiple sets of styles to transition in sequence, you can use keyframe animations. Keyframe animations are defined in CSS using the [`@keyframes`](/api/css/at-rule/keyframes.md) rule, which specifies the style changes at various stages of the animation. The [`animation`](/api/css/properties/animation.md) property is then used to apply the defined animation to elements, allowing you to set parameters such as animation name, duration, delay, and number of iterations. Keyframe animations are more flexible and controllable compared to transitions, as they allow you to specify the process and provide finer control over timing curves. You can define them in CSS with [`@keyframes`](/api/css/at-rule/keyframes.md) and specify them using the shorthand [`animation`](/api/css/properties/animation.md) property, or define them with individual properties such as [`animation-name`](/api/css/properties/animation-name.md), [`animation-duration`](/api/css/properties/animation-duration.md), and others. ### To achieve a rotation effect Keyframe animations can be used to achieve the effect of a bounding box rotation. **This is an example below: animation** **Entry:** `src/keyframe_rotate` **Bundle:** `dist/keyframe_rotate.lynx.bundle` | Web: `dist/keyframe_rotate.web.bundle` ```scss page { background-color: #f7f7f7; display: flex; justify-content: center; align-items: center; height: 100vh; } .container { border: 1px solid red; } .title-name-wrapper-border { position: relative; z-index: 0; width: 100%; height: 100%; border-radius: 10px; overflow: hidden; padding: 2rem; } @keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(1turn); } } @keyframes opacityChange { 50% { opacity: 1; } 100% { opacity: 0.5; } } .container { position: relative; z-index: 0; width: 80%; height: 300px; border-radius: 10px; overflow: hidden; } .title-name-wrapper-border-before { position: absolute; z-index: -2; left: -50%; top: -50%; width: 200%; height: 200%; background-color: red; background-repeat: no-repeat, no-repeat, no-repeat, no-repeat; background-size: 50% 50%, 50% 50%; background-position: 0px 0px, 100% 0px, 100% 100%, 0px 100%; background-image: linear-gradient(#399953, #399953), linear-gradient(#fbb300, #fbb300), linear-gradient(#d53e33, #d53e33), linear-gradient(#377af5, #377af5); animation: rotate 4s linear infinite; } .title-name-wrapper-border-after { position: absolute; z-index: -1; left: 6px; top: 6px; width: calc(100% - 12px); height: calc(100% - 12px); background: white; border-radius: 5px; animation: opacityChange 3s infinite alternate; } ``` ### To achieve a spring effect Keyframe animations can add spring-like physics to element motion. **This is an example below: animation** **Entry:** `src/keyframe_spring` **Bundle:** `dist/keyframe_spring.lynx.bundle` | Web: `dist/keyframe_spring.web.bundle` ```scss .container { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f5f5f5; } .spring-box { width: 200px; height: 200px; background-color: #4a90e2; border-radius: 8px; display: flex; justify-content: center; align-items: center; } .box-text { color: white; font-size: 24px; } .animate { animation: kf-anim-spring 4s linear forwards; } @keyframes kf-anim-spring { 0% { transform: scale(0, 0); } 0.999% { transform: scale(0.306, 0.306); } 1.998% { transform: scale(0.967, 0.967); } 2.997% { transform: scale(1.586, 1.586); } 3.996% { transform: scale(1.825, 1.825); } 4.995% { transform: scale(1.586, 1.586); } 5.994% { transform: scale(1.046, 1.046); } 6.993% { transform: scale(0.529, 0.529); } 7.992% { transform: scale(0.319, 0.319); } 9.09% { transform: scale(0.54, 0.54); } 10.089% { transform: scale(0.993, 0.993); } 11.088% { transform: scale(1.409, 1.409); } 12.087% { transform: scale(1.561, 1.561); } 13.086% { transform: scale(1.389, 1.389); } 14.085% { transform: scale(1.018, 1.018); } 15.084% { transform: scale(0.671, 0.671); } 16.083% { transform: scale(0.537, 0.537); } 17.082% { transform: scale(0.67, 0.67); } 18.081% { transform: scale(0.973, 0.973); } 19.08% { transform: scale(1.263, 1.263); } 20.079% { transform: scale(1.381, 1.381); } 21.178% { transform: scale(1.258, 1.258); } 22.177% { transform: scale(1.003, 1.003); } 23.176% { transform: scale(0.77, 0.77); } 24.175% { transform: scale(0.685, 0.685); } 25.174% { transform: scale(0.781, 0.781); } 26.173% { transform: scale(0.989, 0.989); } 27.172% { transform: scale(1.184, 1.184); } 28.171% { transform: scale(1.259, 1.259); } 29.17% { transform: scale(1.185, 1.185); } 30.169% { transform: scale(1.015, 1.015); } 31.168% { transform: scale(0.852, 0.852); } 32.167% { transform: scale(0.785, 0.785); } 33.266% { transform: scale(0.855, 0.855); } 34.265% { transform: scale(0.997, 0.997); } 35.264% { transform: scale(1.128, 1.128); } 36.263% { transform: scale(1.176, 1.176); } 38.261% { transform: scale(1.006, 1.006); } 40.259% { transform: scale(0.854, 0.854); } 42.257% { transform: scale(0.991, 0.991); } 44.255% { transform: scale(1.12, 1.12); } 46.353% { transform: scale(1.001, 1.001); } 48.351% { transform: scale(0.9, 0.9); } 52.347% { transform: scale(1.081, 1.081); } 56.343% { transform: scale(0.932, 0.932); } 60.439% { transform: scale(1.055, 1.055); } 64.435% { transform: scale(0.954, 0.954); } 68.431% { transform: scale(1.037, 1.037); } 72.527% { transform: scale(0.968, 0.968); } 76.523% { transform: scale(1.025, 1.025); } 80.519% { transform: scale(0.978, 0.978); } 84.615% { transform: scale(1.017, 1.017); } 88.611% { transform: scale(0.985, 0.985); } 92.607% { transform: scale(1.011, 1.011); } 96.703% { transform: scale(0.99, 0.99); } 100% { transform: scale(1.006, 1.006); } } ``` ## Create flexible keyframe animations in JS. Additionally, our [animate api](/api/lynx-api/lynx/lynx-animate-api.md) extends CSS keyframe animations, allowing for more flexible and dynamic creation and control of animations in JavaScript. Developers can dynamically generate and modify animations at runtime based on interactions or logic, offering users a more vibrant and interactive experience. ### To achieve a variable speed transform motions By using the animate api, we can add a motion to the original that changes its rate in real time. **This is an example below: animation** **Entry:** `src/animate` **Bundle:** `dist/animate.lynx.bundle` ```tsx import { root } from "@lynx-js/react"; import "./index.scss"; const AnimateAnimationExample = () => { return ( { const ani = lynx.getElementById("view1").animate( [ { transform: "translate(0%, 0%) rotate(0deg)", "animation-timing-function": "linear", }, { transform: "translate(200px, 0%) rotate(90deg)", "animation-timing-function": "cubic-bezier(.91,.03,.94,.11)", }, { transform: "translate(200px, 100%) rotate(180deg)", "animation-timing-function": "linear", }, { transform: "translate(0%, 100%) rotate(270deg)", "animation-timing-function": "cubic-bezier(.91,.03,.94,.11)", }, { transform: "translate(0%, 0%) rotate(360deg)", }, ], { name: "js-animation-1", duration: 5000, iterations: Infinity, easing: "linear", }, ); }} > ); }; root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` --- # Source: https://lynxjs.org/help/api.md # Documenting APIs The Lynx documentation relies on a structured system to ensure API references are accurate and consistent. ## Compatibility Data (`lynx-compat-data`) The source of truth for platform compatibility is stored in `packages/lynx-compat-data`. This is a JSON database similar to MDN's browser-compat-data. ### Adding a New API 1. Navigate to `packages/lynx-compat-data`. 2. Find the appropriate JSON file (e.g., `lynx-api/global/console/log.json`). 3. Add your API definition following the schema. ## Displaying API Tables To display a compatibility table in your documentation, use the `` component. ### Using Frontmatter (Recommended) It is recommended to define the `api` field in the frontmatter. ```yaml --- api: lynx-api/global/console/log --- ``` Then place `` in your MDX file. It will automatically read the `api` field. ```tsx ``` ### Multiple Tables (Explicit Query) When you need to display multiple tables on a single page, you can pass the `query` prop explicitly. For example, in [fetch](/api/lynx-api/global/fetch.md), separate tables are used for `Headers`, `Request`, and `Response`: ```tsx ### Headers ### Request ``` **Compatibility Table** **Query:** `lynx-api.fetch.Headers` **MDN Reference:** [https://developer.mozilla.org/docs/Web/API/Headers](https://developer.mozilla.org/docs/Web/API/Headers) **Platform Support** | Platform | Version Added | Notes | |----------|---------------|-------| | Android | 2.18 | - | | iOS | 2.18 | - | | HarmonyOS | 3.5 | - | | Web | ✅ Yes | - | You can verify valid queries using the [Interactive Explorer](#interactive-explorer) below. ## API Summary For a high-level view of API groups (like methods, properties, events), use ``. Similar to ``, it defaults to reading from the `api` frontmatter field. ```tsx ``` ## Interactive Explorer You can use the explorer below to find valid API queries and preview their tables. ## Validating Documentation We provide a script to ensure your API documentation matches the compatibility data. ```bash pnpm run check-docs ``` This script (`scripts/check_api_doc`) checks for: - Invalid `api` frontmatter keys. - Missing documentation for defined APIs. ## TypeDoc Generation API reference pages are automatically generated from TypeScript source code using TypeDoc. - **Config**: `scripts/typedoc/` - **Command**: `pnpm run typedoc` Do not manually edit files generated by TypeDoc (usually in `docs/en/api/...`), as they will be overwritten. Edit the source comments instead. --- # Source: https://lynxjs.org/guide/styling/appearance.md # Visual Appearance ## Background and Borders You can do a lot creative things with background and borders. Using [`background-image`](/api/css/properties/background-image.md) to apply network image or gradient effects to the background area of an element, using [`border-radius`](/api/css/properties/border-radius.md) to add a rounded corner, using [`box-shadow`](/api/css/properties/box-shadow.md) to create a shadow effect. In the following example, we add a background with gradient effect, two styles of borders at top and left sides, a black shadow to an element with the top right corner rounded. **This is an example below: css** **Entry:** `src/border_background_shadow` **Bundle:** `dist/border_background_shadow.lynx.bundle` | Web: `dist/border_background_shadow.web.bundle` ```tsx {8-12} import { root } from "@lynx-js/react"; function App() { return ( ); } root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` :::info [`border-image`](https://developer.mozilla.org/en-US/docs/Web/CSS/border-image) and related properties are under development. ::: ## Colors With Lynx CSS, you can apply color values to various properties to create the look you want. ### Properties that can have color #### Text - [`color`](/api/css/properties/color.md): The color to use when drawing the text. - [`-x-handle-color`](): The color of selection handlers (the cursur on the two ends of the selected text) when text is selected. - [`text-shadow`](/api/css/properties/text-shadow.md): The color of the shadow in the shape of text. - [`text-decoration-color`](/api/css/properties/text-decoration.md#text-decoration-color): The color to use when drawing the decoration line on the text. #### Background and Border - [`background-color`](/api/css/properties/background-color.md): The background color of the element. - [`box-shadow`](/api/css/properties/box-shadow.md): The color of shadow. - [`border-color`](/api/css/properties/border-color.md): The color to use when drawing the border. Can be set separately for the foursides via [`border-top-color`](/api/css/properties/border-color.md), [`border-top-color`](/api/css/properties/border-color.md), [`border-top-color`](/api/css/properties/border-color.md) or [`border-top-color`](/api/css/properties/border-color.md) as well. Colors can be set to the property via [`selectors`](/api/css/selectors.md) or the `style` property of the element directly. The color value should be a hex number start with a '#', or a value calculated by function `rgb()`, `rgba()` or `hsl()`. View the specification for [``](/api/css/data-type/color.md) value for more details. ## Gradient You can use [``](/api/css/data-type/gradient.md) value to define a gradient effect and apply it to the following properties: - [`color`](/api/css/properties/color.md): Drawing the text with a gradient effect. - [`background-image`](/api/css/properties/background-image.md): Fill the background area with a gradient effect. - [`mask-image`](/api/css/properties/mask-image.md): Use the gradient effect to create a alpha mask.

Text with a gradient color

Filling background with radial-gradient

Create a 'fading edge' effect by adding linear-gradient to mask-image property
## Clipping and Masking In Lynx, besides [`overflow`](/api/css/properties/overflow.md), you can show content of an element in the area you want using [`clip-path`](/api/css/properties/clip-path.md) and [`mask-image`](/api/css/properties/mask-image.md). **This is an example below: css** **Entry:** `src/clip_path_super_ellipse` **Bundle:** `dist/clip_path_super_ellipse.lynx.bundle` | Web: `dist/clip_path_super_ellipse.web.bundle` ```tsx {14} import { root } from "@lynx-js/react"; function App() { return ( LYNX ); } root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ```
Using clip-path to clip out a super-elliptical area
**This is an example below: css** **Entry:** `src/mask_image_circle_gradient` **Bundle:** `dist/mask_image_circle_gradient.lynx.bundle` | Web: `dist/mask_image_circle_gradient.web.bundle` ```tsx {14} import { root } from "@lynx-js/react"; function App() { return ( LYNX ); } root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ```
Using mask-image to create a circle area with fading edge
--- # Source: https://lynxjs.org/rspeedy/assets.md # Static Assets Powered by Rsbuild, Rspeedy supports using static assets, including images, fonts, audios and videos. :::tip What is Static Assets Static assets are files that are part of a Lynx application and do not change, even when the application is being used. Examples of static assets include images, fonts, medias, stylesheets, and JavaScript files. These assets are typically stored on a web server or CDN, and delivered to the users when the Lynx application is accessed. Because they do not change, static assets can be cached by the App, which helps to improve the performance of the Lynx application. ::: ## Import Assets You can directly import static assets in JavaScript: ```jsx // Import the logo.png image in the static directory import logo from './static/logo.png'; function App() { return ; // Can be directly used in ReactLynx } ``` The result of the import will be a URL string that represent the static asset. And the asset will be emitted to the output folder. You can also use static assets in CSS: ```css .logo { background-image: url('../static/logo.png'); } ``` ### URL Prefix The URL returned after importing a asset will automatically include the path prefix: - In development, using [`dev.assetPrefix`] to set the path prefix. - In production, using [`output.assetPrefix`] to set the path prefix. For example, you can set `output.assetPrefix` to `https://example.com`: ```js import logo from './static/logo.png'; console.log(logo); // "https://example.com/assets/logo.6c12aba3.png" ``` ### Public Folder The `public` folder at the project root can be used to place some static assets. These assets will not be bundled by Rspeedy. - When you start the dev server, these assets will be served under the root path, `/`. - When you perform a production build, these assets will be copied to the output directory. In JavaScript code, you can splice the URL via `process.env.ASSET_PREFIX`: ```js const logoURL = `${process.env.ASSET_PREFIX}/logo.png`; ``` :::warning - Avoid importing files from the public folder into your source code, instead reference them by URL. - When referencing resources in the public folder via URL, please use absolute paths instead of relative paths. - During the production build, the files in public folder will be copied to the output folder (default is `dist`). Please be careful to avoid name conflicts with the output files. When files in the `public` folder have the same name as outputs, the outputs have higher priority and will overwrite the files with the same name in the `public` folder. ::: ### Type Declaration When you import static assets in TypeScript code, TypeScript may prompt that the module is missing a type definition: ``` TS2307: Cannot find module './static/logo.png' or its corresponding type declarations. ``` To fix this, you need to add a type declaration file for the static assets, please create a `src/rspeedy-env.d.ts` file, and add the corresponding type declaration. ```typescript title=src/rspeedy-env.d.ts /// ``` ## Inline Assets Inline static assets refer to the practice of including the content of a static asset directly in the JS output, instead of linking to an external file. This can improve the performance of a Lynx application by reducing the number of HTTP requests that Lynx has to make to load the application. However, static assets inlining also has some disadvantages, such as increasing the size of a single file, which may lead to slower loading. Therefore, in the actual scenario, it is necessary to decide whether to use static assets inlining according to the specific situation. ### Automatic Inlining Rspeedy will inline assets when the file size of is less than a threshold (the default is 2KiB). When inlined, the asset will be converted to a base64-encoded string and will no longer send a separate HTTP request. When the file size is greater than this threshold, it is loaded as a separate file with a separate HTTP request. The threshold can be modified with the [`output.dataUriLimit`] config. For example, set the threshold of images to 5000 bytes, and set media assets not to be inlined: ```ts title="lynx.config.ts" import { defineConfig } from '@lynx-js/rspeedy'; export default defineConfig({ output: { dataUriLimit: { image: 5000, media: 0, }, }, }); ``` ### Force Inlining You can force an asset to be inlined by adding the `inline` query when importing the asset, regardless of whether the asset's size is smaller than the size threshold. ```js import img from './foo.png?inline'; console.log(img); // "data:image/png;base64,iVBORw0KGgo..." ``` In the above example, the `foo.png` image will always be inlined, regardless of whether the size of the image is larger than the threshold. ### Force No Inlining When you want to always treat some assets as separate files, no matter how small the asset is, you can add the `url` query to force the asset not to be inlined. ```js import img from '. /foo.png?url'; console.log(img); // "/static/foo.fe0bb4d0.png" ``` In the above example, the `foo.png` image will always be loaded as a separate file, even if the size of the image is smaller than the threshold. ## Extend Asset Types If the built-in asset types in Rsbuild cannot meet your requirements, you can: - Use the [`source.assetsInclude`] configuration option to specify additional file types to be treated as static assets. - Modify the built-in Rspack configuration and extend the asset types you need using [`tools.rspack`]. For example, if you want to treat `*.pdf` files as assets and directly output them to the dist directory, you can add the following configuration: ```ts title="lynx.config.ts" import { defineConfig } from '@lynx-js/rspeedy'; // planA: source.assetsInclude export default defineConfig({ source: { assetsInclude: /\.pdf$/, }, }); // planB: tools.rspack export default defineConfig({ tools: { rspack(config, { addRules }) { addRules([ { test: /\.pdf$/, // converts asset to a separate file and exports the URL address. type: 'asset/resource', }, ]); return config; }, }, }); ``` After adding the above configuration, you can import `*.pdf` files in your code, for example: ```js import myFile from './static/myFile.pdf'; console.log(myFile); // "/static/myFile.6c12aba3.pdf" ``` For more information about asset modules, please refer to [Rspack - Asset modules](https://rspack.dev/guide/features/asset-module). [`dev.assetPrefix`]: /api/rspeedy/rspeedy.dev.assetprefix.md [`output.assetPrefix`]: /api/rspeedy/rspeedy.output.assetprefix.md [`output.dataUriLimit`]: /api/rspeedy/rspeedy.output.dataurilimit.md [`tools.rspack`]: /api/rspeedy/rspeedy.tools.rspack.md [`source.assetsInclude`]: /api/rspeedy/rspeedy.source.assetsinclude.md --- # Source: https://lynxjs.org/help/blog.md # Writing Blog Posts The Lynx website hosts a blog to share updates, tutorials, and announcements. ## Location All blog posts are located in `docs/en/blog/`. ## Creating a New Post 1. Create a new `.mdx` file in `docs/en/blog/`. The filename will be part of the URL. 2. Add the necessary frontmatter. ```yaml --- title: My New Blog Post date: 2024-01-01 author: Your Name description: A short summary of the post. --- ``` 3. Write your content using standard Markdown and MDX components. ## Blog Components We provide specialized components for blog listings and author avatars. ### `` Renders the list of blog posts automatically. ```tsx import { BlogList } from '@lynx'; ; ``` [Lynx 3.5: Main Thread Script, React Compiler, HarmonyOS ImprovementsNovember 10, 2025 ![](https://github.com/loongliu.png)Leron LiuPerformance Lead @ Lynx![](https://github.com/huxpro.png)Xuan HuangArchitect @ Lynx![](https://github.com/lynx-family.png)The Lynx Teamlynxjs.org](/next/blog/lynx-3-5) ### `` Renders avatars for blog authors. You can add new authors in `src/components/blog-avatar/authors.json`. ```tsx import { BlogAvatar } from '@lynx'; ; ``` ## Blog Index The blog index is automatically generated. Ensure your `date` field is correct so posts are ordered chronologically. ## Images Place images in the `public/` directory or relative to the blog post if configured. --- # Source: https://lynxjs.org/rspeedy/build-profiling.md # Build Profiling Performing a performance analysis can help you identify performance bottlenecks in your project, allowing for targeted optimization. ## Using Rsdoctor Rsdoctor is a build analyser that can visually display the compilation time of each loaders and plugins. Please refer to [Use Rsdoctor](/rspeedy/use-rsdoctor.md) for more information. ## Node.js Profiling When Rspeedy executes a build, you can use Node.js profiling to analyze the JavaScript execution, which helps to identify performance bottlenecks. For example, to perform the [CPU profiling](https://nodejs.org/docs/v20.17.0/api/cli.html#--cpu-prof) analysis, run the following command in the root directory of your project: ```bash #dev node --cpu-prof ./node_modules/@lynx-js/rspeedy/bin/rspeedy.js dev # build node --cpu-prof ./node_modules/@lynx-js/rspeedy/bin/rspeedy.js build ``` The above commands will generate a `*.cpuprofile` file. We can use [speedscope](https://github.com/jlfwong/speedscope) to visualize this file: ```bash # Install speedscope npm install -g speedscope # View cpuprofile content # Replace the name with the local file name speedscope CPU.date.000000.00000.0.001.cpuprofile ``` ## Rspack profiling Rspeedy supports the use of the `RSPACK_PROFILE` environment variable for Rspack build performance profiling. ```bash # dev RSPACK_PROFILE=ALL rspeedy dev # build RSPACK_PROFILE=ALL rspeedy build ``` This command will generate a `rspack-profile-${timestamp}` folder in the dist folder, and it will contain `logging.json`, `trace.json` and `jscpuprofile.json` files: - `trace.json`: The time spent on each phase of the Rust side is recorded at a granular level using tracing and can be viewed using [ui.perfetto.dev](https://ui.perfetto.dev/). - `jscpuprofile.json`: The time spent at each stage on the JavaScript side is recorded at a granular level using [Node.js inspector](https://nodejs.org/dist/latest-v18.x/docs/api/inspector.html) and can be viewed using [speedscope.app](https://www.speedscope.app/). - `logging.json`: Includes some logging information that keeps a coarse-grained record of how long each phase of the build took. (Not supported in development environment yet) > For more information about Rspack build performance analysis usage, please refer to [Rspack - Profiling](https://web-infra-dev.github.io/rspack-dev-guide/profiling/intro.html#profiling). --- # Source: https://lynxjs.org/rspeedy/cli.md # CLI Rspeedy comes with a lightweight CLI that includes commands such as `dev` and `build`. ## Using the global Rspeedy version You can invoke Rspeedy using `npx rspeedy`, but it's more convenient to also install it globally so that it's always available in your shell `PATH`: ```bash # Install the Rspeedy globally npm install --global @lynx-js/rspeedy ``` :::info What if the globally installed Rspeedy binary is the wrong version? Just like [Rush](https://rushstack.io/), Rspeedy implements a "version selector" feature that will automatically discover your local `node_modules` folder and invoke `./node_modules/.bin/rspeedy`, ensuring that the correct version is used. ::: ## Using Node.js TypeScript support If the version of Node.js you are using supports TypeScript: 1. Node.js >= v23.6 2. Node.js >= v22.6 with [--experimental-strip-types](https://nodejs.org/api/cli.html#--experimental-strip-types) 3. Node.js >= v22.7 with [--experimental-transform-types](https://nodejs.org/api/cli.html#--experimental-transform-types) you can use the built-in TS transformation of Node.js. ```json title="package.json" { "build": "NODE_OPTIONS=--experimental-transform-types rspeedy build" } ``` See [Node.js - TypeScript](https://nodejs.org/api/typescript.html) for more details. ## rspeedy -h To view all available CLI commands, run the following command in the project directory: ```bash rspeedy -h ``` The output is shown below: ```text ➜ rspeedy --help Usage: rspeedy [options] Options: -V, --version output the version number --unmanaged Force to use the unmanaged version of Rspeedy, instead of the locally installed. -h, --help display help for command Commands: build [options] Build the project in production mode dev [options] Run the dev server and watch for source file changes while serving. inspect [options] View the Rsbuild config and Rspack config of the project. preview [options] Preview the production build outputs locally. help [command] display help for command ``` ## rspeedy dev The `rspeedy dev` command is used to start a local dev server and compile the source code for development. ```text ➜ rspeedy dev --help Usage: rspeedy dev [options] Run the dev server and watch for source file changes while serving. Options: --base specify the base path of the server --environment specify the name of environment to build -c --config specify the configuration file, can be a relative or absolute path --env-mode specify the env mode to load the .env.[mode] file --no-env disable loading `.env` files" -m --mode specify the build mode, can be `development`, `production` or `none` -h, --help display help for command ``` The dev server will restart automatically when the content of the configuration file is modified. ## rspeedy build The `rspeedy build` command will build the outputs for production in the `dist/` directory by default. ```text ➜ rspeedy build --help Usage: rspeedy build [options] Build the project in production mode Options: --environment specify the name of environment to build --watch Enable watch mode to automatically rebuild on file changes -c --config specify the configuration file, can be a relative or absolute path --env-mode specify the env mode to load the .env.[mode] file --no-env disable loading `.env` files" -m --mode specify the build mode, can be `development`, `production` or `none` -h, --help display help for command ``` ## rspeedy preview The `rspeedy preview` command is used to preview the production build outputs locally. Note that you need to execute the `rspeedy build` command beforehand to generate the build outputs. ```text ➜ rspeedy preview --help Usage: rspeedy preview [options] Preview the production build outputs locally. Options: --base specify the base path of the server -c --config specify the configuration file, can be a relative or absolute path --env-mode specify the env mode to load the .env.[mode] file --no-env disable loading `.env` files" -m --mode specify the build mode, can be `development`, `production` or `none` -h, --help display help for command ``` :::tip The preview command is only used for local preview. Do not use it for production servers, as it is not designed for that. ::: ## rspeedy inspect The `rspeedy inspect` command is used to view the Rspeedy config and Rspack config of the project. ```text ➜ rspeedy inspect --help Usage: rspeedy inspect [options] View the Rsbuild config and Rspack config of the project. Options: --output specify inspect content output path --verbose show full function definitions in output -c --config specify the configuration file, can be a relative or absolute path --env-mode specify the env mode to load the .env.[mode] file --no-env disable loading `.env` files" -m --mode specify the build mode, can be `development`, `production` or `none` -h, --help display help for command ``` When you run the command `rspeedy inspect` in the project root directory, the following files will be generated in the `dist/.rspeedy` directory of the project: - `rspeedy.config.js`: Represents the Rspeedy configuration used during the build. - `rsbuild.config.mjs`: Represents the Rsbuild configuration used during the build. - `rspack.config.lynx.mjs`: Represents the Rspack configuration used during the build. ```text ➜ rspeedy inspect Inspect config succeed, open following files to view the content: - Rspeedy Config: /project/dist/.rsbuild/rspeedy.config.mjs - Rspack Config (lynx): /project/dist/.rsbuild/rspack.config.lynx.mjs Inspect Rspeedy config succeed, open following files to view the content: - Rspeedy: /Users/colin/rspeedy/examples/react/dist/rspeedy-rspack/.rsbuild/rspeedy.config.js ``` ### Specifying Mode By default, the inspect command outputs the configuration for the development mode. You can add the `--mode production` option to output the configuration for the production mode: ```bash rspeedy inspect --mode production ``` ### Verbose content By default, the inspect command omits the content of functions in the configuration object. You can add the `--verbose` option to output the complete content of functions: ```bash rspeedy inspect --verbose ``` --- # Source: https://lynxjs.org/react/code-splitting.md # Code Splitting > Rspack supports code splitting, which allows splitting the code into other chunks. You have the full control about size and number of generated assets, which allow you to gain performance improvements in loading time. > > [Rspack - Code Splitting](https://rspack.dev/guide/optimization/code-splitting) ## Lazy-loading components Usually, you import components with the static import declaration: ```jsx import LazyComponent from './LazyComponent.jsx'; export function App() { return ( ); } ``` To defer loading this component’s code until it’s rendered for the first time, replace this import with: ```diff - import LazyComponent from './LazyComponent.jsx' + import { lazy } from '@lynx-js/react' + const LazyComponent = lazy(() => import('./LazyComponent.jsx')) ``` This code relies on [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import), which is supported by Rspack. Using this pattern requires that the lazy component you are importing was exported as the default export. Now that your component’s code loads on demand, you also need to specify what should be displayed while it is loading. You can do this by wrapping the lazy component or any of its parents into a `` boundary: :::info The split components will only start downloading when they are rendered. ::: ```jsx title="src/App.tsx" import { Suspense, lazy } from '@lynx-js/react'; const LazyComponent = lazy(() => import('./LazyComponent.jsx')); export function App() { return ( Loading...
}> ); } ``` ### Load lazy component when needed In this example, the code for `LazyComponent` won’t be loaded until you attempt to render it. If `LazyComponent` hasn’t loaded yet, a "Loading..." will be shown in its place. For example: ```jsx title="src/App.tsx" import { Suspense, lazy, useState } from '@lynx-js/react'; const LazyComponent = lazy(() => import('./LazyComponent.jsx')); export function App() { const [shouldDisplay, setShouldDisplay] = useState(false); const handleClick = () => { setShouldDisplay(true); }; return ( Load Component {shouldDisplay && ( Loading...
}> )} ); } ``` :::warning Differences from the Web In Lynx, CSS is scoped to each [Bundle](/api/lynx-native-api/template-bundle.md). Since lazy-loaded components generate their own Bundles (see output structure at [Output Files](/rspeedy/output.md)), you shouldn’t expect them to behave like on the Web. Global CSS defined in the main Bundle will not affect lazy-loaded components, and vice versa. ::: ### Error handling #### Use ErrorBoundary If loading is completed, lazy-loaded components are essentially also a React component, so the error handling practices in React are still applicable. Checkout [React - Catching rendering errors with an error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) for details. ## Lazy-loading standalone project You may also lazy-load modules that being built in a standalone Rspeedy project. ### Glossary of Terms - Producer (Remote): An application that exposes modules to be consumed by other Lynx applications. - Consumer (Host): An application that consumes modules from other Producers. ### Create a standalone Producer project Create a standalone project using [`create-rspeedy`](https://npmjs.com/create-rspeedy): ```bash pnpm create rspeedy@latest ``` Then add [`experimental_isLazyBundle`] to the options of `pluginReactLynx` in the `lynx.config.js`: ```js import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; import { defineConfig } from '@lynx-js/rspeedy'; export default defineConfig({ source: { entry: './src/index.tsx', }, plugins: [ pluginReactLynx({ experimental_isLazyBundle: true, }), ], }); ``` Finally, change the `index.tsx` to export the `App`. ```js title="src/index.tsx" import { App } from './App.jsx'; export default App; ``` ### Modify the Consumer project To load the Producer project, add an import to `@lynx-js/react/experimental/lazy/import` at the beginning of the entry. ```jsx title="src/index.tsx" import '@lynx-js/react/experimental/lazy/import'; import { root } from '@lynx-js/react'; import { App } from './App.jsx'; root.render(); ``` This would provide essential APIs that the Producer needs. Then, the Producer could be loaded using [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import). ```jsx title="src/App.tsx" import { Suspense, lazy } from '@lynx-js/react'; const LazyComponent = lazy( () => import('https://:/path/to/lynx.bundle', { with: { type: 'component' }, }), ); export function App() { return ( Loading...
}> ); } ``` ### Developing Producer project It is recommended to create a separated Consumer in the Producer project. ```jsx title="src/Consumer.tsx" import { Suspense, lazy, root } from '@lynx-js/react'; // You may use static import if you want const App = lazy(() => import('./App.jsx')); root.render( , ); ``` Then, create a separated `lynx.config.consumer.js`: ```js title="lynx.config.consumer.js" import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; import { defineConfig } from '@lynx-js/rspeedy'; export default defineConfig({ source: { entry: './src/Consumer.tsx', }, plugins: [pluginReactLynx()], }); ``` Use `npx rspeedy dev --config lynx.config.consumer.js` to start developing the producer project. [`experimental_isLazyBundle`]: /api/rspeedy/react-rsbuild-plugin.pluginreactlynxoptions.experimental_islazybundle.md --- # Source: https://lynxjs.org/guide/compatibility.md # Compatibility This article explains how to ensure version compatibility between [Bundle] and [Lynx Engine], and how to handle challenges that come with Lynx Engine version evolution. ## Build from Source A simple way to ensure compatibility is to **always build the Bundle with the Host application from source**. - Bundle can fully utilize all features of the current Lynx Engine version - Compatibility can be fully verified during development, what you see is what you get ## Multi-version Compatibility However, in a complex project, the relationship between Bundle and Lynx Engine is not one-to-one: - A Bundle might run in applications with different Lynx Engine versions - An application can run multiple Bundles maintained by different teams In this case, you need to set the [`engineVersion`] to ensure compatibility. :::info Engine Version When the Bundle's [`engineVersion`] is greater than the Lynx Engine version, it will not be able to run. ::: For example: a Bundle with [`engineVersion`] 3.3 can run on Lynx Engine 3.3 and later versions, but cannot run on 3.2. {` graph TB subgraph Bundle["🎯 Bundle"] B10["Engine Version 3.3"] end subgraph Engine["⚙️ Lynx Engine"] E12["Version 3.5"] E11["Version 3.4"] E10["Version 3.3"] E09["Version 3.2"] end B10 -.->|❌ Not Supported| E09 B10 ==>|✅ Can Run| E10 B10 ==>|✅ Can Run| E11 B10 ==>|✅ Can Run| E12 %% Node styles style E12 fill:#2b5a83,stroke:#4a90e2,stroke-width:3px,rx:10px style E11 fill:#2b5a83,stroke:#4a90e2,stroke-width:3px,rx:10px style E10 fill:#2b5a83,stroke:#4a90e2,stroke-width:3px,rx:10px style E09 fill:#2b5a83,stroke:#4a90e2,stroke-width:2px,rx:10px,stroke-dasharray:5,5 style B10 fill:#2d5a1e,stroke:#7ed321,stroke-width:3px,rx:10px %% Subgraph styles style Bundle fill:transparent,stroke:#7ed321,stroke-width:2px,rx:10px style Engine fill:transparent,stroke:#4a90e2,stroke-width:2px,rx:10px %% Default styles classDef default fill:#23272f,color:#ccc,font-family:system-ui %% Connection line label styles linkStyle default stroke-width:2px `} When a Bundle needs to run on multiple Lynx Engine versions, its [`engineVersion`] must be lower than all Lynx Engine versions. When running multiple Bundles on a single Lynx Engine version, each Bundle can set different [`engineVersion`]s, but none can be greater than the Lynx Engine version. ### Version Incompatibility Handling If you try to run a Bundle on a lower version of the Lynx Engine, a Fatal level error with code [10204](/api/errors/error-code.md#subcode-10204) will occur, and the rendering process will stop. This mechanism prevents potential runtime issues caused by version incompatibility. ### Configuring Engine Version The [`engineVersion`] is a string containing two version numbers, and you can specify it in your configuration file: ```js title="lynx.config.js" import { defineConfig } from '@lynx-js/rspeedy'; import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; export default defineConfig({ plugins: [ pluginReactLynx({ engineVersion: '3.2', }), ], }); ``` ## Upgrading Lynx Engine As Lynx Engine evolves, new features are added and some features may be deprecated. Their compatibility is also managed by [`engineVersion`]. ### New Features Some new features **_will not_** affect existing Bundles, but if [`engineVersion`] is lower than the version where they were introduced, runtime detection is needed, for example: ```js // Detect if `lynx.newlyAddedMethod` can be called if (lynx.newlyAddedMethod) { lynx.newlyAddedMethod(); } ``` While some new features cannot run on lower versions of the Lynx Engine at all, so they will only be enabled when [`engineVersion`] is greater than or equal to the corresponding version. ### Deprecated Features Some features may be deprecated during iteration, and their behavior may change when a higher [`engineVersion`] is set. - If only the Lynx Engine version is upgraded without upgrading the Bundle's [`engineVersion`], there will be no compatibility issues - If both Lynx Engine and Bundle's [`engineVersion`] are upgraded, you need to read the CHANGELOG to ensure there are no unexpected behavior changes ## API Compatibility Lynx provides comprehensive compatibility information for each API, built-in component, and CSS property. We offer two paired components to help you understand platform support: ### APISummary The `` component provides a quick, high-level overview of an API's availability across platforms. It shows a summary status (e.g., "Widely available") and badges for supported platforms. Clicking on this summary card will automatically jump to the detailed compatibility table. ### APITable The `` component displays detailed, version-specific support information for each platform. It breaks down support by OS (Android, iOS) and Web, including specific version numbers where applicable. ### Interactive Explorer Use the interactive explorer below to search and discover compatibility information using both components: - **CSS Properties**: Enter paths like `css/properties/gap` - **Built-in Elements**: Enter paths like `elements/view` to see element compatibility - **Nested APIs**: Use dot notation to access nested identifiers, e.g., `css/properties/align-self.supported_in_flex_layout` [Bundle]: /guide/spec.md#app-bundle-aka-template-bundle [Lynx Engine]: /guide/spec.md#engine [`engineVersion`]: /api/rspeedy/react-rsbuild-plugin.pluginreactlynxoptions.targetsdkversion.md --- # Source: https://lynxjs.org/help/components.md # MDX Components Reference This page serves as a reference for the custom components available in the Lynx documentation. You can import these from `@lynx`. ## Callout & Alerts Used to highlight important information. You can use standard Markdown syntax `:::type` for callouts. ```markdown :::info This is an info callout. ::: :::warning This is a warning callout. ::: :::tip This is a tip callout. ::: :::danger This is a danger callout. ::: ``` :::info This is an info callout. ::: :::warning This is a warning callout. ::: :::tip This is a tip callout. ::: :::danger This is a danger callout. ::: ## Badges ### Platform Badges Indicate platform support. ```tsx ```
### Status Badges Indicate API or feature status. ```tsx ```
### Runtime Badges Indicate which thread the script runs on. ```tsx ```
### Version Badge Indicates the Lynx version a feature was introduced. ```tsx 2.5.1 ```
2.5.1
### Generic Badges Standard Rspress badge. ```tsx ```
## Layout & Containers ### Platform Tabs Organize content by platform. ```tsx iOS Content Android Content ``` iOS Content Android Content ### Columns Split content into columns. Pass `titles` prop for column headers. ```tsx
Content for the left column.
Content for the right column.
```
Content for the left column.
Content for the right column.
### Responsive Dual Column A layout that switches to single column on smaller screens. Use `FlexItem` to control width. ```tsx
Left Content (min 300px)
Right Content (min 300px)
```
Left Content (min 300px)
Right Content (min 300px)
### Browser Container Wraps content in a browser-like window frame. ```tsx
Browser Content
```
Browser Content
### CodeFold Collapsible code block, optionally with an image. ````tsx ```ts console.log('Hidden code'); ``` ```` ```ts console.log('Hidden code'); ``` ## Media & Embeds ### YouTube ```tsx ``` ### Video List Display a list of videos with titles. ```tsx ``` ### Mermaid Diagrams ```tsx graph TD; A-->B; A-->C; B-->D; C-->D; ``` graph TD; A-->B; A-->C; B-->D; C-->D; ## Complex Components ### Blog & Social See [Writing Blog Posts](/help/blog.md) for details on `` and ``. ```tsx ``` ### Interactive Example See [Managing Interactive Examples](/help/example.md) for details on ``. ```tsx ``` ### API Tables See [Documenting APIs](/help/api.md) for details on `` and ``. ```tsx ``` ## Documentation Utilities ### Edit This Renders "Edit source" and "Edit in Cloud IDE" links. ```tsx ``` ### Version Table Renders a table of Lynx versions. ```tsx ``` --- # Source: https://lynxjs.org/api/css/properties/css-variable.md # Custom properties (`--*`): CSS variables ## Introduction CSS variables, are defined with a specific syntax (e.g., `--main-color: black;`) and their values are accessed using the`var()`function (e.g., `color: var(--main-color);`). Custom properties store a value in one place and allow it to be referenced in multiple other places throughout the stylesheet, promoting reusability and maintainability. ## Examples **This is an example below: css** **Entry:** `src/css_variable_theme` **Bundle:** `dist/css_variable_theme.lynx.bundle` | Web: `dist/css_variable_theme.web.bundle` ```tsx {23-43} import { root } from "@lynx-js/react"; import { useState } from "react"; import "./index.scss"; export default function App() { const [isDark, setIsDark] = useState(false); const [useJS, setUseJS] = useState(false); const [showError, setShowError] = useState(false); const themeClass = isDark ? "theme-dark" : "theme-light"; const toggleTheme = () => { if (useJS) { setShowError(true); setTimeout(() => setShowError(false), 3000); return; } setIsDark(prev => !prev); }; const toggleThemeByJS = () => { setUseJS(true); const rootElement = lynx.getElementById("root"); const newTheme = isDark ? "light" : "dark"; if (rootElement) { if (isDark) { rootElement.setProperty({ "--bg-primary": "#ffffff", "--bg-secondary": "#f5f5f5", "--text-primary": "#1a1a1a", "--text-secondary": "#666666", "--shadow": "rgba(0, 0, 0, 0.1)", }); } else { rootElement.setProperty({ "--bg-primary": "#2d2d2d", "--bg-secondary": "#1a1a1a", "--text-primary": "#ffffff", "--text-secondary": "#cccccc", "--shadow": "rgba(0, 0, 0, 0.3)", }); } setIsDark(prev => !prev); } }; return ( {isDark ? "🌙" : "☀️"} {isDark ? "Dark Mode" : "Light Mode"} Tap to switch theme by className {isDark ? "🌙" : "☀️"} {isDark ? "Dark Mode" : "Light Mode"} Tap to switch theme through JS Card Sample 1 This is a demo card showing theme switching effects. Card Sample 2 This is a demo card showing theme switching effects. Card Sample 3 This is a demo card showing theme switching effects. Card Sample 4 This is a demo card showing theme switching effects. {showError && ( Cannot change variables through the class after modifying them in JS! )} ); } root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` ## Syntax ```css /* Declare css variables */ --somekeyword: left; --somecolor: #0000ff; /* Reference css variables */ background: var(--somecolor); ``` ## Basic Usage ### Declaration CSS Variable is a property whose name starts with two hyphens (`-`), such as `--foo`, which can be referenced with `var()` after it is defined. ```css :root { --main-bg-color: yellow; } .two { --main-height: 200px; color: white; background-color: black; width: 100%; height: 100%; } ``` You can delcare CSS variables in `style` attribute as well{/* enable hints */}. ```tsx ``` :::info CSS Variables can be defined in the `:root` selector to take effect globally, or in a separate selector to take effect on the applied element and its child elements. ::: ### How To Reference CSS variables You use CSS variable by referencing the property in a `var()` function in place of a standard property value ```css .three { /* --main-bg-color: blue; */ color: white; background-color: var(--main-bg-color); width: 50%; border: 1px blue solid; } ``` You can use them in `style` attributes as well{/* enable hints */}: ```tsx ``` And a CSS variable is able to be a value of another: ```css .nested-variables { --first-var: blue; /* Nested reference */ --nested-reference: var(--first-var); /* [!code highlight] */ } ``` #### Default Values When a CSS variable cannot find a defined CSS variable value, a preset default value can be used: ```css .two { width: var(--view-width, 100px); } ``` :::info The part of the `var()` function after the first comma is returned as a whole and used as an alternate value for `var()`. ::: #### CSS Variable With Calc expressions In the CSS Variable declaration, the property value cannot be directly mathematically operated, and needs to use the `calc()` function, similar to: ```css .four { background-color: var(--main-bg-color); width: 25%; height: calc(var(--main-height) - 100px); } ``` #### CSS Variable Scope Like ordinary properties, the inheritance and priority of CSS variables also follow the CSS cascading rules. If no CSS variable is defined on an element, the value of that variable is inherited from its parent element. Look up according to the cascading relationship. Finally, the root element is found, which is the variable defined by the :root selector used in the previous example. Therefore, the scope of a variable is the valid scope of the selector it is in. :::info Since CSS Variable is defined in the selector, the scope is the same as that of the selector. When the selector is applied to an element, the CSS variable on the selector will also be applied to the element. ::: ```html ``` ```css :root { --main-bg-color: yellow; } .one { color: white; width: 100%; height: 100%; } .two { --main-bg-color: red; --main-height: 200px; color: white; background-color: black; width: 100%; height: 100%; } .three { --main-bg-color: blue; color: white; background-color: var(--main-bg-color); width: 50%; border: 1px blue solid; } .four { background-color: var(--main-bg-color); width: 25%; height: calc(var(--main-height) - 100px); } ``` For the above example, the values of the `var(--main-bg-color)` variable are: - For elements with `class="three"`: blue; - For elements with `class="four"`: red; ### Modifying the Value of CSS Variables #### Modifying CSS Variables via JavaScript API You can modify the value of `css-variable` by using the API on the JS side: Get an element node through the [`lynx.getElementById().setProperty`](/api/lynx-api/lynx/lynx-get-element-by-id.md) method, and modify the value of `css-var` on the node: ```javascript // Modify a css variable at a time lynx.getElementById('test').setProperty('--main-height', '300px'); // Batch modify css variables lynx.getElementById('test').setProperty({ '--main-height1': '300px', '--main-height2': '400px', }); ``` :::warning `setProperty` method's params must be `Object` or `String`. ::: #### Modifying the Selector that Declares CSS Variables In a selector, you can declare the value of CSS variables. By switching the selector applied to the corresponding ancestor node, you can modify the corresponding value of the CSS variables. ```css .a { --main-bg-color: red; } .b { --main-bg-color: blue; } .child { background-color: var(--main-bg-color); width: 25%; } ``` ```jsx ``` In the example above, by toggling the class 'a' or 'b', you can achieve the effect of modifying the corresponding variable --main-bg-color. ## Compatibility **Compatibility Table** **Query:** `css.properties.custom-property` **MDN Reference:** [https://developer.mozilla.org/en-US/docs/Web/CSS/--](https://developer.mozilla.org/en-US/docs/Web/CSS/--) **Platform Support** | Platform | Version Added | Notes | |----------|---------------|-------| | Android | 1.0 | - | | iOS | 1.0 | - | | HarmonyOS | 3.4 | - | | Clay Android | 1.0 | - | | Clay macOS | 1.0 | - | | Clay Windows | 1.0 | - | | Web | ✅ Yes | - | --- # Source: https://lynxjs.org/guide/custom-native-component.md # Custom Element If the built-in elements do not meet your requirements, you can extend Lynx's capabilities by creating custom native elements. This section will guide you through creating and registering custom elements on Android, iOS and HarmonyOS platforms. :::info Prerequisites ✅ Completed [Quick Start](/guide/start/quick-start.md) ✅ Completed [Lynx Integration](/guide/start/integrate-with-existing-apps.md) ✅ Familiar with [element Basics](/guide/ui/elements-components.md) ::: ## Building your Native Code ## Use your Native Element Once you have completed the development of a custom element, you can use it just like a built-in element. Below is a simple example of using an `` element: **This is an example below: native-element** **Bundle:** `dist/main.lynx.bundle` ```tsx {33-39} import { useState } from "@lynx-js/react"; import * as Lynx from "@lynx-js/types"; import "./App.css"; export function App() { const [inputValue, setInputValue] = useState(""); const handleInput = (e: Lynx.BaseEvent<"input", { value: string }>) => { const currentValue = e.detail.value.trim(); setInputValue(currentValue); }; const requestFocus = () => { lynx .createSelectorQuery() .select("#input-id") .invoke({ method: "focus", params: {}, success: function(res) { console.log("lynx", "request focus success"); }, fail: function(res) { console.log("lynx", "request focus fail"); }, }) .exec(); }; return ( Card URL Go ); } ``` --- # Source: https://lynxjs.org/guide/styling/custom-theming.md # Theming Lynx supports a wide range of [CSS properties](/api/css/properties.md), enabling seamless integration with [CSS selectors](/api/css/selectors.md), [CSS variables](/api/css/properties/css-variable.md), and opt-in CSS inheritance. By defining and managing different theme variables, developers can easily switch between various color schemes, font styles, and other visual elements, ensuring an optimal visual experience and interaction for users. ## Using CSS Descendant Selectors to Switch Themes Similar to web development, using descendant selectors by toggling the class of a parent element can affect the styles of all its descendant nodes, thus enabling the switching of multiple theme styles. ### Defining CSS Themes First, multiple theme CSS styles need to be defined, with different themes having different properties such as colors and backgrounds. For example, we can define both light and dark theme styles, with the light mode defined using `.theme-light .content` and the dark mode defined using `.theme-dark .content`. ```css /* light theme */ .theme-light .content { color: black; background-color: white; } /* dark theme */ .theme-dark .content { color: white; background-color: black; } ``` ### Applying CSS Styles In the page, set the class of the ancestor node (can be defined in the [`page`](/api/elements/built-in/page.md#using-page-element-explicitly)) to `theme-dark` or `theme-light`, and set the class of the descendant nodes to `content`. In this way, the descendant nodes can be styled with `.theme-light .content` or `.theme-dark .content` styles. ```tsx function App() { return ( text ); } ``` ### Switching Theme Styles When the theme changes, switch the class of the ancestor node to `theme-dark` or `theme-light`, which will update the styles of the descendant nodes. In the Lynx development scenario, the front-end themes can be notified by the native client. For example, the native client can notify the front-end of theme changes by updating [globalProps](/api/lynx-api/lynx/lynx-global-props.md). The corresponding front-end implementation: ```tsx import { useMemo } from '@lynx-js/react'; import './App.css'; export function App() { const themeClass = useMemo( () => `theme-${lynx.__globalProps.appTheme}`, [lynx.__globalProps.appTheme], ); return ( //themeClass's value is 'theme-dark' or 'theme-light' ... Hello Theme ... ); } ``` ### Example **This is an example below: css** **Entry:** `src/descendant_selectors_theme` **Bundle:** `dist/descendant_selectors_theme.lynx.bundle` | Web: `dist/descendant_selectors_theme.web.bundle` ```tsx import { root } from "@lynx-js/react"; import { useState } from "react"; import "./index.scss"; export default function App() { const [isDark, setIsDark] = useState(false); const themeClass = isDark ? "theme-dark" : "theme-light"; const toggleTheme = () => { setIsDark(prev => !prev); }; return ( {isDark ? "🌙" : "☀️"} {isDark ? "Dark Mode" : "Light Mode"} Tap to switch theme Card Sample 1 This is a demo card showing theme switching effects. Card Sample 2 This is a demo card showing theme switching effects. Card Sample 3 This is a demo card showing theme switching effects. Card Sample 4 This is a demo card showing theme switching effects. ); } root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` ## Using CSS Variables to Switch Themes When using descendant selectors for theme switching, we need to predefine selectors for different theme styles, which lacks flexibility when dealing with multiple themes. Using [CSS Variable](/api/css/properties/css-variable.md) to define theme styles and achieve theme switching by directly modifying the variable values. ### Defining CSS Themes Similarly, we define the theme style variables that need to change and assign different values to the same variables. For example, under different themes, `color` and `background-color` need to change with the theme. Therefore, two CSS variables `--color` and `--bg` need to be defined. The descendant nodes can obtain the values of these variables in the stylesheet using `var(--color)` and `var(--bg)`. ```css .theme-light { --color: black; --bg: white; } .content { color: var(--color); background-color: var(--bg); } ``` ### Applying CSS Styles Note that CSS variables need to be mounted on the ancestor node (can be defined in the [`page`](/api/elements/built-in/page.md#using-page-element-explicitly)) so that their descendant nodes can use these variables in their respective stylesheets. The descendant nodes can apply the values of these variables in `.content` using the `var(--*)` syntax. ```tsx function App() { return ( text ); } ``` ### Switching Theme Styles #### Directly Changing CSS Variable Values with JS Use JS API ([`setProperty`](/api/css/properties/css-variable.md#modifying-css-variables-via-javascript-api)) to directly modify CSS variable values, allowing flexible batch updates of CSS variables. ```tsx import './App.css'; export function App() { const handleClick = () => { lynx.getElementById('root').setProperty({ '--color': 'white', '--bg': 'black', }); }; return ( Hello Variable ); } ``` #### Indirectly Changing Variable Values by Switching Classes Alternatively, you can indirectly modify variable values by switching classes on the ancestor node that define different [CSS variables](/api/css/properties/css-variable.md#modifying-the-selector-that-declares-css-variables), triggering style updates for all child nodes using these variables when theme switching is needed. For example, use `.theme-light` and `.theme-dark` to define CSS variable values for different themes: ```css .theme-light { --color: black; --bg: white; } .theme-dark { --color: white; --bg: black; } .content { color: var(--color); background-color: var(--bg); } ``` Switching between `.theme-light` or `.theme-dark` on the ancestor node changes the values of `--color` and `--bg`, which updates the styles for corresponding `.content` elements. ```tsx import { useMemo } from '@lynx-js/react'; import './App.css'; export function App() { const themeClass = useMemo( () => `theme-${lynx.__globalProps.appTheme}`, [lynx.__globalProps.appTheme], ); return ( //themeClass's value is 'theme-dark' or 'theme-light' Hello Variable ); } ``` ### Example **This is an example below: css** **Entry:** `src/css_variable_theme` **Bundle:** `dist/css_variable_theme.lynx.bundle` | Web: `dist/css_variable_theme.web.bundle` ```tsx {23-43} import { root } from "@lynx-js/react"; import { useState } from "react"; import "./index.scss"; export default function App() { const [isDark, setIsDark] = useState(false); const [useJS, setUseJS] = useState(false); const [showError, setShowError] = useState(false); const themeClass = isDark ? "theme-dark" : "theme-light"; const toggleTheme = () => { if (useJS) { setShowError(true); setTimeout(() => setShowError(false), 3000); return; } setIsDark(prev => !prev); }; const toggleThemeByJS = () => { setUseJS(true); const rootElement = lynx.getElementById("root"); const newTheme = isDark ? "light" : "dark"; if (rootElement) { if (isDark) { rootElement.setProperty({ "--bg-primary": "#ffffff", "--bg-secondary": "#f5f5f5", "--text-primary": "#1a1a1a", "--text-secondary": "#666666", "--shadow": "rgba(0, 0, 0, 0.1)", }); } else { rootElement.setProperty({ "--bg-primary": "#2d2d2d", "--bg-secondary": "#1a1a1a", "--text-primary": "#ffffff", "--text-secondary": "#cccccc", "--shadow": "rgba(0, 0, 0, 0.3)", }); } setIsDark(prev => !prev); } }; return ( {isDark ? "🌙" : "☀️"} {isDark ? "Dark Mode" : "Light Mode"} Tap to switch theme by className {isDark ? "🌙" : "☀️"} {isDark ? "Dark Mode" : "Light Mode"} Tap to switch theme through JS Card Sample 1 This is a demo card showing theme switching effects. Card Sample 2 This is a demo card showing theme switching effects. Card Sample 3 This is a demo card showing theme switching effects. Card Sample 4 This is a demo card showing theme switching effects. {showError && ( Cannot change variables through the class after modifying them in JS! )} ); } root.render(); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` ## Leveraging CSS Inheritance As Needed In pages with complex styles, using CSS inheritance can simplify development. However, implementing inheritance logic adds complexity to the style processing flow and can introduce some performance overhead. To optimize performance, Lynx does not enable inheritance for ordinary CSS properties by default, developers must enable it as needed. CSS custom properties (also known as CSS variables) are inherited by descendant nodes by default. ### Inheritance of CSS Custom Properties [CSS Custom Properties](/api/css/properties/css-variable.md) (CSS variables, e.g., `--primary-color`) adhere to Web standards and are inherited by descendant nodes by default without additional configuration. Developers can define CSS custom properties in ancestor nodes to achieve dynamic style management. ### Inheritance of Regular (Non-Custom) Properties To enable inheritance, configure[`enableCSSInheritance`](/api/rspeedy/react-rsbuild-plugin.pluginreactlynxoptions.enablecssinheritance.md). #### Default-Inheritable Properties After enabling `enableCSSInheritance`, these properties can be inherited: [`direction`](/api/css/properties/direction.md),[`color`](/api/css/properties/color.md),[`font-family`](/api/css/properties/font-family.md),[`font-size`](/api/css/properties/font-size.md),[`font-style`](/api/css/properties/font-style.md),[`font-weight`](/api/css/properties/font-weight.md),[`letter-spacing`](/api/css/properties/letter-spacing.md),[`line-height`](/api/css/properties/line-height.md),[`text-align`](/api/css/properties/text-align.md),[`text-decoration`](/api/css/properties/text-decoration.md),[`text-shadow`](/api/css/properties/text-shadow.md) Default inherited properties inherit behavior alignment with [🌐W3C definition](https://www.w3.org/TR/css-cascade-3/#inheriting) #### Custom-Inheritable Properties In addition to the default inheritable properties, you can configure the page with [`customCSSInheritanceList`](/api/rspeedy/react-rsbuild-plugin.pluginreactlynxoptions.customcssinheritancelist.md)to define custom inheritable CSS properties. When there are custom inheritance declarations, only the CSS properties listed in the `customCSSInheritanceList` will be inheritable. Example: ```json "customCSSInheritanceList":["font-size","flex-direction"] ``` #### Limitations of CSS Inheritance 1. Elements with `position: fixed` will always inherit properties only from the page. 2. The keyword "inherit" is not supported. 3. In addition to the default inheritable properties, only CSS properties with types enum or boolean support custom inheritance. --- # Source: https://lynxjs.org/help/dashboard.md # API Status Dashboard Guide :::tip This usage guide was generated with AI assistance. If you find any inaccuracies, please help us improve it by submitting a pull request. ::: This guide explains how to use the Lynx API Status Dashboard to explore API compatibility across different platforms. ![API Status Dashboard Overview](/api-status-help/api-status-main.png) *** ## 1. Select Platform At the top of the dashboard, you'll find the **Platform Selector** which allows you to select one or multiple platforms to view their specific API coverage. ### Native Platforms - **Android** - Mobile Android platform - **iOS** - Apple iOS platform - **Harmony** - HarmonyOS platform - **Web** - Web Lynx implementation Use the checkboxes to select multiple platforms simultaneously. The dashboard will update to show coverage statistics for the combined selection. ### Clay Platforms Click the **Clay** toggle button to reveal additional Clay platform options: ![Clay Platforms Expanded](/api-status-help/api-status-clay-platforms.png) Clay platforms include: - **Clay (Android)** - Clay running on Android - **Clay (iOS)** - Clay running on iOS - **Clay (macOS)** - Clay running on macOS - **Clay (Windows)** - Clay running on Windows *** ## 2. Search, Filter, and View APIs ### Search Box Use the search box to quickly find specific APIs by name or description. The search is case-insensitive and matches partial text. **Examples:** - Search `image` to find all image-related APIs - Search `scroll` to find scrolling functionality - Search `animation` to find animation APIs ### Category Filter The first dropdown allows you to filter APIs by category: - **All** - Show all categories - **ELEMENT** - Element-related APIs - **CSS** - CSS property support - **API** - JavaScript API methods ### State Filter The second dropdown filters APIs by their support status on the selected platform: - **All** - Show all APIs - **Supported** - Only show supported APIs - **Unsupported** - Only show unsupported APIs ### API List The API list displays all matching APIs in a two-column grid layout. Each API item shows: - **Category badge** (e.g., `ELEMENT`, `CSS`, `API`) - **API name** (e.g., `commonality`, `image.loop-count`) - **Color coding**: - 🟢 **Green background** - API is supported on all selected platforms - 🟡 **Yellow background** - API is partially supported (supported on some but not all selected platforms) - 🔴 **Red background** - API is not supported on any selected platform For partially supported APIs, a small indicator (e.g., "2/3") shows how many of the selected platforms support that feature. By default, only the first 100 results are shown for performance. Click **"Show All"** to display all matching results. ### API Detail Drawer Click on any API item to open the detailed compatibility drawer: ![API Detail Drawer](/api-status-help/api-status-drawer.png) The drawer shows a compatibility table with: - **Rows** - Each sub-API or property - **Columns** - All platforms (Android, iOS, HarmonyOS, macOS, Windows, Web) | Icon | Meaning | | -------------- | ---------------------------- | | ✓ with version | Supported since that version | | ✗ No | Not supported | | ? | Support status unknown | Click the **"View source"** link to see the raw compatibility data in the GitHub repository. *** ## 3. View Platform Coverage and Trends The bottom section shows platform statistics and historical trends: ![Coverage Card and Trend Chart](/api-status-help/api-status-coverage-trend.png) ### Coverage Card (Left) - **Percentage** - Overall API coverage (e.g., 87%) - **Fraction** - Exact count (e.g., 945 / 1,092) - **Progress bar** - Visual representation with platform-specific color ### Trend Chart (Right) - **X-axis** - Lynx versions (e.g., 2.14 → 3.4) - **Y-axis** - API coverage percentage - **Line** - Coverage progression over time This helps you understand how API support has improved across versions. ### Category Table The **Coverage** section provides a breakdown by API category: ![Category Table with Expanded View](/api-status-help/api-status-category-expanded.png) | Column | Description | | -------- | --------------------------------------- | | Category | API category name (e.g., Elements, CSS) | | Coverage | Percentage and count of supported APIs | | Missing | Number of unsupported APIs (if any) | **Highlight Modes:** - **Highlight Good** (Green mode) - Emphasizes high coverage categories - **Highlight Gap** (Red mode) - Emphasizes low coverage categories Click on any category row to expand it and see the individual APIs. Unsupported APIs are highlighted in red for easy identification. *** ## 4. Recently Added APIs The **Recently Added** section lists APIs that were recently added to Lynx, grouped by version. ![Recently Added APIs by Version](/api-status-help/api-status-recently-added.png) Each version group shows: - **Version number** (e.g., v3.5, v3.4, v2.18) - **API count** for the selected platform - **List of APIs** added in that version This is useful for tracking new features in each Lynx release. *** ## Tips 1. **Start with platform selection** - Choose your target platforms (one or more) first to see relevant coverage data. 2. **Use Colorblind Mode** - Toggle the **Colorblind Mode** switch in the sidebar footer to enable a high-contrast Blue/Orange theme for better accessibility. 3. **Use search for specific APIs** - If you know the API name, search is faster than scrolling. 4. **Check the drawer for details** - The compatibility table shows version-specific information. 5. **Monitor trends** - Use the trend chart to understand coverage improvements over time. 6. **Toggle Clay for desktop** - Enable Clay platforms if you're building cross-platform desktop apps. *** ## Need Help? If you have questions about API compatibility or need assistance: - Check the [API documentation](/api/index.md) - Contribute on [GitHub](https://github.com/lynx-family/lynx) --- # Source: https://lynxjs.org/react/data-fetching.md # Data Fetching Whether fetching static content from a remote server or interacting with a REST API, ReactLynx applications often need to retrieve data from external sources. For example, you might want to load user posts in a social media app or fetch the latest product listings in an e-commerce application. Lynx provides the [Fetch API](/api/lynx-api/global/fetch.md), enabling you to make network requests. You can refer to the [Networking](/guide/interaction/networking.md) chapter for more details. The Fetch API provided by Lynx can be used together with server state management libraries from the React ecosystem, such as [TanStack Query (React Query)](https://tanstack.com/query), to simplify data fetching and state management. It is important to note that Lynx's Fetch API has subtle differences compared to the [Web Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). You can check the [Fetch API Reference - Compatibility](/api/lynx-api/global/fetch.md#compatibility) section to learn more about these differences. As a result, you may need to adapt libraries from the React ecosystem to ensure compatibility. If you encounter any issues on Lynx Fetch API, you are welcome to submit feature requests or [contribute](https://github.com/lynx-family/lynx/blob/develop/CONTRIBUTING.md) to help Lynx better support the React ecosystem. ## Using TanStack Query TanStack Query is a popular server state management library in the React ecosystem, helping developers easily manage data fetching and caching. ### Installing Dependencies ### Example The following example application shows how to use TanStack Query with the Fetch API in ReactLynx to fetch, display, and delete user posts provided by the [JSONPlaceholder API](https://jsonplaceholder.typicode.com/). The application first uses the [`useQuery`](https://tanstack.com/query/v5/docs/framework/react/reference/useQuery) hook from TanStack Query to call `fetchPosts`, fetching and displaying the first 10 posts. When the user clicks the "Delete Post 1" button, it triggers an [Optimistic Update](https://tanstack.com/query/v4/docs/framework/react/guides/optimistic-updates) using the [`useMutation`](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) hook: the post with `id` 1 is immediately removed from the list, and the `deletePost` function calls the Fetch API to send a delete request. If the request fails, the state will roll back to its original state. **This is an example below: networking** **Entry:** `src/react-query` **Bundle:** `dist/react-query.lynx.bundle` ```tsx import { root } from "@lynx-js/react"; import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import "./index.scss"; interface Post { userId: number; id: number; title: string; body: string; } const queryClient = new QueryClient(); const fetchPosts = async (): Promise => { const response = await fetch("https://jsonplaceholder.typicode.com/posts"); if (!response.ok) { throw new Error("Failed to fetch posts"); } const data = await response.json(); return data.slice(0, 10); // Only show the first 10 posts }; const deletePost = async (postId: number) => { const response = await fetch( `https://jsonplaceholder.typicode.com/posts/${postId}`, { method: "DELETE", }, ); if (!response.ok) { throw new Error("Failed to delete post"); } return postId; }; const App = () => { const queryClient = useQueryClient(); // Fetch posts const { data: posts, isLoading, isError, error, } = useQuery({ queryKey: ["posts"], queryFn: fetchPosts, }); // Mutation to delete post optimistically const mutation = useMutation({ mutationFn: () => deletePost(1), onMutate: async () => { await queryClient.cancelQueries({ queryKey: ["posts"] }); // Snapshot current state const previousPosts = queryClient.getQueryData(["posts"]); // Optimistically remove post with ID 1 queryClient.setQueryData(["posts"], (oldPosts: Post[] | undefined) => { return oldPosts ? oldPosts.filter((post) => post.id !== 1) : []; }); // Return previous state to OnError for rolling back optimistic update return { previousPosts }; }, onError: (err, variables, context) => { // Rollback to previous state if (context?.previousPosts) { queryClient.setQueryData(["posts"], context.previousPosts); } }, }); const deleteFirstPost = () => { "background only"; mutation.mutate(); }; return ( {isLoading ? Loading... : isError ? ( {error?.message || "Error fetching posts"} ) : ( posts?.map((post) => ( {`${post.id} : ${post.title}`} )) )} {/* Button to trigger mutation */} Delete Post 1 ); }; root.render( , ); if (import.meta.webpackHot) { import.meta.webpackHot.accept(); } ``` --- # Source: https://lynxjs.org/guide/devtool.md # Lynx DevTool Lynx DevTool is a collection of performance and debugging tools for Lynx apps. You need to [integrate DevTool](/guide/start/integrate-lynx-devtool.md) into your Lynx pages, and then connect to the device via the [DevTool Desktop Application](#run-lynx-devtool-desktop-application) to debug the page.