From 60fc3fabb154c163e307ce5b32f6e647d6d0ba17 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Tue, 11 Nov 2025 12:21:16 +0800 Subject: [PATCH 01/62] chore: update .gitignore to include compile_commands.json for clangd --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2db28fdcc..c9c70b099 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ build*/ dev_*/ **/.cache/ +# For clangd +compile_commands.json + # CMake files CMakeFiles/ CMakeCache.txt From 69f2ddb204a9b2bd6cb2308b3755de75b82760c2 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Wed, 12 Nov 2025 09:12:26 +0800 Subject: [PATCH 02/62] fix: update image paths in test components to use correct directory structure --- test/image/1/index.jsx | 2 +- test/image/2/index.jsx | 2 +- test/image/3/index.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/image/1/index.jsx b/test/image/1/index.jsx index a36f875df..5afec4f25 100644 --- a/test/image/1/index.jsx +++ b/test/image/1/index.jsx @@ -6,7 +6,7 @@ const { width, height } = Dimensions.window function App () { return ( - + ) diff --git a/test/image/2/index.jsx b/test/image/2/index.jsx index e0120a155..3972f989d 100644 --- a/test/image/2/index.jsx +++ b/test/image/2/index.jsx @@ -52,7 +52,7 @@ function App () { onChange={e=> setOpacity(e.value)} /> Date: Fri, 14 Nov 2025 11:34:11 +0800 Subject: [PATCH 03/62] chore: update txiki subproject to latest commit to support fetch blob --- deps/txiki | 2 +- src/engine/engine.cpp | 4 +-- src/render/native/components/arc/arc_wrap.cpp | 2 +- .../components/calendar/calendar_wrap.cpp | 4 +-- .../native/components/chart/chart_wrap.cpp | 28 +++++++++---------- src/render/native/components/component.hpp | 6 ++-- .../dropdownlist/dropdownlist_wrap.cpp | 2 +- .../native/components/line/line_wrap.cpp | 4 +-- .../native/components/roller/roller_wrap.cpp | 2 +- .../native/components/slider/slider_wrap.cpp | 2 +- .../components/tabview/tabview_wrap.cpp | 2 +- src/render/native/core/style/style.cpp | 6 ++-- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/deps/txiki b/deps/txiki index 69fa6a055..e359e5ec5 160000 --- a/deps/txiki +++ b/deps/txiki @@ -1 +1 @@ -Subproject commit 69fa6a055cca4d6d8315fdeef35dcdd6bbd90d97 +Subproject commit e359e5ec5f5586a07f9c8f75d19625807a4d5e31 diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 0b848b6ec..d1108ae39 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -19,11 +19,11 @@ int main(int argc, char **argv) { CHECK_NOT_NULL(qrt); JSValue global_obj = JS_GetGlobalObject(qrt->ctx); - JSValue render_sym = JS_NewSymbol(qrt->ctx, "lvgljs", TRUE); + JSValue render_sym = JS_NewSymbol(qrt->ctx, "lvgljs", true); JSAtom render_atom = JS_ValueToAtom(qrt->ctx, render_sym); JSValue render = JS_NewObjectProto(qrt->ctx, JS_NULL); - CHECK_EQ(JS_DefinePropertyValue(qrt->ctx, global_obj, render_atom, render, JS_PROP_C_W_E), TRUE); + CHECK_EQ(JS_DefinePropertyValue(qrt->ctx, global_obj, render_atom, render, JS_PROP_C_W_E), true); NativeRenderInit(qrt->ctx, render); diff --git a/src/render/native/components/arc/arc_wrap.cpp b/src/render/native/components/arc/arc_wrap.cpp index 6d91866a0..753a0d3a8 100644 --- a/src/render/native/components/arc/arc_wrap.cpp +++ b/src/render/native/components/arc/arc_wrap.cpp @@ -21,7 +21,7 @@ WRAPPED_SCROLL_INTO_VIEW(Arc, "Arc") WRAPPED_JS_CLOSE_COMPONENT(Arc, "Arc") static JSValue NativeCompSetRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ArcClassID); int32_t min; int32_t max; diff --git a/src/render/native/components/calendar/calendar_wrap.cpp b/src/render/native/components/calendar/calendar_wrap.cpp index ed6e32950..0bb6dcddd 100644 --- a/src/render/native/components/calendar/calendar_wrap.cpp +++ b/src/render/native/components/calendar/calendar_wrap.cpp @@ -13,7 +13,7 @@ WRAPPED_SCROLL_INTO_VIEW(Calendar, "Calendar") WRAPPED_JS_CLOSE_COMPONENT(Calendar, "Calendar") static JSValue NativeCompSetHightLights(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0]) && JS_IsNumber(argv[1])) { + if (argc >= 1 && JS_IsArray(argv[0]) && JS_IsNumber(argv[1])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, CalendarClassID); int32_t len; @@ -30,7 +30,7 @@ static JSValue NativeCompSetHightLights(JSContext *ctx, JSValueConst this_val, i for (int i=0; i= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); int32_t len, i; @@ -46,7 +46,7 @@ static JSValue NativeCompSetLeftAxisLabels(JSContext *ctx, JSValueConst this_val }; static JSValue NativeCompSetRightAxisLabels(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); int32_t len, i; @@ -77,7 +77,7 @@ static JSValue NativeCompSetRightAxisLabels(JSContext *ctx, JSValueConst this_va }; static JSValue NativeCompSetTopAxisLabels(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); int32_t len, i; @@ -108,7 +108,7 @@ static JSValue NativeCompSetTopAxisLabels(JSContext *ctx, JSValueConst this_val, }; static JSValue NativeCompSetBottomAxisLabels(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); int32_t len, i; @@ -139,7 +139,7 @@ static JSValue NativeCompSetBottomAxisLabels(JSContext *ctx, JSValueConst this_v }; static JSValue NativeCompSetDivLine(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); int32_t hdiv, vdiv; @@ -295,7 +295,7 @@ static JSValue NativeCompSetBottomAxisOption(JSContext *ctx, JSValueConst this_v }; // static JSValue NativeCompSetBottomAxisData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { -// if (argc >= 1 && JS_IsArray(ctx, argv[0])) { +// if (argc >= 1 && JS_IsArray(argv[0])) { // COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); // int32_t len, i, data_item; @@ -319,7 +319,7 @@ static JSValue NativeCompSetBottomAxisOption(JSContext *ctx, JSValueConst this_v // }; // static JSValue NativeCompSetTopAxisData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { -// if (argc >= 1 && JS_IsArray(ctx, argv[0])) { +// if (argc >= 1 && JS_IsArray(argv[0])) { // COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); // int32_t len, i, data_item; @@ -343,7 +343,7 @@ static JSValue NativeCompSetBottomAxisOption(JSContext *ctx, JSValueConst this_v // }; static JSValue NativeCompSetLeftAxisData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); std::vector data; @@ -392,7 +392,7 @@ static JSValue NativeCompSetLeftAxisData(JSContext *ctx, JSValueConst this_val, }; static JSValue NativeCompSetRightAxisData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); std::vector data; @@ -441,7 +441,7 @@ static JSValue NativeCompSetRightAxisData(JSContext *ctx, JSValueConst this_val, }; static JSValue NativeCompSetScatterData (JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); std::vector data; @@ -490,7 +490,7 @@ static JSValue NativeCompSetScatterData (JSContext *ctx, JSValueConst this_val, }; static JSValue NativeCompSetLeftAxisRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); JSValue min_value = JS_GetPropertyUint32(ctx, argv[0], 0); @@ -512,7 +512,7 @@ static JSValue NativeCompSetLeftAxisRange(JSContext *ctx, JSValueConst this_val, }; static JSValue NativeCompSetRightAxisRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); JSValue min_value = JS_GetPropertyUint32(ctx, argv[0], 0); @@ -534,7 +534,7 @@ static JSValue NativeCompSetRightAxisRange(JSContext *ctx, JSValueConst this_val }; static JSValue NativeCompSetTopAxisRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); JSValue min_value = JS_GetPropertyUint32(ctx, argv[0], 0); @@ -556,7 +556,7 @@ static JSValue NativeCompSetTopAxisRange(JSContext *ctx, JSValueConst this_val, }; static JSValue NativeCompSetBottomAxisRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); JSValue min_value = JS_GetPropertyUint32(ctx, argv[0], 0); diff --git a/src/render/native/components/component.hpp b/src/render/native/components/component.hpp index 2fb86339a..71f0d474e 100644 --- a/src/render/native/components/component.hpp +++ b/src/render/native/components/component.hpp @@ -148,7 +148,7 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); #define WRAPPED_JS_SETSTYLE(COMPONENT,COMPONENT_NAME) \ static JSValue NativeCompSetStyle(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) { \ - if (argc >= 2 && JS_IsObject(argv[0]) && JS_IsArray(ctx, argv[1]) && JS_IsNumber(argv[2]) && JS_IsNumber(argv[3]) && JS_IsBool(argv[4])) { \ + if (argc >= 2 && JS_IsObject(argv[0]) && JS_IsArray(argv[1]) && JS_IsNumber(argv[2]) && JS_IsNumber(argv[3]) && JS_IsBool(argv[4])) { \ int len; \ std::vector keys; \ std::string key; \ @@ -194,7 +194,7 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); #define WRAPPED_JS_Align(COMPONENT,COMPONENT_NAME) \ static JSValue NativeCompSetAlign(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \ - if (argc >= 1 && JS_IsNumber(argv[0]) && JS_IsArray(ctx, argv[1])) { \ + if (argc >= 1 && JS_IsNumber(argv[0]) && JS_IsArray(argv[1])) { \ COMP_REF* s = (COMP_REF*)JS_GetOpaque(this_val, COMPONENT##ClassID); \ int32_t x; \ int32_t y; \ @@ -217,7 +217,7 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); #define WRAPPED_JS_Align_To(COMPONENT,COMPONENT_NAME) \ static JSValue NativeCompSetAlignTo(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \ - if (argc >= 1 && JS_IsNumber(argv[0]) && JS_IsArray(ctx, argv[1]) && JS_IsObject(argv[2])) { \ + if (argc >= 1 && JS_IsNumber(argv[0]) && JS_IsArray(argv[1]) && JS_IsObject(argv[2])) { \ COMP_REF* s = (COMP_REF*)JS_GetOpaque(this_val, COMPONENT##ClassID); \ int32_t x; \ int32_t y; \ diff --git a/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp b/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp index af9af40e3..234b5c90f 100644 --- a/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp +++ b/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp @@ -13,7 +13,7 @@ WRAPPED_SCROLL_INTO_VIEW(Dropdownlist, "Dropdownlist") WRAPPED_JS_CLOSE_COMPONENT(Dropdownlist, "Dropdownlist") static JSValue NativeCompSetItems(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0]) && JS_IsNumber(argv[1])) { + if (argc >= 1 && JS_IsArray(argv[0]) && JS_IsNumber(argv[1])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, DropdownlistClassID); std::vector items; diff --git a/src/render/native/components/line/line_wrap.cpp b/src/render/native/components/line/line_wrap.cpp index 1711a6ce4..351237e91 100644 --- a/src/render/native/components/line/line_wrap.cpp +++ b/src/render/native/components/line/line_wrap.cpp @@ -14,7 +14,7 @@ WRAPPED_SCROLL_INTO_VIEW(Line, "Line") WRAPPED_JS_CLOSE_COMPONENT(Line, "Line") static JSValue NativeCompSetPoints(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0]) && JS_IsNumber(argv[1])) { + if (argc >= 1 && JS_IsArray(argv[0]) && JS_IsNumber(argv[1])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, LineClassID); int32_t len; @@ -29,7 +29,7 @@ static JSValue NativeCompSetPoints(JSContext *ctx, JSValueConst this_val, int ar for (int i=0; i= 1 && JS_IsArray(ctx, argv[0]) && JS_IsNumber(argv[1]) && JS_IsBool(argv[2])) { + if (argc >= 1 && JS_IsArray(argv[0]) && JS_IsNumber(argv[1]) && JS_IsBool(argv[2])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, RollerClassID); std::vector items; diff --git a/src/render/native/components/slider/slider_wrap.cpp b/src/render/native/components/slider/slider_wrap.cpp index 9f70864e9..bad611324 100644 --- a/src/render/native/components/slider/slider_wrap.cpp +++ b/src/render/native/components/slider/slider_wrap.cpp @@ -14,7 +14,7 @@ WRAPPED_SCROLL_INTO_VIEW(Slider, "Slider") WRAPPED_JS_CLOSE_COMPONENT(Slider, "Slider") static JSValue NativeCompSetRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsArray(ctx, argv[0])) { + if (argc >= 1 && JS_IsArray(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, SliderClassID); int32_t min; int32_t max; diff --git a/src/render/native/components/tabview/tabview_wrap.cpp b/src/render/native/components/tabview/tabview_wrap.cpp index d6a743725..221dd50ec 100644 --- a/src/render/native/components/tabview/tabview_wrap.cpp +++ b/src/render/native/components/tabview/tabview_wrap.cpp @@ -17,7 +17,7 @@ WRAPPED_SCROLL_INTO_VIEW(TabView, "TabView") WRAPPED_JS_CLOSE_COMPONENT(TabView, "TabView") // static JSValue NativeCompSetTabs(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { -// if (argc >= 1 && JS_IsArray(ctx, argv[0])) { +// if (argc >= 1 && JS_IsArray(argv[0])) { // COMP_REF* ref = (COMP_REF*)JS_GetOpaque3(this_val); // COMP_REF* ref_content; diff --git a/src/render/native/core/style/style.cpp b/src/render/native/core/style/style.cpp index b4836d10c..faa3fa6e1 100644 --- a/src/render/native/core/style/style.cpp +++ b/src/render/native/core/style/style.cpp @@ -702,7 +702,7 @@ static void CompSetPosition (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, }; static void CompGridColumnRow (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - if (JS_IsArray(ctx, obj)) { + if (JS_IsArray(obj)) { BasicComponent* instance = static_cast(lv_obj_get_user_data(comp)); const lv_coord_t* old_ptr1 = instance->grid_column_desc; const lv_coord_t* old_ptr2 = instance->grid_row_desc; @@ -754,7 +754,7 @@ static void CompGridColumnRow (lv_obj_t* comp, lv_style_t* style, JSContext* ctx }; static void CompSetGridChild (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - if (JS_IsArray(ctx, obj)) { + if (JS_IsArray(obj)) { JSValue JSValue1 = JS_GetPropertyUint32(ctx, obj, 0); JSValue JSValue2 = JS_GetPropertyUint32(ctx, obj, 1); JSValue JSValue3 = JS_GetPropertyUint32(ctx, obj, 2); @@ -786,7 +786,7 @@ static void CompSetGridChild (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, }; static void CompsetGridAlign (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - if (JS_IsArray(ctx, obj)) { + if (JS_IsArray(obj)) { JSValue JSValue1 = JS_GetPropertyUint32(ctx, obj, 0); JSValue JSValue2 = JS_GetPropertyUint32(ctx, obj, 1); From 36cffeecb94f63717aa0bc2427788ea23f828f69 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Fri, 14 Nov 2025 11:49:37 +0800 Subject: [PATCH 04/62] refactor: replace getBinary functions with fetchBinary utility for GIF and Image components --- src/render/react/components/GIF/comp.ts | 16 +++------------- src/render/react/components/Image/comp.ts | 18 ++++-------------- src/render/react/core/style/post.ts | 22 +++++----------------- src/render/react/utils/helpers.ts | 5 +++++ 4 files changed, 17 insertions(+), 44 deletions(-) diff --git a/src/render/react/components/GIF/comp.ts b/src/render/react/components/GIF/comp.ts index 36da7314f..5851b5328 100644 --- a/src/render/react/components/GIF/comp.ts +++ b/src/render/react/components/GIF/comp.ts @@ -1,5 +1,5 @@ import { BUILT_IN_SYMBOL } from "../../core/style/symbol"; -import { isValidUrl } from "../../utils/helpers"; +import { isValidUrl, fetchBinary } from "../../utils/helpers"; import { CommonComponentApi, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, @@ -11,16 +11,6 @@ import { const bridge = globalThis[Symbol.for('lvgljs')]; const NativeGIF = bridge.NativeRender.NativeComponents.GIF; -async function getGIFBinary(url) { - const resp = await fetch(url, { - headers: { - "Content-Type": "application/octet-stream", - }, - }); - const GIFBuffer = await resp.arrayBuffer(); - return GIFBuffer; -} - export type GIFProps = CommonProps & { src: string; } @@ -49,8 +39,8 @@ function setGIFProps(comp, newProps: GIFProps, oldProps: GIFProps) { console.log("setGIF error", e); }); } else { - getGIFBinary(url) - .then((buffer) => comp.setGIFBinary(Buffer.from(buffer).buffer)) + fetchBinary(url) + .then((buffer) => comp.setGIFBinary(buffer)) .catch(console.warn); } } diff --git a/src/render/react/components/Image/comp.ts b/src/render/react/components/Image/comp.ts index 6e183e395..9ddd23e83 100644 --- a/src/render/react/components/Image/comp.ts +++ b/src/render/react/components/Image/comp.ts @@ -1,5 +1,5 @@ import { BUILT_IN_SYMBOL } from "../../core/style/symbol"; -import { isValidUrl } from "../../utils/helpers"; +import { isValidUrl, fetchBinary } from "../../utils/helpers"; import { CommonComponentApi, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, @@ -12,16 +12,6 @@ import path from 'tjs:path'; const bridge = globalThis[Symbol.for('lvgljs')]; const NativeImage = bridge.NativeRender.NativeComponents.Image; -async function getImageBinary(url) { - const resp = await fetch(url, { - headers: { - "Content-Type": "application/octet-stream", - }, - }); - const imageBuffer = await resp.arrayBuffer(); - return imageBuffer; -} - export type ImageProps = CommonProps & { /** GIF loading resource, support network url, local path, buildtin symbol */ src: string; @@ -43,7 +33,7 @@ function setImageProps(comp, newProps: ImageProps, oldProps: ImageProps) { if (!path.isAbsolute(url)) { url = path.resolve(url); } - tjs.readFile(url, { encoding: "binary" }) + tjs.readFile(url) .then((data) => { comp.setImageBinary(data.buffer); }) @@ -51,8 +41,8 @@ function setImageProps(comp, newProps: ImageProps, oldProps: ImageProps) { console.log("setImage error", e); }); } else { - getImageBinary(url) - .then((buffer) => comp.setImageBinary(Buffer.from(buffer).buffer)) + fetchBinary(url) + .then((buffer) => comp.setImageBinary(buffer)) .catch(console.warn); } } diff --git a/src/render/react/core/style/post.ts b/src/render/react/core/style/post.ts index 03fda2cca..00987d858 100644 --- a/src/render/react/core/style/post.ts +++ b/src/render/react/core/style/post.ts @@ -1,13 +1,7 @@ import { StyleProps } from "./index"; -import { isValidUrl } from "../../utils/helpers"; +import { isValidUrl, fetchBinary } from "../../utils/helpers"; import { BUILT_IN_SYMBOL } from "./symbol"; -async function getImageBinary(url) { - const resp = await fetch(url, {}); - const imageBuffer = await resp.arrayBuffer(); - return imageBuffer; -} - export function PostProcessStyle({ comp, styleSheet, styleType }: { comp: any; styleSheet: StyleProps; styleType: any }) { if (styleSheet["background-image"] !== void 0) { let url = styleSheet["background-image"]; @@ -31,11 +25,8 @@ export function PostProcessStyle({ comp, styleSheet, styleType }: { comp: any; s console.log("setBackground error", e); }); } else { - getImageBinary(url) - .then( - (buffer) => comp.setBackgroundImage(Buffer.from(buffer).buffer), - styleType, - ) + fetchBinary(url) + .then((buffer) => comp.setBackgroundImage(buffer, styleType)) .catch(console.warn); } } @@ -62,11 +53,8 @@ export function PostProcessStyle({ comp, styleSheet, styleType }: { comp: any; s console.log("setArcImage error", e); }); } else { - getImageBinary(url) - .then( - (buffer) => comp.setArcImage(Buffer.from(buffer).buffer), - styleType, - ) + fetchBinary(url) + .then((buffer) => comp.setArcImage(buffer, styleType)) .catch(console.warn); } } diff --git a/src/render/react/utils/helpers.ts b/src/render/react/utils/helpers.ts index bd4e32d50..d0eb1c50c 100644 --- a/src/render/react/utils/helpers.ts +++ b/src/render/react/utils/helpers.ts @@ -13,3 +13,8 @@ export function isValidUrl(str: string) { return false; } } + +export async function fetchBinary(url: string): Promise { + const resp = await fetch(url); + return await (await resp.blob()).arrayBuffer(); +} From 1b8da286d04e54daf7930276604f36c51ed1e961 Mon Sep 17 00:00:00 2001 From: huiqing <37806648+sunnyswag@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:33:07 +0800 Subject: [PATCH 05/62] Update .gitignore Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c9c70b099..2fc2e53b1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ dev_*/ **/.cache/ # For clangd -compile_commands.json +compile_commands.json # CMake files CMakeFiles/ From ec284e1f43dbb2e23dba6433902a7396bf2cb885 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Fri, 14 Nov 2025 15:07:50 +0800 Subject: [PATCH 06/62] fix: enhance fetchBinary function to handle HTTP errors and improve error messaging --- src/render/react/utils/helpers.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/render/react/utils/helpers.ts b/src/render/react/utils/helpers.ts index d0eb1c50c..441f874c0 100644 --- a/src/render/react/utils/helpers.ts +++ b/src/render/react/utils/helpers.ts @@ -16,5 +16,11 @@ export function isValidUrl(str: string) { export async function fetchBinary(url: string): Promise { const resp = await fetch(url); - return await (await resp.blob()).arrayBuffer(); + + if (!resp.ok) { + throw new Error(`Failed to fetch ${url}: ${resp.status} ${resp.statusText}`); + } + + const blob = await resp.blob(); + return await blob.arrayBuffer(); } From e07f1bed92344a18acdc0b6675a66033e45abe3a Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 12 Jan 2026 16:09:48 +0800 Subject: [PATCH 07/62] build: add support for building static library and refactor main entry point - Introduced option to build lvgljs as a static library. - Refactored engine initialization and execution into separate functions. - Updated CMakeLists.txt and Makefile to accommodate new build configurations. - Added main.cpp as the entry point for executable builds. --- CMakeLists.txt | 12 +++++++++++- Makefile | 13 +++++++++---- src/engine/engine.cpp | 4 +++- src/engine/engine.hpp | 3 +++ src/engine/main.cpp | 7 +++++++ 5 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 src/engine/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d6b911f0..17ee2b5c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,9 +7,11 @@ set(LV_CONF_PATH ${CMAKE_CURRENT_SOURCE_DIR}/deps/lv_conf.h CACHE INTERNAL "LV_C set(BUILD_NATIVE OFF CACHE BOOL "Build wasm3 with native support") +option(BUILD_STATIC_LIB "Build as static library (.a) instead of executable" OFF) + find_path(LVGL_PATH lvgl.h PATHS ${CMAKE_CURRENT_SOURCE_DIR}/deps PATH_SUFFIXES lvgl) -add_executable(lvgljs +set(LVGLJS_SOURCES src/engine/engine.cpp src/render/native/core/style/style.cpp src/render/native/core/style/font/font.cpp @@ -74,6 +76,14 @@ add_executable(lvgljs src/render/native/bootstrap/render_bootstrap.cpp ) +if(BUILD_STATIC_LIB) + add_library(lvgljs STATIC ${LVGLJS_SOURCES}) + message(STATUS "Building lvgljs as static library (.a)") +else() + add_executable(lvgljs ${LVGLJS_SOURCES} src/engine/main.cpp) + message(STATUS "Building lvgljs as executable") +endif() + if(${CMAKE_BUILD_TYPE} MATCHES Simulator) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -Wall -g -ggdb -std=c++14") set(BUILD_WITH_MIMALLOC OFF) # TODO: SDL and mimalloc don't play well together diff --git a/Makefile b/Makefile index e82382d4f..75f9a7fb6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ BUILD_SIM=build +BUILD_LIB=build_lib -.PHONY: setup simulator demo clean +.PHONY: setup simulator lib demo clean setup: git submodule update --recursive --init @@ -8,10 +9,14 @@ setup: simulator: @mkdir -p $(BUILD_SIM) - cmake -B "$(BUILD_SIM)" -DCMAKE_BUILD_TYPE=Simulator + cmake -B "$(BUILD_SIM)" -DCMAKE_BUILD_TYPE=Simulator -DBUILD_STATIC_LIB=OFF cmake --build $(BUILD_SIM) -j -# Set default project argument to 'widgets' if no project is provided +lib: + @mkdir -p $(BUILD_LIB) + cmake -B "$(BUILD_LIB)" -DCMAKE_BUILD_TYPE=Simulator -DBUILD_STATIC_LIB=ON + cmake --build $(BUILD_LIB) -j + demo: simulator @PROJECT=$${PROJECT:-widgets}; \ echo "Running demo with project: $$PROJECT"; \ @@ -19,4 +24,4 @@ demo: simulator ./${BUILD_SIM}/lvgljs run demo/$$PROJECT/index.js clean: - rm -rf $(BUILD_SIM) \ No newline at end of file + rm -rf $(BUILD_SIM) $(BUILD_LIB) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index d1108ae39..860b75db1 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -12,7 +12,7 @@ static void timer_cb(uv_timer_t *handle) { lv_timer_handler(); } -int main(int argc, char **argv) { +void EngineInit(int argc, char **argv) { TJS_Initialize(argc, argv); qrt = TJS_NewRuntime(); @@ -42,7 +42,9 @@ int main(int argc, char **argv) { } else if (uv_timer_start(&handle, timer_cb, 30, 30) != 0) { printf("uv_timer_start failed\n"); } +} +int EngineRun() { int exit_code = TJS_Run(qrt); TJS_FreeRuntime(qrt); diff --git a/src/engine/engine.hpp b/src/engine/engine.hpp index e750ab971..33b7c4382 100644 --- a/src/engine/engine.hpp +++ b/src/engine/engine.hpp @@ -4,4 +4,7 @@ extern "C" { #include "private.h" }; +void EngineInit(int argc, char **argv); +int EngineRun(); TJSRuntime* GetRuntime(); + diff --git a/src/engine/main.cpp b/src/engine/main.cpp new file mode 100644 index 000000000..2b73f9aa7 --- /dev/null +++ b/src/engine/main.cpp @@ -0,0 +1,7 @@ +#include "engine.hpp" + +int main(int argc, char **argv) { + EngineInit(argc, argv); + return EngineRun(); +} + From 78c35609f90a1d2babd10959aa0bb9dc12be74b3 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 13 Jan 2026 11:07:21 +0800 Subject: [PATCH 08/62] build: add display resolution configuration to CMake and update device initialization --- CMakeLists.txt | 8 ++++++++ src/engine/hal/device/device.cpp | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17ee2b5c5..add19fe00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,9 @@ set(BUILD_NATIVE OFF CACHE BOOL "Build wasm3 with native support") option(BUILD_STATIC_LIB "Build as static library (.a) instead of executable" OFF) +set(DISP_HOR_RES 1024 CACHE STRING "Display horizontal resolution") +set(DISP_VER_RES 600 CACHE STRING "Display vertical resolution") + find_path(LVGL_PATH lvgl.h PATHS ${CMAKE_CURRENT_SOURCE_DIR}/deps PATH_SUFFIXES lvgl) set(LVGLJS_SOURCES @@ -118,6 +121,11 @@ target_include_directories(lvgljs PUBLIC src/render/native/core ) +target_compile_definitions(lvgljs PRIVATE + DISP_HOR_RES=${DISP_HOR_RES} + DISP_VER_RES=${DISP_VER_RES} +) + target_link_libraries(lvgljs PUBLIC tjs lvgl diff --git a/src/engine/hal/device/device.cpp b/src/engine/hal/device/device.cpp index fd61193a3..382cf85db 100644 --- a/src/engine/hal/device/device.cpp +++ b/src/engine/hal/device/device.cpp @@ -1,6 +1,6 @@ #include "./device.hpp" -#define DISP_BUF_SIZE (1024 * 600) +#define DISP_BUF_SIZE (DISP_HOR_RES * DISP_VER_RES) void hal_init () { /*LittlevGL init*/ @@ -21,8 +21,8 @@ void hal_init () { lv_disp_drv_init(&disp_drv); disp_drv.draw_buf = &disp_buf; disp_drv.flush_cb = fbdev_flush; - disp_drv.hor_res = 1024; - disp_drv.ver_res = 600; + disp_drv.hor_res = DISP_HOR_RES; + disp_drv.ver_res = DISP_VER_RES; lv_disp_drv_register(&disp_drv); /* Linux input device init */ @@ -35,6 +35,7 @@ void hal_init () { indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = evdev_read; //lv_gesture_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev) lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv); + (void)my_indev; }; uint32_t custom_tick_get(void) From a92a9746c787eed80fd2d07c25a90fd0c5a637ef Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 13 Jan 2026 12:14:38 +0800 Subject: [PATCH 09/62] build: enhance CMake configuration with LVGLJS_CONF_DIR and display resolution options --- CMakeLists.txt | 7 ++++- doc/build/build-device.md | 61 +++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index add19fe00..4caffcbda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,12 @@ cmake_minimum_required(VERSION 3.16) project(lvgljs LANGUAGES C CXX) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(LV_CONF_PATH ${CMAKE_CURRENT_SOURCE_DIR}/deps/lv_conf.h CACHE INTERNAL "LV_CONF_PATH") + +if(NOT DEFINED LVGLJS_CONF_DIR) + set(LVGLJS_CONF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps CACHE INTERNAL "LVGLJS_CONF_DIR") +endif() + +set(LV_CONF_PATH ${LVGLJS_CONF_DIR}/lv_conf.h CACHE INTERNAL "LV_CONF_PATH") set(BUILD_NATIVE OFF CACHE BOOL "Build wasm3 with native support") diff --git a/doc/build/build-device.md b/doc/build/build-device.md index f16b74db6..b0475a036 100644 --- a/doc/build/build-device.md +++ b/doc/build/build-device.md @@ -5,9 +5,9 @@ This is not too different from building for a regular Linux target, besides that you will probably need to cross-compile and won't want to use the sdl2 simulator. When building for a target device, the [*device HAL*](../../src/engine/hal/device) is selected.\ -Currently it is not possible to configure the properties of the device and -it will by default use a screen size of 1024x600 together with the framebuffer device. +By default, it will use a screen size of 1024x600 together with the framebuffer device. +You can configure the device properties when building lvgljs as a static library or executable. You will most likely need to tweak the screen size for your device, and can also opt to use a different LVGL display like DRM or [wayland](https://github.com/lvgl/lv_drivers/blob/master/wayland/README.md). @@ -21,11 +21,62 @@ Take a look at the [txiki readme](https://github.com/saghul/txiki.js#building) f - you provide your own libffi library, since building it together with txiki doesn't work when cross-compiling at this moment.\ Do this by passing `-DUSE_EXTERNAL_FFI=ON` to cmake. -You can now cross-compile like normal. -For instance, if you're using Yocto, you source your SDK environment and then do +## Configuration Options + +When integrating lvgljs into your project, you can configure the following options: + +### Build as Static Library + +To build lvgljs as a static library instead of an executable: + +```cmake +set(BUILD_STATIC_LIB ON CACHE BOOL "Build lvgljs as static library") +``` + +### Display Resolution + +Configure the display resolution for your target device: + +```cmake +set(DISP_HOR_RES 480 CACHE STRING "Display horizontal resolution") +set(DISP_VER_RES 480 CACHE STRING "Display vertical resolution") +``` + +### Configuration Directory + +Specify a custom directory for LVGL configuration files: + +```cmake +set(LVGLJS_CONF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/config CACHE INTERNAL "LVGLJS_CONF_DIR") +``` + +This will set `LV_CONF_PATH` to `${LVGLJS_CONF_DIR}/lv_conf.h`. + +### Example: External Project Integration + +In your project's `CMakeLists.txt`, you can configure lvgljs like this: + +```cmake +set(BUILD_STATIC_LIB ON CACHE BOOL "Build lvgljs as static library") +set(DISP_HOR_RES 480 CACHE STRING "Display horizontal resolution") +set(DISP_VER_RES 480 CACHE STRING "Display vertical resolution") +set(LVGLJS_CONF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/config CACHE INTERNAL "LVGLJS_CONF_DIR") + +add_subdirectory(lv_binding_js) + +add_executable(my_app main.cpp) +target_link_libraries(my_app lvgljs) +``` + +Or via command line: ```sh -cmake -B build -DUSE_EXTERNAL_FFI=ON +cmake -B build \ + -DUSE_EXTERNAL_FFI=ON \ + -DBUILD_STATIC_LIB=ON \ + -DDISP_HOR_RES=480 \ + -DDISP_VER_RES=480 \ + -DLVGLJS_CONF_DIR=${CMAKE_CURRENT_SOURCE_DIR}/config cmake --build build ``` From 04a6d886e9ea6b7560693fb4c1b5d316eea699ed Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 13 Jan 2026 21:08:24 +0800 Subject: [PATCH 10/62] feat: implement LVGL Group focus navigation support - Add GroupManager singleton to manage lv_group_t instances - Modify BasicComponent appendChild/removeChild to handle group membership - Add unregisterContainer call in BasicComponent destructor - Remove auto lv_group_add_obj from all component constructors (21 files) - Add setInGroup method to View component for JS binding - Add DefaultGroup constant in React layer - Add group prop support in View React component - Add onFocusedStyle support in CommonComponentApi - Add test case in test/group/1/index.jsx --- CMakeLists.txt | 1 + src/render/native/components/arc/arc.cpp | 1 - .../native/components/button/button.cpp | 2 - .../native/components/calendar/calendar.cpp | 2 - src/render/native/components/chart/chart.cpp | 2 - .../native/components/checkbox/checkbox.cpp | 1 - .../components/dropdownlist/dropdownlist.cpp | 1 - src/render/native/components/gif/gif.cpp | 1 - src/render/native/components/image/image.cpp | 1 - .../native/components/keyboard/keyboard.cpp | 1 - src/render/native/components/line/line.cpp | 1 - src/render/native/components/list/list.cpp | 1 - src/render/native/components/mask/mask.cpp | 2 - .../components/progressbar/progressbar.cpp | 1 - .../native/components/roller/roller.cpp | 1 - .../native/components/slider/slider.cpp | 1 - .../native/components/switch/switch.cpp | 1 - .../native/components/tabview/tabview.cpp | 1 - src/render/native/components/text/text.cpp | 1 - .../native/components/textarea/textarea.cpp | 1 - src/render/native/components/view/view.cpp | 1 - .../native/components/view/view_wrap.cpp | 14 +++ .../native/components/window/window.cpp | 1 - src/render/native/core/basic/comp.cpp | 21 +++- .../native/core/group/group_manager.cpp | 55 +++++++++ .../native/core/group/group_manager.hpp | 31 +++++ src/render/react/components/View/comp.ts | 10 +- src/render/react/components/common/index.ts | 10 ++ src/render/react/core/group/index.ts | 2 + src/render/react/index.ts | 1 + test/group/1/index.jsx | 109 ++++++++++++++++++ 31 files changed, 249 insertions(+), 30 deletions(-) create mode 100644 src/render/native/core/group/group_manager.cpp create mode 100644 src/render/native/core/group/group_manager.hpp create mode 100644 src/render/react/core/group/index.ts create mode 100644 test/group/1/index.jsx diff --git a/CMakeLists.txt b/CMakeLists.txt index 4caffcbda..a72a97d32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ set(LVGLJS_SOURCES src/render/native/core/theme/theme.cpp src/render/native/core/dimensions/dimensions.cpp src/render/native/core/basic/comp.cpp + src/render/native/core/group/group_manager.cpp src/render/native/core/event/event.cpp src/render/native/core/img/png/lodepng.cpp src/render/native/core/img/png/png.cpp diff --git a/src/render/native/components/arc/arc.cpp b/src/render/native/components/arc/arc.cpp index 265c70caa..2bff9d317 100644 --- a/src/render/native/components/arc/arc.cpp +++ b/src/render/native/components/arc/arc.cpp @@ -6,7 +6,6 @@ Arc::Arc(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_arc_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/button/button.cpp b/src/render/native/components/button/button.cpp index b0ef1b97f..466433a9f 100644 --- a/src/render/native/components/button/button.cpp +++ b/src/render/native/components/button/button.cpp @@ -7,8 +7,6 @@ Button::Button(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_btn_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); - lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); diff --git a/src/render/native/components/calendar/calendar.cpp b/src/render/native/components/calendar/calendar.cpp index 8f9329d58..9e604cfe8 100644 --- a/src/render/native/components/calendar/calendar.cpp +++ b/src/render/native/components/calendar/calendar.cpp @@ -9,8 +9,6 @@ Calendar::Calendar(std::string uid, lv_obj_t* parent): BasicComponent(uid) { lv_calendar_header_dropdown_create(this->instance); lv_calendar_header_arrow_create(this->instance); - lv_group_add_obj(lv_group_get_default(), this->instance); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); diff --git a/src/render/native/components/chart/chart.cpp b/src/render/native/components/chart/chart.cpp index b6d7ea45c..28784f49a 100644 --- a/src/render/native/components/chart/chart.cpp +++ b/src/render/native/components/chart/chart.cpp @@ -6,8 +6,6 @@ Chart::Chart(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_chart_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); - lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); diff --git a/src/render/native/components/checkbox/checkbox.cpp b/src/render/native/components/checkbox/checkbox.cpp index 9d4439abc..03096a504 100644 --- a/src/render/native/components/checkbox/checkbox.cpp +++ b/src/render/native/components/checkbox/checkbox.cpp @@ -5,7 +5,6 @@ Checkbox::Checkbox(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->type = COMP_TYPE_CHECKBOX; this->uid = uid; this->instance = lv_checkbox_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); diff --git a/src/render/native/components/dropdownlist/dropdownlist.cpp b/src/render/native/components/dropdownlist/dropdownlist.cpp index b42b04d96..2c5e93d1d 100644 --- a/src/render/native/components/dropdownlist/dropdownlist.cpp +++ b/src/render/native/components/dropdownlist/dropdownlist.cpp @@ -6,7 +6,6 @@ Dropdownlist::Dropdownlist(std::string uid, lv_obj_t* parent): BasicComponent(ui this->uid = uid; this->instance = lv_dropdown_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/gif/gif.cpp b/src/render/native/components/gif/gif.cpp index d839f9e0c..ef6403b99 100644 --- a/src/render/native/components/gif/gif.cpp +++ b/src/render/native/components/gif/gif.cpp @@ -6,7 +6,6 @@ GIF::GIF(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_gif_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICKABLE); diff --git a/src/render/native/components/image/image.cpp b/src/render/native/components/image/image.cpp index b7b73bc78..3deee7d78 100644 --- a/src/render/native/components/image/image.cpp +++ b/src/render/native/components/image/image.cpp @@ -6,7 +6,6 @@ Image::Image(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_img_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICKABLE); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); diff --git a/src/render/native/components/keyboard/keyboard.cpp b/src/render/native/components/keyboard/keyboard.cpp index c1f7c94dc..bb5719ef1 100644 --- a/src/render/native/components/keyboard/keyboard.cpp +++ b/src/render/native/components/keyboard/keyboard.cpp @@ -5,7 +5,6 @@ Keyboard::Keyboard(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->type = COMP_TYPE_TEXTAREA; this->uid = uid; this->instance = lv_keyboard_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/line/line.cpp b/src/render/native/components/line/line.cpp index 27583ed2f..4b1e73ed0 100644 --- a/src/render/native/components/line/line.cpp +++ b/src/render/native/components/line/line.cpp @@ -6,7 +6,6 @@ Line::Line(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_line_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/list/list.cpp b/src/render/native/components/list/list.cpp index cb9964e6d..1ad9a7794 100644 --- a/src/render/native/components/list/list.cpp +++ b/src/render/native/components/list/list.cpp @@ -6,7 +6,6 @@ List::List(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_list_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); diff --git a/src/render/native/components/mask/mask.cpp b/src/render/native/components/mask/mask.cpp index cdc7d5f24..2cc6055de 100644 --- a/src/render/native/components/mask/mask.cpp +++ b/src/render/native/components/mask/mask.cpp @@ -7,8 +7,6 @@ Mask::Mask(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_obj_create(lv_layer_top()); - lv_group_add_obj(lv_group_get_default(), this->instance); - lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); diff --git a/src/render/native/components/progressbar/progressbar.cpp b/src/render/native/components/progressbar/progressbar.cpp index 3da5be5a8..1aabe418e 100644 --- a/src/render/native/components/progressbar/progressbar.cpp +++ b/src/render/native/components/progressbar/progressbar.cpp @@ -6,7 +6,6 @@ ProgressBar::ProgressBar(std::string uid, lv_obj_t* parent): BasicComponent(uid) this->uid = uid; this->instance = lv_bar_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/roller/roller.cpp b/src/render/native/components/roller/roller.cpp index 3bfe2c837..11da9b36f 100644 --- a/src/render/native/components/roller/roller.cpp +++ b/src/render/native/components/roller/roller.cpp @@ -5,7 +5,6 @@ Roller::Roller(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->type = COMP_TYPE_ROLLER; this->uid = uid; this->instance = lv_roller_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/slider/slider.cpp b/src/render/native/components/slider/slider.cpp index 976f404e6..9b47cf907 100644 --- a/src/render/native/components/slider/slider.cpp +++ b/src/render/native/components/slider/slider.cpp @@ -6,7 +6,6 @@ Slider::Slider(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_slider_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/switch/switch.cpp b/src/render/native/components/switch/switch.cpp index 920b7b4c2..9ddcc8e83 100644 --- a/src/render/native/components/switch/switch.cpp +++ b/src/render/native/components/switch/switch.cpp @@ -5,7 +5,6 @@ Switch::Switch(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->type = COMP_TYPE_SWITCH; this->uid = uid; this->instance = lv_switch_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/tabview/tabview.cpp b/src/render/native/components/tabview/tabview.cpp index 9fefd681d..bb9746cd2 100644 --- a/src/render/native/components/tabview/tabview.cpp +++ b/src/render/native/components/tabview/tabview.cpp @@ -6,7 +6,6 @@ TabView::TabView(std::string uid, uint32_t pos, uint32_t size, lv_obj_t* parent) this->uid = uid; this->instance = lv_tabview_create(parent != nullptr ? parent : GetWindowInstance(), pos, size); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/text/text.cpp b/src/render/native/components/text/text.cpp index 8cbf87286..0f479248e 100644 --- a/src/render/native/components/text/text.cpp +++ b/src/render/native/components/text/text.cpp @@ -6,7 +6,6 @@ Text::Text(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_label_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/textarea/textarea.cpp b/src/render/native/components/textarea/textarea.cpp index 4c05c3923..4091dd1f5 100644 --- a/src/render/native/components/textarea/textarea.cpp +++ b/src/render/native/components/textarea/textarea.cpp @@ -5,7 +5,6 @@ Textarea::Textarea(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->type = COMP_TYPE_TEXTAREA; this->uid = uid; this->instance = lv_textarea_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_set_user_data(this->instance, this); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/view/view.cpp b/src/render/native/components/view/view.cpp index 917475408..bbbbe8678 100644 --- a/src/render/native/components/view/view.cpp +++ b/src/render/native/components/view/view.cpp @@ -5,7 +5,6 @@ View::View(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->type = COMP_TYPE_VIEW; this->uid = uid; this->instance = lv_obj_create(parent != nullptr ? parent : GetWindowInstance()); - lv_group_add_obj(lv_group_get_default(), this->instance); lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); diff --git a/src/render/native/components/view/view_wrap.cpp b/src/render/native/components/view/view_wrap.cpp index bdba4931b..763186fd6 100644 --- a/src/render/native/components/view/view_wrap.cpp +++ b/src/render/native/components/view/view_wrap.cpp @@ -1,4 +1,5 @@ #include "view.hpp" +#include "native/core/group/group_manager.hpp" static JSClassID ViewClassID; @@ -16,6 +17,18 @@ WRAPPED_MOVE_TO_BACKGROUND(View, "View") WRAPPED_SCROLL_INTO_VIEW(View, "View") WRAPPED_JS_CLOSE_COMPONENT(View, "View") +static JSValue NativeCompSetInGroup(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + if (argc >= 1 && JS_IsBool(argv[0])) { + COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ViewClassID); + bool value = JS_ToBool(ctx, argv[0]); + + if (value) { + GroupManager::getInstance().registerContainer((BasicComponent*)(ref->comp)); + } + } + return JS_UNDEFINED; +} + static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("nativeSetStyle", 0, NativeCompSetStyle), TJS_CFUNC_DEF("addEventListener", 0, NativeCompAddEventListener), @@ -31,6 +44,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), + TJS_CFUNC_DEF("setInGroup", 1, NativeCompSetInGroup), }; static const JSCFunctionListEntry ComponentClassFuncs[] = { diff --git a/src/render/native/components/window/window.cpp b/src/render/native/components/window/window.cpp index e83678d40..5c0b89579 100644 --- a/src/render/native/components/window/window.cpp +++ b/src/render/native/components/window/window.cpp @@ -17,7 +17,6 @@ lv_obj_t* GetWindowInstance () { void WindowInit () { lv_disp_t* disp_default = lv_disp_get_default(); window_instance = lv_obj_create(lv_scr_act()); - lv_group_add_obj(lv_group_get_default(), window_instance); lv_obj_set_style_height(window_instance, disp_default->driver->ver_res, 0); lv_obj_set_style_width(window_instance, disp_default->driver->hor_res, 0); lv_obj_set_style_pad_all(window_instance, 0, 0); diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index 7d26e20aa..2aff3d21f 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -1,6 +1,7 @@ #include "./comp.hpp" #include "native/core/utils/utils.hpp" +#include "native/core/group/group_manager.hpp" std::unordered_map comp_map; @@ -46,13 +47,24 @@ void BasicComponent::insertChildBefore(void *child) { }; void BasicComponent::removeChild(void* child) { - lv_obj_del_async((static_cast(child))->instance); + BasicComponent* childComp = static_cast(child); + + if (GroupManager::getInstance().isContainerRegistered(this)) { + GroupManager::getInstance().removeFromGroup(childComp->instance); + } + + lv_obj_del_async(childComp->instance); }; void BasicComponent::appendChild (void* child) { - static_cast(child)->parent_instance = this->instance; - if (!(static_cast(child)->is_fixed) && (static_cast(child)->type != COMP_TYPE_MASK)) { - lv_obj_set_parent((static_cast(child))->instance, this->instance); + BasicComponent* childComp = static_cast(child); + childComp->parent_instance = this->instance; + if (!childComp->is_fixed && childComp->type != COMP_TYPE_MASK) { + lv_obj_set_parent(childComp->instance, this->instance); + } + + if (GroupManager::getInstance().isContainerRegistered(this)) { + GroupManager::getInstance().addToGroup(childComp->instance); } }; @@ -234,6 +246,7 @@ void BasicComponent::setBackgroundImage (uint8_t* buf, size_t buf_len, int32_t s }; BasicComponent::~BasicComponent () { + GroupManager::getInstance().unregisterContainer(this); comp_map.erase(this->uid); const lv_coord_t* ptr1 = this->grid_row_desc; diff --git a/src/render/native/core/group/group_manager.cpp b/src/render/native/core/group/group_manager.cpp new file mode 100644 index 000000000..aaa09b336 --- /dev/null +++ b/src/render/native/core/group/group_manager.cpp @@ -0,0 +1,55 @@ +#include "group_manager.hpp" + +GroupManager& GroupManager::getInstance() { + static GroupManager instance; + return instance; +} + +lv_group_t* GroupManager::getDefaultGroup() { + return lv_group_get_default(); +} + +void GroupManager::registerContainer(BasicComponent* container) { + if (container) { + registered_containers.insert(container); + } +} + +void GroupManager::unregisterContainer(BasicComponent* container) { + registered_containers.erase(container); +} + +bool GroupManager::isContainerRegistered(BasicComponent* container) { + return registered_containers.count(container) > 0; +} + +void GroupManager::addToGroup(lv_obj_t* obj) { + lv_group_t* group = getDefaultGroup(); + if (group && obj) { + lv_group_add_obj(group, obj); + checkAutoEditMode(); + } +} + +void GroupManager::removeFromGroup(lv_obj_t* obj) { + if (obj) { + lv_group_remove_obj(obj); + checkAutoEditMode(); + } +} + +void GroupManager::checkAutoEditMode() { + lv_group_t* group = getDefaultGroup(); + if (!group) return; + + uint32_t count = lv_group_get_obj_count(group); + if (count == 1) { + lv_obj_t* focused = lv_group_get_focused(group); + if (focused && lv_obj_is_editable(focused)) { + lv_group_set_editing(group, true); + } + } else if (count > 1) { + lv_group_set_editing(group, false); + } +} + diff --git a/src/render/native/core/group/group_manager.hpp b/src/render/native/core/group/group_manager.hpp new file mode 100644 index 000000000..e59047e4d --- /dev/null +++ b/src/render/native/core/group/group_manager.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +extern "C" { + #include "lvgl.h" +}; + +class BasicComponent; + +class GroupManager { +public: + static GroupManager& getInstance(); + + lv_group_t* getDefaultGroup(); + + void registerContainer(BasicComponent* container); + void unregisterContainer(BasicComponent* container); + bool isContainerRegistered(BasicComponent* container); + + void addToGroup(lv_obj_t* obj); + void removeFromGroup(lv_obj_t* obj); + void checkAutoEditMode(); + +private: + std::unordered_set registered_containers; + GroupManager() = default; + GroupManager(const GroupManager&) = delete; + GroupManager& operator=(const GroupManager&) = delete; +}; + diff --git a/src/render/react/components/View/comp.ts b/src/render/react/components/View/comp.ts index 937bbfe58..743f594bd 100644 --- a/src/render/react/components/View/comp.ts +++ b/src/render/react/components/View/comp.ts @@ -6,15 +6,23 @@ import { setStyle, styleGetterProp, } from "../config"; +import { DefaultGroup } from "../../core/group"; const bridge = globalThis[Symbol.for('lvgljs')]; const NativeView = bridge.NativeRender.NativeComponents.View; -export type ViewProps = CommonProps +export type ViewProps = CommonProps & { + group?: typeof DefaultGroup; +} function setViewProps(comp, newProps: ViewProps, oldProps: ViewProps) { const setter = { ...CommonComponentApi({ compName: "View", comp, newProps, oldProps }), + group(g) { + if (g === DefaultGroup) { + comp.setInGroup(true); + } + }, }; Object.keys(setter).forEach((key) => { if (newProps.hasOwnProperty(key)) { diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index 0660a3cac..abbf95fd4 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -56,6 +56,7 @@ export type CommonProps = { currentTarget: any, stopPropogation: () => void, }) => void; + onFocusedStyle?: StyleProps; }; export type OnChangeEvent = { @@ -162,5 +163,14 @@ export const CommonComponentApi = function ({ onReleased(fn) { handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_RELEASED); }, + onFocusedStyle(styleSheet) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.STATE_FOCUSED, + oldStyleSheet: oldProps.onFocusedStyle, + }); + }, }; }; diff --git a/src/render/react/core/group/index.ts b/src/render/react/core/group/index.ts new file mode 100644 index 000000000..3bc153319 --- /dev/null +++ b/src/render/react/core/group/index.ts @@ -0,0 +1,2 @@ +export const DefaultGroup = Symbol('DefaultGroup'); + diff --git a/src/render/react/index.ts b/src/render/react/index.ts index 3f509f204..82165f8ff 100644 --- a/src/render/react/index.ts +++ b/src/render/react/index.ts @@ -74,5 +74,6 @@ export { EAnimateEasingFunc, Animate } from "./core/animate"; export { Dimensions } from "./core/dimensions"; export { BUILT_IN_SYMBOL } from "./core/style/symbol"; export { Theme } from "./core/theme"; +export { DefaultGroup } from "./core/group"; export const Render = Renderer; diff --git a/test/group/1/index.jsx b/test/group/1/index.jsx new file mode 100644 index 000000000..883cddab9 --- /dev/null +++ b/test/group/1/index.jsx @@ -0,0 +1,109 @@ +import { View, Render, Text, Button, Slider, DefaultGroup, Dimensions } from 'lvgljs-ui'; +import React, { useState } from 'react'; + +const { width, height } = Dimensions.window; + +function App() { + const [showSlider, setShowSlider] = useState(true); + + return ( + + + Header (not in group) + + + + + Content (in group, use keyboard to navigate) + + + + {showSlider && ( + + )} + + + + + ); +} + +const style = { + window: { + width, + height, + display: 'flex', + 'flex-direction': 'column', + }, + header: { + height: 80, + 'background-color': '#f0f0f0', + display: 'flex', + 'align-items': 'center', + 'padding-left': 20, + }, + headerText: { + 'text-color': '#333', + }, + toggleBtn: { + width: 140, + height: 40, + 'margin-left': 20, + 'background-color': '#2196f3', + }, + content: { + flex: 1, + padding: 20, + display: 'flex', + 'flex-direction': 'column', + 'row-spacing': 15, + }, + contentText: { + 'text-color': '#666', + 'margin-bottom': 10, + }, + button: { + width: 200, + height: 50, + 'border-width': 2, + 'border-color': '#ccc', + 'background-color': '#ffffff', + display: 'flex', + 'justify-content': 'center', + 'align-items': 'center', + }, + buttonFocused: { + 'border-width': 3, + 'border-color': '#ff0000', + 'background-color': '#ffe0e0', + }, + slider: { + width: 200, + height: 20, + }, + sliderFocused: { + 'background-color': '#e0ffe0', + }, +}; + +Render.render(); + From 053617dded1faf3adb8d5d28376ca8e7c0016aa2 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 14 Jan 2026 12:01:24 +0800 Subject: [PATCH 11/62] refactor: extract init_input_devices for indev init --- src/engine/hal/simulator/simulator.cpp | 66 +++++++++++++------------- src/engine/hal/simulator/simulator.hpp | 12 ----- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/engine/hal/simulator/simulator.cpp b/src/engine/hal/simulator/simulator.cpp index 30a047204..3cb558fb6 100644 --- a/src/engine/hal/simulator/simulator.cpp +++ b/src/engine/hal/simulator/simulator.cpp @@ -1,16 +1,40 @@ #include "./simulator.hpp" +#include "private.h" -void hal_init(void) { - hor_res = SDL_HOR_RES; - ver_res = SDL_VER_RES; +static lv_indev_t *init_input_devices(lv_group_t *g) { + /* Add input devices: mouse, keyboard, and encoder */ + struct { + lv_indev_type_t type; + void (*read_cb)(lv_indev_drv_t *, lv_indev_data_t *); + bool set_group; + } indev_configs[] = { + {LV_INDEV_TYPE_POINTER, &sdl_mouse_read, false}, + {LV_INDEV_TYPE_KEYPAD, &sdl_keyboard_read, true}, + {LV_INDEV_TYPE_ENCODER, &sdl_mousewheel_read, true} + }; - static lv_color_t buf[SDL_HOR_RES * 100]; + static lv_indev_drv_t indev_drvs[3]; + lv_indev_t *mouse_indev = nullptr; - flush_cb = sdl_display_flush; + for (size_t i = 0; i < ARRAY_SIZE(indev_configs); i++) { + lv_indev_drv_init(&indev_drvs[i]); /*Basic initialization*/ + indev_drvs[i].type = indev_configs[i].type; + indev_drvs[i].read_cb = indev_configs[i].read_cb; + lv_indev_t *cur_indev = lv_indev_drv_register(&indev_drvs[i]); + + if (indev_configs[i].set_group) + lv_indev_set_group(cur_indev, g); + + if (indev_configs[i].type == LV_INDEV_TYPE_POINTER) + mouse_indev = cur_indev; + } - read_cb1 = &sdl_mouse_read; - read_cb2 = &sdl_keyboard_read; - read_cb3 = &sdl_mousewheel_read; + return mouse_indev; +} + +void hal_init(void) { + + static lv_color_t buf[SDL_HOR_RES * 100]; /* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/ sdl_init(); @@ -23,7 +47,7 @@ void hal_init(void) { static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); /*Basic initialization*/ disp_drv.draw_buf = &disp_buf1; - disp_drv.flush_cb = flush_cb; + disp_drv.flush_cb = &sdl_display_flush; disp_drv.hor_res = SDL_HOR_RES; disp_drv.ver_res = SDL_VER_RES; @@ -35,29 +59,7 @@ void hal_init(void) { lv_group_t * g = lv_group_create(); lv_group_set_default(g); - /* Add the mouse as input device - * Use the 'mouse' driver which reads the PC's mouse*/ - static lv_indev_drv_t indev_drv_1; - lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/ - indev_drv_1.type = LV_INDEV_TYPE_POINTER; - - /*This function will be called periodically (by the library) to get the mouse position and state*/ - indev_drv_1.read_cb = read_cb1; - lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1); - - static lv_indev_drv_t indev_drv_2; - lv_indev_drv_init(&indev_drv_2); /*Basic initialization*/ - indev_drv_2.type = LV_INDEV_TYPE_KEYPAD; - indev_drv_2.read_cb = read_cb2; - lv_indev_t *kb_indev = lv_indev_drv_register(&indev_drv_2); - lv_indev_set_group(kb_indev, g); - - static lv_indev_drv_t indev_drv_3; - lv_indev_drv_init(&indev_drv_3); /*Basic initialization*/ - indev_drv_3.type = LV_INDEV_TYPE_ENCODER; - indev_drv_3.read_cb = read_cb3; - lv_indev_t * enc_indev = lv_indev_drv_register(&indev_drv_3); - lv_indev_set_group(enc_indev, g); + lv_indev_t *mouse_indev = init_input_devices(g); /*Set a cursor for the mouse*/ LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/ diff --git a/src/engine/hal/simulator/simulator.hpp b/src/engine/hal/simulator/simulator.hpp index 12713b802..e2f53fd9d 100644 --- a/src/engine/hal/simulator/simulator.hpp +++ b/src/engine/hal/simulator/simulator.hpp @@ -4,15 +4,3 @@ #include "lvgl/lvgl.h" #include "lv_drivers/sdl/sdl.h" -static void* buf; - -static void (*flush_cb)(struct _lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); - -static lv_coord_t hor_res; -static lv_coord_t ver_res; - -using read_cb = void (*)(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -static read_cb read_cb1; -static read_cb read_cb2; -static read_cb read_cb3; From 1b17f0cd656f3245fe5088a1b6a0f6d7a69ad7f8 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Thu, 15 Jan 2026 00:32:02 +0800 Subject: [PATCH 12/62] demo: add flex ViewPager demo (ts) --- demo/viewpager/index.tsx | 180 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 demo/viewpager/index.tsx diff --git a/demo/viewpager/index.tsx b/demo/viewpager/index.tsx new file mode 100644 index 000000000..649f6c15e --- /dev/null +++ b/demo/viewpager/index.tsx @@ -0,0 +1,180 @@ +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { Button, Dimensions, Render, Text, View } from "lvgljs-ui"; + +const { width, height } = Dimensions.window; + +/** + * 纯 View + flex + scroll-snap 的 “ViewPager” demo + * + * - pager: 横向 flex 容器,可滚动 + * - page: 每页固定宽高,并开启 snappable + * - 导航点: 底部一排小圆点 + prev/next 按钮(方便在没手势时测试) + */ +function App() { + const pageCount = 4; + const pagerRef = useRef(); + const pageRefs = useRef([]); + + const [active, setActive] = useState(0); + + const pageColors = useMemo( + () => ["red", "blue", "green", "orange"], + [] + ); + + const scrollTo = (idx: number) => { + const n = Math.max(0, Math.min(pageCount - 1, idx)); + setActive(n); + // 让对应 page 滚动进可视区域(LVGL 内部会按 snap 对齐) + pageRefs.current[n]?.scrollIntoView?.(); + }; + + useEffect(() => { + // 初始定位到第 0 页 + scrollTo(2); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + {Array.from({ length: pageCount }).map((_, i) => ( + (pageRefs.current[i] = ins)} + style={[ + style.page, + { "background-color": pageColors[i % pageColors.length] }, + ]} + > + Page {i + 1} + + flex-row + scroll-snap-x + scrollIntoView() + + + ))} + + + + + + + {Array.from({ length: pageCount }).map((_, i) => ( + + ))} + + + + + + ); +} + +const style: Record = { + root: { + width, + height, + padding: 0, + "border-width": 0, + "border-radius": 0, + "background-color": "black", + }, + + // 横向滚动容器 + pager: { + width, + height: height - 80, + "border-width": 0, + "border-radius": 0, + + // flex 横向排布 + display: "flex", + "flex-flow": 0, // LV_FLEX_FLOW_ROW(用数值是为了符合你们 style.cpp 的 JS_ToInt32) + + // 开启滚动 + 惯性 + overflow: 0, // 0 -> add_flag(SCROLLABLE) + "overflow-scrolling": 1, + + // 开启 X 方向 snap(枚举值见 LV_SCROLL_SNAP_*) + "scroll-snap-x": 2, // 通常 2=LV_SCROLL_SNAP_CENTER(不同版本可能略有差异;看效果不对再调) + }, + + // 每一页:固定为一屏大小,并允许被 snap + page: { + width, + height: height - 80, + "border-radius": 0, + "border-width": 0, + "padding": 16, + "scroll-enable-snap": 1, + }, + + pageTitle: { + "text-color": "white", + }, + pageDesc: { + "text-color": "white", + }, + + controls: { + width, + height: 80, + display: "flex", + "flex-flow": 0, // row + "justify-content": 3, // space-evenly(你们 style.cpp 直接把 int cast 成 lv_flex_align_t) + "align-items": 2, // center + "background-color": "grey", + }, + + navBtn: { + width: 60, + height: 50, + "border-radius": 25, + "background-color": "white", + }, + + dots: { + display: "flex", + "flex-flow": 0, // row + "justify-content": 3, + "align-items": 2, + width: width - 140, + height: 50, + }, + + dot: { + width: 10, + height: 10, + "border-radius": 0x7fff, + }, + dotActive: { + "background-color": "white", + opacity: 255, + }, + dotInactive: { + "background-color": "white", + opacity: 80, + }, +}; + +Render.render(); + From 41ed000adbc8d087aae927312364f07555f1de2a Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 14 Jan 2026 17:45:10 +0800 Subject: [PATCH 13/62] feat: add arc test code --- test/arc/1/index.tsx | 88 ++++++++++++++++++++++++ test/arc/2/index.tsx | 158 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 test/arc/1/index.tsx create mode 100644 test/arc/2/index.tsx diff --git a/test/arc/1/index.tsx b/test/arc/1/index.tsx new file mode 100644 index 000000000..e73dfb5e1 --- /dev/null +++ b/test/arc/1/index.tsx @@ -0,0 +1,88 @@ +import { View, Text, Render, Dimensions, Arc } from 'lvgljs-ui'; +import React, { useState } from 'react'; + +const { width, height } = Dimensions.window; + +function App() { + const [value, setValue] = useState(35); + + return ( + + setValue(e.value)} + /> + {`value: ${Math.round(value)}`} + Drag the knob or click the arc + + ); +} + +const style = { + window: { + width, + height, + display: 'flex', + 'flex-direction': 'column', + 'justify-content': 'center', + 'align-items': 'center', + }, + arc: { + width: 200, + height: 200, + 'arc-width': 16, + 'arc-color': 'rgb(200,200,200)', + 'arc-rounded': true, + 'background-color': 'white', + }, + arcPressed: { + 'arc-color': 'rgb(160,160,160)', + }, + indicator: { + 'arc-width': 16, + 'arc-color': 'cyan', + 'arc-rounded': true, + }, + indicatorPressed: { + 'arc-color': '0x00838F', + }, + knob: { + 'background-color': 'white', + 'border-width': 2, + 'border-color': 'cyan', + 'border-radius': 0x7fff, + padding: 6, + }, + knobPressed: { + 'background-color': '0x00838F', + 'border-color': '0x00838F', + }, + text: { + 'text-color': 'black', + 'font-size': 20, + 'padding-top': 10, + }, + hint: { + 'text-color': 'grey', + 'font-size': 14, + 'padding-top': 4, + }, +}; + +Render.render(); + + diff --git a/test/arc/2/index.tsx b/test/arc/2/index.tsx new file mode 100644 index 000000000..9a1d7ad24 --- /dev/null +++ b/test/arc/2/index.tsx @@ -0,0 +1,158 @@ +import { View, Text, Render, Dimensions, Arc, Button } from 'lvgljs-ui'; +import React, { useMemo, useState } from 'react'; + +const { width, height } = Dimensions.window; + +const modes: Array<'normal' | 'symmetrical' | 'reverse'> = [ + 'normal', + 'symmetrical', + 'reverse', +]; + +function App() { + const [modeIndex, setModeIndex] = useState(0); + const [rotation, setRotation] = useState(0); + const [rangeToggle, setRangeToggle] = useState(false); + const [value, setValue] = useState(10); + + const mode = modes[modeIndex]; + const range: [number, number] = useMemo( + () => (rangeToggle ? [-50, 50] : [0, 100]), + [rangeToggle], + ); + + return ( + + setValue(e.value)} + /> + + + {`mode: ${mode} rotation: ${rotation}° range: [${range[0]}, ${range[1]}] value: ${Math.round( + value, + )}`} + + + + + + + + + + + + + ); +} + +const style = { + window: { + width, + height, + display: 'flex', + 'flex-direction': 'column', + 'justify-content': 'center', + 'align-items': 'center', + }, + arc: { + width: 220, + height: 220, + 'arc-width': 18, + 'arc-color': 'rgb(210,210,210)', + 'arc-rounded': true, + 'background-color': 'white', + }, + indicator: { + 'arc-width': 18, + 'arc-color': '0x4caf50', + 'arc-rounded': true, + }, + knob: { + 'background-color': 'white', + 'border-width': 2, + 'border-color': '0x4caf50', + 'border-radius': 0x7fff, + padding: 6, + }, + text: { + width: width - 20, + 'text-color': 'black', + 'font-size': 14, + 'text-align': 'center', + 'padding-top': 12, + 'padding-bottom': 12, + }, + controls: { + width: width - 20, + display: 'flex', + 'flex-direction': 'row', + 'justify-content': 'space-evenly', + 'align-items': 'center', + }, + button: { + width: 90, + height: 44, + 'border-width': 2, + 'border-color': 'grey', + 'background-color': 'white', + 'border-radius': 12, + display: 'flex', + 'justify-content': 'center', + 'align-items': 'center', + }, + buttonPressed: { + 'border-color': '0x4caf50', + 'border-width': 3, + }, + buttonText: { + 'text-color': 'black', + 'font-size': 12, + 'text-align': 'center', + }, +}; + +Render.render(); + + From 90e252ab7dfb52e7ab98206f404e9e535e3d27f8 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Thu, 15 Jan 2026 12:04:20 +0800 Subject: [PATCH 14/62] feat: enhance group management in React components - Introduced AddChildToDefGroup and AddCurToDefGroup symbols for group type management. - Updated View component to support groupType prop for specifying group behavior. - Modified GroupManager to handle new group types and improve child management. - Refactored BasicComponent methods to integrate with the new group system. - Updated documentation and examples to reflect changes in group handling. --- .gitignore | 3 + doc/component/View.md | 4 +- doc/props/groupType.md | 59 ++++++++++ .../native/components/view/view_wrap.cpp | 15 ++- src/render/native/core/basic/comp.cpp | 22 ++-- .../native/core/group/group_manager.cpp | 109 +++++++++++++----- .../native/core/group/group_manager.hpp | 23 ++-- src/render/react/components/View/comp.ts | 11 +- src/render/react/core/group/index.ts | 11 +- src/render/react/index.ts | 2 +- test/group/1/index.jsx | 26 ++++- 11 files changed, 203 insertions(+), 82 deletions(-) create mode 100644 doc/props/groupType.md diff --git a/.gitignore b/.gitignore index 2fc2e53b1..441397dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ CMakeCache.txt # NPM node_modules/ src/render/react/index.js + +# Cursor AI +.cursor/ \ No newline at end of file diff --git a/doc/component/View.md b/doc/component/View.md index cb73473ca..7a744fd87 100644 --- a/doc/component/View.md +++ b/doc/component/View.md @@ -19,10 +19,11 @@ - [onLongPressRepeat](../props/onLongPressRepeat.md) - [align](../props/align.md) - [alignTo](../props/alignTo.md) +- [groupType](../props/groupType.md) ## Usage ```jsx -import { View, EAlignType, Button, Text } from 'lvlgjs-ui' +import { View, EAlignType, Button, Text, AddChildToDefGroup } from 'lvlgjs-ui' import { useRef, useEffect } from 'react' function Component () { @@ -34,6 +35,7 @@ function Component () { return ( { e.stopPropagation() }} onPressed={() => {}} diff --git a/doc/props/groupType.md b/doc/props/groupType.md new file mode 100644 index 000000000..936654d56 --- /dev/null +++ b/doc/props/groupType.md @@ -0,0 +1,59 @@ +# Component prop groupType + +`groupType` is used to control **LVGL default group** behavior (focus navigation by keyboard/encoder). + +This project exports: +- `AddCurToDefGroup`: add **current component** to default group +- `AddChildToDefGroup`: when this component is used as a container, add **its children** to default group (and keep focus order consistent with UI order) + +## Type +```ts +import type { AddToDefGroupType } from 'lvgljs-ui'; + +interface Props { + groupType?: AddToDefGroupType; +} +``` + +## How it works +- **Default group**: must be created and set by platform/hal code (simulator already does this via `lv_group_set_default`). +- **AddCurToDefGroup**: + - Adds the current component instance into the default group. + - Useful for `View` because LVGL `lv_obj` is not `group_def` by default, but it can still be focused if added to group and has `LV_OBJ_FLAG_CLICK_FOCUSABLE`. +- **AddChildToDefGroup**: + - Marks the current component as a “group container”. + - When children are appended to it, those children are added into the default group. + - Some widgets (e.g. `Button`, `Slider`, `Textarea`, etc.) are `group_def` in LVGL and will be auto-added to the default group at creation time. When they are later re-parented into the UI tree, this can cause **focus order != UI order**. + - This binding will re-order the default group's internal list to match the container's child order when children are appended, so focus navigation follows UI order. + +## Usage +```jsx +import { + View, + Text, + Button, + Slider, + AddChildToDefGroup, + AddCurToDefGroup, +} from 'lvgljs-ui'; + +export function App() { + return ( + + {/* 1) Make a focusable "row" by adding the current View to group */} + + Focusable View + + + {/* 2) LVGL group_def widgets (e.g. Button/Slider) will be in default group */} + + + + + ); +} +``` + + diff --git a/src/render/native/components/view/view_wrap.cpp b/src/render/native/components/view/view_wrap.cpp index 763186fd6..b27eaf9a7 100644 --- a/src/render/native/components/view/view_wrap.cpp +++ b/src/render/native/components/view/view_wrap.cpp @@ -17,14 +17,13 @@ WRAPPED_MOVE_TO_BACKGROUND(View, "View") WRAPPED_SCROLL_INTO_VIEW(View, "View") WRAPPED_JS_CLOSE_COMPONENT(View, "View") -static JSValue NativeCompSetInGroup(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsBool(argv[0])) { +static JSValue NativeCompSetInGroupType(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + if (argc >= 1 && JS_IsNumber(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ViewClassID); - bool value = JS_ToBool(ctx, argv[0]); - - if (value) { - GroupManager::getInstance().registerContainer((BasicComponent*)(ref->comp)); - } + int32_t value; + JS_ToInt32(ctx, &value, argv[0]); + + GroupManager::getInstance().setInGroupType((BasicComponent*)(ref->comp), value); } return JS_UNDEFINED; } @@ -44,7 +43,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), - TJS_CFUNC_DEF("setInGroup", 1, NativeCompSetInGroup), + TJS_CFUNC_DEF("setInGroupType", 1, NativeCompSetInGroupType), }; static const JSCFunctionListEntry ComponentClassFuncs[] = { diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index 2aff3d21f..b328375ba 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -37,22 +37,18 @@ bool BasicComponent::isEventRegist(int eventType) { }; void BasicComponent::insertChildBefore(void *child) { - static_cast(child)->parent_instance = this->instance; - if (!(static_cast(child)->is_fixed) && (static_cast(child)->type != COMP_TYPE_MASK)) { - lv_obj_t* ins = (static_cast(child))->instance; - lv_obj_set_parent(ins, this->instance); - uint32_t index = lv_obj_get_index(ins); - lv_obj_move_to_index(ins, index); + BasicComponent* childComp = static_cast(child); + childComp->parent_instance = this->instance; + if (!childComp->is_fixed && childComp->type != COMP_TYPE_MASK) { + lv_obj_set_parent(childComp->instance, this->instance); + uint32_t index = lv_obj_get_index(childComp->instance); + lv_obj_move_to_index(childComp->instance, index); + GroupManager::getInstance().addChildToDefGroup(childComp); } }; void BasicComponent::removeChild(void* child) { BasicComponent* childComp = static_cast(child); - - if (GroupManager::getInstance().isContainerRegistered(this)) { - GroupManager::getInstance().removeFromGroup(childComp->instance); - } - lv_obj_del_async(childComp->instance); }; @@ -61,11 +57,9 @@ void BasicComponent::appendChild (void* child) { childComp->parent_instance = this->instance; if (!childComp->is_fixed && childComp->type != COMP_TYPE_MASK) { lv_obj_set_parent(childComp->instance, this->instance); + GroupManager::getInstance().addChildToDefGroup(childComp); } - if (GroupManager::getInstance().isContainerRegistered(this)) { - GroupManager::getInstance().addToGroup(childComp->instance); - } }; void BasicComponent::initCompStyle (int32_t type) { diff --git a/src/render/native/core/group/group_manager.cpp b/src/render/native/core/group/group_manager.cpp index aaa09b336..cfeb332cd 100644 --- a/src/render/native/core/group/group_manager.cpp +++ b/src/render/native/core/group/group_manager.cpp @@ -1,55 +1,100 @@ #include "group_manager.hpp" +#include +#include +#include +#include + GroupManager& GroupManager::getInstance() { static GroupManager instance; return instance; } -lv_group_t* GroupManager::getDefaultGroup() { - return lv_group_get_default(); +static void getDesiredOrder(lv_obj_t* parent, std::vector& desired, lv_group_t* def_group) { + // Desired order: parent's children order, but only those currently in default group. + if (!parent) return; + uint32_t child_cnt = lv_obj_get_child_cnt(parent); + for (uint32_t i = 0; i < child_cnt; i++) { + lv_obj_t* child = lv_obj_get_child(parent, i); + if (!child) continue; + if (lv_obj_get_group(child) == def_group) desired.push_back(child); + } } -void GroupManager::registerContainer(BasicComponent* container) { - if (container) { - registered_containers.insert(container); +static size_t getMatchedSize(lv_group_t* def_group, std::vector& desired, + std::unordered_map& node_of +) { + size_t matched_size = 0; + node_of.reserve(desired.size()); + + void* node; + _LV_LL_READ(&def_group->obj_ll, node) { + lv_obj_t** obj_i = static_cast(node); + lv_obj_t* obj = *obj_i; + if (std::find(desired.begin(), desired.end(), obj) != desired.end()) { + if (desired[matched_size] == obj) matched_size++; + node_of[obj] = node; + if (matched_size == desired.size()) break; + } } + return matched_size; } -void GroupManager::unregisterContainer(BasicComponent* container) { - registered_containers.erase(container); +static void startReorder(lv_group_t* def_group, std::vector& desired, + std::unordered_map& node_of +) { + for (size_t i = desired.size() - 1; i > 0; i--) { + void* n_act = node_of[desired[i - 1]]; + void* n_after = node_of[desired[i]]; + if (n_act && n_after && n_act != n_after) { + _lv_ll_move_before(&def_group->obj_ll, n_act, n_after); + } + } } -bool GroupManager::isContainerRegistered(BasicComponent* container) { - return registered_containers.count(container) > 0; +static void reorderDefaultGroupChildrenForParent(lv_obj_t* parent) { + lv_group_t* def_group = lv_group_get_default(); + if (!def_group) return; + + std::vector desired; + getDesiredOrder(parent, desired, def_group); + if (desired.size() < 2) return; + + std::unordered_map node_of; + size_t matched_size = getMatchedSize(def_group, desired, node_of); + if (matched_size == desired.size()) return; + + startReorder(def_group, desired, node_of); } -void GroupManager::addToGroup(lv_obj_t* obj) { - lv_group_t* group = getDefaultGroup(); - if (group && obj) { - lv_group_add_obj(group, obj); - checkAutoEditMode(); - } +static void addToGroupInternal(BasicComponent* container) { + if (!container || !container->instance) return; + lv_group_add_obj(lv_group_get_default(), container->instance); } -void GroupManager::removeFromGroup(lv_obj_t* obj) { - if (obj) { - lv_group_remove_obj(obj); - checkAutoEditMode(); +void GroupManager::setInGroupType(BasicComponent* container, int32_t type) { + if (!container) return; + + switch (type) { + case ADD_CUR_TO_DEF_GROUP: + addToGroupInternal(container); + break; + case ADD_CHILD_TO_DEF_GROUP: + parent_instances.insert(container->instance); + break; + default: + break; } } -void GroupManager::checkAutoEditMode() { - lv_group_t* group = getDefaultGroup(); - if (!group) return; - - uint32_t count = lv_group_get_obj_count(group); - if (count == 1) { - lv_obj_t* focused = lv_group_get_focused(group); - if (focused && lv_obj_is_editable(focused)) { - lv_group_set_editing(group, true); - } - } else if (count > 1) { - lv_group_set_editing(group, false); - } +void GroupManager::unregisterContainer(BasicComponent* container) { + parent_instances.erase(container->instance); } +void GroupManager::addChildToDefGroup(BasicComponent* container) { + if (parent_instances.find(container->parent_instance) == parent_instances.end()) return; + addToGroupInternal(container); + // Fix ordering: some widgets are auto-added to default group at creation time (before re-parenting), + // so when we attach children we re-order the group's focus list to match the parent's child order. + reorderDefaultGroupChildrenForParent(container->parent_instance); +} diff --git a/src/render/native/core/group/group_manager.hpp b/src/render/native/core/group/group_manager.hpp index e59047e4d..f1b621108 100644 --- a/src/render/native/core/group/group_manager.hpp +++ b/src/render/native/core/group/group_manager.hpp @@ -1,31 +1,28 @@ #pragma once #include +#include "native/core/basic/comp.hpp" extern "C" { - #include "lvgl.h" }; -class BasicComponent; - class GroupManager { public: static GroupManager& getInstance(); - lv_group_t* getDefaultGroup(); - - void registerContainer(BasicComponent* container); + void setInGroupType(BasicComponent* container, int32_t type); void unregisterContainer(BasicComponent* container); - bool isContainerRegistered(BasicComponent* container); - - void addToGroup(lv_obj_t* obj); - void removeFromGroup(lv_obj_t* obj); - void checkAutoEditMode(); + void addChildToDefGroup(BasicComponent* container); private: - std::unordered_set registered_containers; + enum EAddToDefGroupType { + ADD_CHILD_TO_DEF_GROUP = 0, + ADD_CUR_TO_DEF_GROUP = 1, + ADD_TO_DEF_GROUP_TYPE_NONE = 2, + }; + + std::unordered_set parent_instances; GroupManager() = default; GroupManager(const GroupManager&) = delete; GroupManager& operator=(const GroupManager&) = delete; }; - diff --git a/src/render/react/components/View/comp.ts b/src/render/react/components/View/comp.ts index 743f594bd..44bff9ae2 100644 --- a/src/render/react/components/View/comp.ts +++ b/src/render/react/components/View/comp.ts @@ -6,22 +6,21 @@ import { setStyle, styleGetterProp, } from "../config"; -import { DefaultGroup } from "../../core/group"; +import { AddToDefGroupType, toNativeInGroupType } from "../../core/group"; const bridge = globalThis[Symbol.for('lvgljs')]; const NativeView = bridge.NativeRender.NativeComponents.View; export type ViewProps = CommonProps & { - group?: typeof DefaultGroup; + groupType?: AddToDefGroupType; } function setViewProps(comp, newProps: ViewProps, oldProps: ViewProps) { const setter = { ...CommonComponentApi({ compName: "View", comp, newProps, oldProps }), - group(g) { - if (g === DefaultGroup) { - comp.setInGroup(true); - } + groupType(g) { + const v = toNativeInGroupType(g); + if (v !== undefined) comp.setInGroupType(v); }, }; Object.keys(setter).forEach((key) => { diff --git a/src/render/react/core/group/index.ts b/src/render/react/core/group/index.ts index 3bc153319..855d7708a 100644 --- a/src/render/react/core/group/index.ts +++ b/src/render/react/core/group/index.ts @@ -1,2 +1,11 @@ -export const DefaultGroup = Symbol('DefaultGroup'); +export const AddChildToDefGroup = Symbol.for('AddChildToDefGroup'); +export const AddCurToDefGroup = Symbol.for('AddCurToDefGroup'); + +export type AddToDefGroupType = typeof AddChildToDefGroup | typeof AddCurToDefGroup; + +export function toNativeInGroupType(g?: AddToDefGroupType): 0 | 1 | undefined { + if (g === AddChildToDefGroup) return 0; + if (g === AddCurToDefGroup) return 1; + return undefined; +} diff --git a/src/render/react/index.ts b/src/render/react/index.ts index 82165f8ff..bf0f689af 100644 --- a/src/render/react/index.ts +++ b/src/render/react/index.ts @@ -74,6 +74,6 @@ export { EAnimateEasingFunc, Animate } from "./core/animate"; export { Dimensions } from "./core/dimensions"; export { BUILT_IN_SYMBOL } from "./core/style/symbol"; export { Theme } from "./core/theme"; -export { DefaultGroup } from "./core/group"; +export { AddChildToDefGroup, AddCurToDefGroup } from "./core/group"; export const Render = Renderer; diff --git a/test/group/1/index.jsx b/test/group/1/index.jsx index 883cddab9..829d135d1 100644 --- a/test/group/1/index.jsx +++ b/test/group/1/index.jsx @@ -1,4 +1,4 @@ -import { View, Render, Text, Button, Slider, DefaultGroup, Dimensions } from 'lvgljs-ui'; +import { View, Render, Text, Button, Slider, AddChildToDefGroup, AddCurToDefGroup, Dimensions } from 'lvgljs-ui'; import React, { useState } from 'react'; const { width, height } = Dimensions.window; @@ -9,7 +9,14 @@ function App() { return ( - Header (not in group) + setShowSlider(!showSlider)} + > + Header (not in group) + - - Content (in group, use keyboard to navigate) + + + + Content (in group, use keyboard to navigate) + + Content (in group, use keyboard to navigate) + Content (in group, use keyboard to navigate) + {title} + + ); +} + +function Page1List({ onBack }: { onBack: () => void }) { + const items = useMemo(() => Array.from({ length: 40 }).map((_, i) => i + 1), []); + const firstItemRef = useRef(null); + useAutoFocus(firstItemRef, []); + + return ( + +
+ + + + {items.map((n) => ( + (firstItemRef.current = ins) : undefined } as any)} + onFocusedStyle={style.focused} + style={style.listRow} + onClick={() => { + // no-op (demo) + }} + > + {`Item ${n}`} + + ))} + + + + ); +} + +function Page2Info({ onBack }: { onBack: () => void }) { + const infos = useMemo( + () => [ + { title: "Info A", body: "This is the first section of info (for demo switching)." }, + { title: "Info B", body: "This is the second section. Use Left/Right to switch." }, + { title: "Info C", body: "This is the third section. Dots indicate the current page." }, + { title: "Info D", body: "This is the fourth section. A simple info page example." }, + { title: "Info E", body: "This is the fifth section. Switching loops around." }, + ], + [], + ); + + const [idx, setIdx] = useState(0); + const cur = infos[idx]; + + const prev = () => setIdx((i) => (i - 1 + infos.length) % infos.length); + const next = () => setIdx((i) => (i + 1) % infos.length); + return ( + +
+ + + + {cur.title} + {cur.body} + + + + + + + + + + {infos.map((_, i) => ( + + ))} + + + + ); +} + +function Page3Controls({ onBack }: { onBack: () => void }) { + const [slider, setSlider] = useState(30); + const [checked1, setChecked1] = useState(false); + const [checked2, setChecked2] = useState(true); + return ( + +
+ + + + Slider + setSlider(e.value)} + /> + {`Current Value: ${Math.round(slider)}%`} + + + + Checkbox + setChecked1(!!e.checked)} + /> + setChecked2(!!e.checked)} + /> + + + + Button + Text + + + + {`Hint: This page's controls are vertically arranged, and the container is scrollable.\nAll operable controls are marked with groupType.`} + + + + + ); +} + +function Page4Countdown({ onBack }: { onBack: () => void }) { + const total = 60; + const [remain, setRemain] = useState(total); + + useEffect(() => { + setRemain(total); + const t: ReturnType = setInterval(() => { + setRemain((r) => (r <= 0 ? 0 : r - 1)); + }, 1000); + return () => clearInterval(t as any); + }, []); + + const elapsed = total - remain; + const angle = Math.floor((elapsed / total) * 360); + return ( + +
+ + + { + // keep non-interactive for this demo + }} + /> + {`time${remain}s`} + + + + ); +} + +function Home({ go }: { go: (p: Page) => void }) { + const btnW = Math.floor((width - 24 * 2 - 12) / 2); + const btnH = 72; + + return ( + + + Navigation Demo (5 Pages) + Four-grid to enter sub-pages, top-left return + + + + + + + + + + ); +} + +function App() { + const [page, setPage] = useState("home"); + const backToHome = () => setPage("home"); + + if (page === "p1") return ; + if (page === "p2") return ; + if (page === "p3") return ; + if (page === "p4") return ; + return ; +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + }, + + header: { + width, + height: 52, + display: "flex", + "flex-direction": "row", + "align-items": "center", + "background-color": "0x202020", + }, + backBtn: { + width: 44, + height: 36, + "border-radius": 10, + "background-color": "0x404040", + margin: "0 8px", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + backText: { "text-color": "white", "font-size": 18 }, + headerTitle: { "text-color": "white", "font-size": 16 }, + + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + centerContent: { + width, + height: height - 52, + display: "flex", + "flex-direction": "column", + "justify-content": "center", + "align-items": "center", + }, + + focused: { + "border-width": 3, + "border-color": "0x00bcd4", + }, + + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, // make scrollable + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, + + listRow: { + width: "100%", + height: 44, + "border-radius": 10, + "background-color": "0x2a2a2a", + margin: "0 0 8px 0", + padding: "0 10px", + display: "flex", + "align-items": "center", + "justify-content": "flex-start", + "scroll-on-focus": 1, + }, + rowText: { "text-color": "white", "font-size": 14 }, + + infoCard: { + width: width - 24, + height: height - 52 - 140, + padding: 12, + "background-color": "0x101010", + "border-radius": 12, + }, + infoTitle: { "text-color": "white", "font-size": 18, "padding-bottom": 8 }, + infoBody: { "text-color": "0xd0d0d0", "font-size": 14 }, + infoControls: { + width: width - 24, + height: 60, + margin: "10px 0 0 0", + display: "flex", + "flex-direction": "row", + "justify-content": "space-between", + "align-items": "center", + }, + navBtn: { + width: 64, + height: 44, + "border-radius": 12, + "background-color": "white", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + navBtnText: { "text-color": "black", "font-size": 18 }, + dots: { + width: width - 24, + height: 30, + display: "flex", + "flex-direction": "row", + "justify-content": "center", + "align-items": "center", + }, + dot: { + width: 10, + height: 10, + "border-radius": 0x7fff, + margin: "0 4px", + }, + dotActive: { "background-color": "white", opacity: 255 }, + dotInactive: { "background-color": "grey", opacity: 80 }, + + sectionTitle: { + "text-color": "white", + "font-size": 16, + "padding-bottom": 6, + }, + divider: { + width: "100%", + height: 1, + "background-color": "0x303030", + margin: "10px 0", + }, + slider: { + "background-color": "0x404040", + "border-radius": 0x7fff, + padding: "-2px 0", + }, + sliderIndicator: { "background-color": "0x00bcd4", "border-radius": 0x7fff }, + sliderIndicatorPressed: { "background-color": "0x00838F" }, + sliderKnob: { + "background-color": "white", + "border-width": 2, + "border-color": "0x00bcd4", + "border-radius": 0x7fff, + padding: 6, + }, + sliderKnobPressed: { "border-color": "0x00838F", "background-color": "0x00838F" }, + + actionBtn: { + width: width - 24, + height: 44, + "border-radius": 12, + "background-color": "white", + display: "flex", + "align-items": "center", + "justify-content": "center", + margin: "6px 0 0 0", + }, + actionBtnText: { "text-color": "black", "font-size": 14 }, + hintText: { + width: "100%", + "text-color": "0xb0b0b0", + "font-size": 12, + "padding-top": 10, + }, + + arc: { + width: 220, + height: 220, + "arc-width": 18, + "arc-color": "red", + "arc-rounded": true, + "background-color": "black", + }, + arcIndicator: { "arc-width": 18, "arc-color": "0x00bcd4", "arc-rounded": true }, + arcKnobHidden: { width: 1, height: 1, opacity: 0 }, + bigText: { "text-color": "black", "font-size": 26, "padding-top": 10 }, + + homeHeader: { + width, + height: 100, + padding: "18px 24px 0 24px", + }, + homeTitle: { "text-color": "white", "font-size": 20 }, + homeSubTitle: { "text-color": "0xb0b0b0", "font-size": 12, "padding-top": 6 }, + homeGrid: { + width, + height: height - 100, + padding: "0 24px", + display: "flex", + "flex-direction": "row", + "flex-wrap": "wrap", + "justify-content": "space-between", + "align-content": "flex-start", + }, + homeBtn: { + "background-color": "0x1d1d1d", + "border-radius": 14, + margin: "0 0 12px 0", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + homeBtnText: { "text-color": "white", "font-size": 16 }, +}; + +Render.render(); + + diff --git a/demo/navigation/useAutoFocus.ts b/demo/navigation/useAutoFocus.ts new file mode 100644 index 000000000..110eefbe7 --- /dev/null +++ b/demo/navigation/useAutoFocus.ts @@ -0,0 +1,14 @@ +import { useEffect } from "react"; + +/** + * Minimal helper to avoid repeating `useEffect(() => ref.current?.focus?.(), [])`. + * Requires the underlying native component to expose a `focus()` method. + */ +export function useAutoFocus(ref: { current?: any }, deps: any[] = []) { + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + ref.current?.focus?.(); + }, deps); +} + + diff --git a/src/render/native/components/arc/arc_wrap.cpp b/src/render/native/components/arc/arc_wrap.cpp index 753a0d3a8..07d5fd94e 100644 --- a/src/render/native/components/arc/arc_wrap.cpp +++ b/src/render/native/components/arc/arc_wrap.cpp @@ -18,6 +18,7 @@ WRAPPED_INT32_VALUE(Arc, "Arc", ChangeRate) WRAPPED_MOVE_TO_FRONT(Arc, "Arc") WRAPPED_MOVE_TO_BACKGROUND(Arc, "Arc") WRAPPED_SCROLL_INTO_VIEW(Arc, "Arc") +WRAPPED_FOCUS(Arc, "Arc") WRAPPED_JS_CLOSE_COMPONENT(Arc, "Arc") static JSValue NativeCompSetRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -99,6 +100,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToFront", 0, NativeCompMoveToFront), TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), + TJS_CFUNC_DEF("focus", 0, NativeCompFocus), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), }; diff --git a/src/render/native/components/button/button_wrap.cpp b/src/render/native/components/button/button_wrap.cpp index a17a2c747..821ac14b6 100644 --- a/src/render/native/components/button/button_wrap.cpp +++ b/src/render/native/components/button/button_wrap.cpp @@ -14,6 +14,7 @@ WRAPPED_INSERT_CHILD(Button,"Button") WRAPPED_MOVE_TO_FRONT(Button, "Button") WRAPPED_MOVE_TO_BACKGROUND(Button, "Button") WRAPPED_SCROLL_INTO_VIEW(Button, "Button") +WRAPPED_FOCUS(Button, "Button") WRAPPED_JS_CLOSE_COMPONENT(Button, "Button") static const JSCFunctionListEntry ComponentProtoFuncs[] = { @@ -30,6 +31,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToFront", 0, NativeCompMoveToFront), TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), + TJS_CFUNC_DEF("focus", 0, NativeCompFocus), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), }; diff --git a/src/render/native/components/checkbox/checkbox_wrap.cpp b/src/render/native/components/checkbox/checkbox_wrap.cpp index ab427156c..fb1253b16 100644 --- a/src/render/native/components/checkbox/checkbox_wrap.cpp +++ b/src/render/native/components/checkbox/checkbox_wrap.cpp @@ -11,6 +11,7 @@ WRAPPED_JS_BACKGROUND_IMAGE(Checkbox,"Checkbox") WRAPPED_MOVE_TO_FRONT(Checkbox, "Checkbox") WRAPPED_MOVE_TO_BACKGROUND(Checkbox, "Checkbox") WRAPPED_SCROLL_INTO_VIEW(Checkbox, "Checkbox") +WRAPPED_FOCUS(Checkbox, "Checkbox") WRAPPED_JS_CLOSE_COMPONENT(Checkbox, "Checkbox") static JSValue NativeCompSetText(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -64,6 +65,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToFront", 0, NativeCompMoveToFront), TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), + TJS_CFUNC_DEF("focus", 0, NativeCompFocus), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), }; diff --git a/src/render/native/components/component.hpp b/src/render/native/components/component.hpp index 71f0d474e..cb5420412 100644 --- a/src/render/native/components/component.hpp +++ b/src/render/native/components/component.hpp @@ -146,6 +146,15 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); }; \ \ +#define WRAPPED_FOCUS(COMPONENT,COMPONENT_NAME) \ + static JSValue NativeCompFocus(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \ + COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, COMPONENT##ClassID); \ + ((COMPONENT*)(ref->comp))->BasicComponent::focus(); \ + LV_LOG_USER("%s %s focus", COMPONENT_NAME, ref->uid); \ + return JS_UNDEFINED; \ + }; \ + \ + #define WRAPPED_JS_SETSTYLE(COMPONENT,COMPONENT_NAME) \ static JSValue NativeCompSetStyle(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) { \ if (argc >= 2 && JS_IsObject(argv[0]) && JS_IsArray(argv[1]) && JS_IsNumber(argv[2]) && JS_IsNumber(argv[3]) && JS_IsBool(argv[4])) { \ diff --git a/src/render/native/components/slider/slider_wrap.cpp b/src/render/native/components/slider/slider_wrap.cpp index bad611324..a0f09db07 100644 --- a/src/render/native/components/slider/slider_wrap.cpp +++ b/src/render/native/components/slider/slider_wrap.cpp @@ -11,6 +11,7 @@ WRAPPED_JS_BACKGROUND_IMAGE(Slider,"Slider") WRAPPED_MOVE_TO_FRONT(Slider, "Slider") WRAPPED_MOVE_TO_BACKGROUND(Slider, "Slider") WRAPPED_SCROLL_INTO_VIEW(Slider, "Slider") +WRAPPED_FOCUS(Slider, "Slider") WRAPPED_JS_CLOSE_COMPONENT(Slider, "Slider") static JSValue NativeCompSetRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -55,6 +56,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToFront", 0, NativeCompMoveToFront), TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), + TJS_CFUNC_DEF("focus", 0, NativeCompFocus), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), }; diff --git a/src/render/native/components/view/view_wrap.cpp b/src/render/native/components/view/view_wrap.cpp index b27eaf9a7..2ad68b538 100644 --- a/src/render/native/components/view/view_wrap.cpp +++ b/src/render/native/components/view/view_wrap.cpp @@ -15,6 +15,7 @@ WRAPPED_INSERT_CHILD(View,"View") WRAPPED_MOVE_TO_FRONT(View, "View") WRAPPED_MOVE_TO_BACKGROUND(View, "View") WRAPPED_SCROLL_INTO_VIEW(View, "View") +WRAPPED_FOCUS(View, "View") WRAPPED_JS_CLOSE_COMPONENT(View, "View") static JSValue NativeCompSetInGroupType(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -42,6 +43,7 @@ static const JSCFunctionListEntry ComponentProtoFuncs[] = { TJS_CFUNC_DEF("moveToFront", 0, NativeCompMoveToFront), TJS_CFUNC_DEF("moveToBackground", 0, NativeCompMoveToBackground), TJS_CFUNC_DEF("scrollIntoView", 0, NativeCompScrollIntoView), + TJS_CFUNC_DEF("focus", 0, NativeCompFocus), TJS_CFUNC_DEF("close", 0, NativeCompCloseComponent), TJS_CFUNC_DEF("setInGroupType", 1, NativeCompSetInGroupType), }; diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index b328375ba..aa0586468 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -62,6 +62,16 @@ void BasicComponent::appendChild (void* child) { }; +void BasicComponent::focus () { + if (!this->instance) return; + lv_group_t* def_group = lv_group_get_default(); + if (def_group) { + lv_group_focus_obj(this->instance); + } else { + lv_obj_add_state(this->instance, LV_STATE_FOCUSED); + } +} + void BasicComponent::initCompStyle (int32_t type) { }; diff --git a/src/render/native/core/basic/comp.hpp b/src/render/native/core/basic/comp.hpp index cc96f0180..672c83bc4 100644 --- a/src/render/native/core/basic/comp.hpp +++ b/src/render/native/core/basic/comp.hpp @@ -84,6 +84,7 @@ class BasicComponent { void moveToFront (); void moveToBackground (); void scrollIntoView (); + void focus (); void setAlign (int32_t align_type, int32_t x, int32_t y); void setAlignTo (int32_t align_type, int32_t x, int32_t y, BasicComponent* parent); From ae96c38a4c0dc6a88339b857a9395035b5b0843b Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 16 Jan 2026 19:43:57 +0800 Subject: [PATCH 16/62] feat: update component registration to support refs - Refactored component registration to use registerWithRef for improved ref handling. - Updated the View, Text, Image, Button, and other components to utilize the new registration method. - Simplified the ref assignment in the Page1List component for better readability and functionality. --- demo/navigation/index.tsx | 2 +- src/render/react/index.ts | 42 +++++++++++++++++++-------------------- src/render/react/ref.ts | 14 +++++++++++++ 3 files changed, 36 insertions(+), 22 deletions(-) create mode 100644 src/render/react/ref.ts diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 027b116e7..5709468e3 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -57,7 +57,7 @@ function Page1List({ onBack }: { onBack: () => void }) { {items.map((n) => ( (firstItemRef.current = ins) : undefined } as any)} + ref={n === 1 ? firstItemRef : undefined} onFocusedStyle={style.focused} style={style.listRow} onClick={() => { diff --git a/src/render/react/index.ts b/src/render/react/index.ts index bf0f689af..0305e7313 100644 --- a/src/render/react/index.ts +++ b/src/render/react/index.ts @@ -40,30 +40,30 @@ import { TextareaComp, TextAreaProps } from "./components/Textarea/comp"; import TextareaConfig from "./components/Textarea/config"; import { ViewComp, ViewProps } from "./components/View/comp"; import ViewConfig from "./components/View/config"; -import { registerComponent } from "./components/config"; import { Renderer } from "./core/renderer"; +import { registerWithRef } from "./ref"; -export const View = registerComponent(new ViewConfig()); +export const View = registerWithRef(new ViewConfig()); // export const Window = registerComponent(new WindowConfig()); -export const Text = registerComponent(new TextConfig()); -export const Image = registerComponent(new ImageConfig()); -export const Button = registerComponent(new ButtonConfig()); -export const Slider = registerComponent(new SliderConfig()); -export const Arc = registerComponent(new ArcConfig()); -export const Switch = registerComponent(new SwitchConfig()); -export const Textarea = registerComponent(new TextareaConfig()); -export const Input = registerComponent(new InputConfig()); -export const Keyboard = registerComponent(new KeyboardConfig()); -export const Checkbox = registerComponent(new CheckboxConfig()); -export const Dropdownlist = registerComponent(new DropdownlistConfig()); -export const ProgressBar = registerComponent(new ProgressBarConfig()); -export const Roller = registerComponent(new RollerConfig()); -export const Line = registerComponent(new LineConfig()); -export const Calendar = registerComponent(new CalendarConfig()); -export const GIF = registerComponent(new GIFConfig()); -export const Tabs = registerComponent(new TabsConfig()); -export const Chart = registerComponent(new ChartConfig()); -export const Mask = registerComponent(new MaskConfig()); +export const Text = registerWithRef(new TextConfig()); +export const Image = registerWithRef(new ImageConfig()); +export const Button = registerWithRef(new ButtonConfig()); +export const Slider = registerWithRef(new SliderConfig()); +export const Arc = registerWithRef(new ArcConfig()); +export const Switch = registerWithRef(new SwitchConfig()); +export const Textarea = registerWithRef(new TextareaConfig()); +export const Input = registerWithRef(new InputConfig()); +export const Keyboard = registerWithRef(new KeyboardConfig()); +export const Checkbox = registerWithRef(new CheckboxConfig()); +export const Dropdownlist = registerWithRef(new DropdownlistConfig()); +export const ProgressBar = registerWithRef(new ProgressBarConfig()); +export const Roller = registerWithRef(new RollerConfig()); +export const Line = registerWithRef(new LineConfig()); +export const Calendar = registerWithRef(new CalendarConfig()); +export const GIF = registerWithRef(new GIFConfig()); +export const Tabs = registerWithRef(new TabsConfig()); +export const Chart = registerWithRef(new ChartConfig()); +export const Mask = registerWithRef(new MaskConfig()); export { EAlignType, diff --git a/src/render/react/ref.ts b/src/render/react/ref.ts new file mode 100644 index 000000000..65e4daa3c --- /dev/null +++ b/src/render/react/ref.ts @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LvgljsComponentConfig, registerComponent } from "./components/config"; + +export type WithRef = React.ForwardRefExoticComponent< + React.PropsWithoutRef & React.RefAttributes +>; + +/** + * Type-only helper: declare that a host component supports `ref` to its public instance. + * Runtime behavior is unchanged; reconciler already supports refs via `getPublicInstance`. + */ +export function registerWithRef(config: LvgljsComponentConfig): WithRef { + return registerComponent(config) as unknown as WithRef; +} From 853264133286002cea459fd954a33e55d99abac6 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 16 Jan 2026 19:44:18 +0800 Subject: [PATCH 17/62] feat: enhance ViewPager component with debugging features and style updates --- demo/viewpager/index.tsx | 36 +++++++++++++++++---- package.json | 2 +- src/render/react/components/common/index.ts | 9 ++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/demo/viewpager/index.tsx b/demo/viewpager/index.tsx index 649f6c15e..451b4b3bc 100644 --- a/demo/viewpager/index.tsx +++ b/demo/viewpager/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; -import { Button, Dimensions, Render, Text, View } from "lvgljs-ui"; +import { AddChildToDefGroup, Button, Dimensions, Render, Text, View } from "lvgljs-ui"; const { width, height } = Dimensions.window; @@ -16,6 +16,7 @@ function App() { const pageRefs = useRef([]); const [active, setActive] = useState(0); + const [debug, setDebug] = useState(""); const pageColors = useMemo( () => ["red", "blue", "green", "orange"], @@ -23,15 +24,19 @@ function App() { ); const scrollTo = (idx: number) => { - const n = Math.max(0, Math.min(pageCount - 1, idx)); - setActive(n); + if (idx < 0 || idx >= pageCount) return; + setActive(idx); // 让对应 page 滚动进可视区域(LVGL 内部会按 snap 对齐) - pageRefs.current[n]?.scrollIntoView?.(); + const target = pageRefs.current[idx]; + const left = target?.style?.left; + target?.scrollIntoView?.(); + const lefts = pageRefs.current.map((p) => p?.style?.left); + setDebug(JSON.stringify({ idx, hasRef: !!target, left, lefts })); }; useEffect(() => { // 初始定位到第 0 页 - scrollTo(2); + scrollTo(0); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -43,6 +48,7 @@ function App() { > {Array.from({ length: pageCount }).map((_, i) => ( (pageRefs.current[i] = ins)} style={[ @@ -85,6 +91,10 @@ function App() { {">"} + + + {debug} + ); } @@ -115,7 +125,7 @@ const style: Record = { "overflow-scrolling": 1, // 开启 X 方向 snap(枚举值见 LV_SCROLL_SNAP_*) - "scroll-snap-x": 2, // 通常 2=LV_SCROLL_SNAP_CENTER(不同版本可能略有差异;看效果不对再调) + "scroll-snap-x": 3, // LV_SCROLL_SNAP_CENTER(本仓库 lvgl: NONE=0 START=1 END=2 CENTER=3) }, // 每一页:固定为一屏大小,并允许被 snap @@ -171,9 +181,21 @@ const style: Record = { opacity: 255, }, dotInactive: { - "background-color": "white", + "background-color": "grey", opacity: 80, }, + pageFocused: { + "background-color": "white", + opacity: 255, + }, + debugBar: { + width, + height: 40, + "background-color": "black", + }, + debugText: { + "text-color": "white", + }, }; Render.render(); diff --git a/package.json b/package.json index c833cb268..c6c34cf8c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "sim": "./build/lvgljs run", "sim:watch": "nodemon --watch 'demo/**/*.js' --ext 'js' --exec 'npm run sim'", "bundle": "node ./build.js", - "bundle:watch": "nodemon --watch 'demo/**/*.jsx' --watch 'test/**/*.jsx' --ext 'jsx' --exec 'npm run bundle'", + "bundle:watch": "nodemon --watch 'demo/**/*.jsx' --watch 'demo/**/*.tsx' --watch 'test/**/*.jsx' --watch 'test/**/*.tsx' --ext 'jsx,tsx' --exec 'npm run bundle'", "fmt": "prettier -w src/render/react" }, "dependencies": { diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index abbf95fd4..78c121234 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -56,6 +56,11 @@ export type CommonProps = { currentTarget: any, stopPropogation: () => void, }) => void; + onCancel?: (event: { + target: any, + currentTarget: any, + stopPropogation: () => void, + }) => void; onFocusedStyle?: StyleProps; }; @@ -64,6 +69,7 @@ export type OnChangeEvent = { currentTarget: any, stopPropogation: () => void, value: number, + checked?: boolean, } export type OnClickEvent = { @@ -163,6 +169,9 @@ export const CommonComponentApi = function ({ onReleased(fn) { handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_RELEASED); }, + onCancel(fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CANCEL); + }, onFocusedStyle(styleSheet) { setStyle({ comp, From 18af2f30d4b1ce87dcb55a8df602a68e5373b1f7 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 16 Jan 2026 20:34:48 +0800 Subject: [PATCH 18/62] feat: update React dependencies and enhance reconciler functionality - Upgraded React to version 16.14.0 and ensured consistent versioning for react-reconciler. - Refactored instance management in the reconciler to use Map for better performance and reliability. - Added cleanupInstance function to handle child component destruction and prevent memory leaks. - Introduced RootContainer class to manage child components with stable ordering semantics. - Improved text handling in the reconciler to support props for Text components. --- package.json | 4 +- src/render/react/core/reconciler/index.js | 64 ++++++++++++++--------- src/render/react/core/renderer/index.js | 29 +++++++++- 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index c6c34cf8c..d3f50b276 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,9 @@ "fetch-blob": "^3.2.0", "nodemon": "^3.1.4", "lvgljs-ui": "file:src/render/react", - "react": "^16.13.1", + "react": "16.14.0", "react-proxy": "^2.0.8", - "react-reconciler": "^0.25.1", + "react-reconciler": "0.25.1", "react-router": "^6.3.0", "text-encoding": "^0.7.0", "urlpattern-polyfill": "^5.0.3", diff --git a/src/render/react/core/reconciler/index.js b/src/render/react/core/reconciler/index.js index 0bdda5777..7b0a190bb 100644 --- a/src/render/react/core/reconciler/index.js +++ b/src/render/react/core/reconciler/index.js @@ -11,7 +11,23 @@ export const getUid = () => { const instanceMap = new Map(); export const getInstance = (uid) => { - return instanceMap[uid]; + return instanceMap.get(uid); +}; + +const cleanupInstance = (child, { destroy } = { destroy: false }) => { + if (!child) return; + const uid = child.uid; + if (uid) { + unRegistEvent(uid); + instanceMap.delete(uid); + } + // IMPORTANT: + // For nested children, the native `parent.removeChild(child)` implementation may already + // delete/detach the underlying LVGL object. Calling `child.close()` again can double-free/hang. + // Only destroy on root-container removal where we own the lifetime explicitly. + if (destroy && child.close) { + child.close(); + } }; const HostConfig = { @@ -32,10 +48,15 @@ const HostConfig = { return {}; }, shouldSetTextContent: function (type, props) { + // Keep text as a prop for our `Text` host component, not as separate text children. + if (type === "Text") { + const c = props?.children; + if (typeof c === "string" || typeof c === "number") return true; + if (Array.isArray(c)) { + return c.every((x) => typeof x === "string" || typeof x === "number"); + } + } return false; - return ( - typeof props.children === "string" || typeof props.children === "number" - ); }, createInstance: ( type, @@ -53,7 +74,7 @@ const HostConfig = { workInProgress, uid, ); - instanceMap[uid] = instance; + instanceMap.set(uid, instance); return instance; }, createTextInstance: ( @@ -62,19 +83,17 @@ const HostConfig = { context, workInProgress, ) => { - return null; - // const { createInstance } = getComponentByTagName('Text'); - // const uid = getUid() - - // return createInstance( - // { - // text - // }, - // rootContainerInstance, - // context, - // workInProgress, - // uid - // ); + const { createInstance } = getComponentByTagName("Text"); + const uid = getUid(); + const instance = createInstance( + { children: text }, + rootContainerInstance, + context, + workInProgress, + uid, + ); + instanceMap.set(uid, instance); + return instance; }, appendInitialChild: (parent, child) => { parent.appendChild(child); @@ -93,13 +112,11 @@ const HostConfig = { container.add(child); }, insertInContainerBefore: (container, child, beforeChild) => { - container.add(child); + container.insertBefore(child, beforeChild); }, removeChildFromContainer: (container, child) => { container.delete(child); - if (child.close) { - child.close(); - } + cleanupInstance(child, { destroy: true }); }, prepareUpdate(instance, oldProps, newProps) { return true; @@ -126,8 +143,7 @@ const HostConfig = { }, removeChild(parent, child) { parent?.removeChild(child); - unRegistEvent(child.uid); - delete instanceMap[child.uid]; + cleanupInstance(child, { destroy: false }); }, commitMount: function (instance, type, newProps, internalInstanceHandle) { const { commitMount } = getComponentByTagName(type); diff --git a/src/render/react/core/renderer/index.js b/src/render/react/core/renderer/index.js index 2af1851a9..50f24995c 100644 --- a/src/render/react/core/renderer/index.js +++ b/src/render/react/core/renderer/index.js @@ -1,14 +1,39 @@ import reconciler from "../reconciler"; -const containerInfo = new Set(); +class RootContainer { + constructor() { + this.children = []; + } + add(child) { + const idx = this.children.indexOf(child); + if (idx === -1) this.children.push(child); + } + insertBefore(child, beforeChild) { + // Ensure stable ordering semantics for reconciler + const curIdx = this.children.indexOf(child); + if (curIdx !== -1) this.children.splice(curIdx, 1); + + const beforeIdx = this.children.indexOf(beforeChild); + if (beforeIdx === -1) { + this.children.push(child); + } else { + this.children.splice(beforeIdx, 0, child); + } + } + delete(child) { + const idx = this.children.indexOf(child); + if (idx !== -1) this.children.splice(idx, 1); + } +} export class Renderer { static container; static portalContainer; static render(element, options) { - const isConcurrent = true; + const isConcurrent = false; const hydrate = false; + const containerInfo = new RootContainer(); Renderer.container = reconciler.createContainer( containerInfo, From 559ebbb9896c6bc5c93f8ec72110e2b2cfffd933 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 16 Jan 2026 20:57:54 +0800 Subject: [PATCH 19/62] feat: implement internationalization support in navigation demo - Added i18n functionality to the navigation demo, allowing for language switching between English and Chinese. - Integrated translation keys for all text elements across the demo pages. - Created separate JSON files for English and Chinese translations. - Introduced a LangSwitcher component for selecting the language. - Updated the App component to use I18nProvider for managing localization context. --- demo/navigation/i18n/en.json | 46 +++++++++++ demo/navigation/i18n/zh.json | 46 +++++++++++ demo/navigation/index.tsx | 144 +++++++++++++++++++++++++-------- src/render/react/i18n/index.ts | 104 ++++++++++++++++++++++++ src/render/react/index.ts | 2 + 5 files changed, 308 insertions(+), 34 deletions(-) create mode 100644 demo/navigation/i18n/en.json create mode 100644 demo/navigation/i18n/zh.json create mode 100644 src/render/react/i18n/index.ts diff --git a/demo/navigation/i18n/en.json b/demo/navigation/i18n/en.json new file mode 100644 index 000000000..f34dddf72 --- /dev/null +++ b/demo/navigation/i18n/en.json @@ -0,0 +1,46 @@ +{ + "nav": { + "title": "Navigation Demo (5 Pages)", + "subTitle": "Four-grid to enter sub-pages, top-left return", + "page1": "Page 1", + "page2": "Page 2", + "page3": "Page 3", + "page4": "Page 4", + "lang": "Lang" + }, + "header": { + "back": "<" + }, + "p1": { + "title": "Page 1 - Vertical Scrollable List", + "item": "Item {n}" + }, + "p2": { + "title": "Page 2 - Info Display/Switch", + "prev": "<", + "next": ">", + "a": { "title": "Info A", "body": "This is the first section of info (for demo switching)." }, + "b": { "title": "Info B", "body": "This is the second section. Use Left/Right to switch." }, + "c": { "title": "Info C", "body": "This is the third section. Dots indicate the current page." }, + "d": { "title": "Info D", "body": "This is the fourth section. A simple info page example." }, + "e": { "title": "Info E", "body": "This is the fifth section. Switching loops around." } + }, + "p3": { + "title": "Page 3 - Control List", + "slider": "Slider", + "currentValue": "Current Value: {value}%", + "checkbox": "Checkbox", + "option1": "Option 1", + "option2": "Option 2", + "buttonText": "Button + Text", + "reset": "Reset to Default", + "hint": "Hint: This page's controls are vertically arranged, and the container is scrollable.\nAll operable controls are marked with groupType." + }, + "p4": { + "title": "Page 4 - 60s Countdown Progress Circle (Circular Progress Bar)", + "time": "time{remain}s", + "restart": "Restart" + } +} + + diff --git a/demo/navigation/i18n/zh.json b/demo/navigation/i18n/zh.json new file mode 100644 index 000000000..bdaef4ed8 --- /dev/null +++ b/demo/navigation/i18n/zh.json @@ -0,0 +1,46 @@ +{ + "nav": { + "title": "导航演示(5 页)", + "subTitle": "四宫格进入子页面,左上角返回", + "page1": "页面 1", + "page2": "页面 2", + "page3": "页面 3", + "page4": "页面 4", + "lang": "语言" + }, + "header": { + "back": "<" + }, + "p1": { + "title": "页面 1 - 纵向可滚动列表", + "item": "条目 {n}" + }, + "p2": { + "title": "页面 2 - 信息展示/切换", + "prev": "<", + "next": ">", + "a": { "title": "信息 A", "body": "这是第一段信息(用于演示切换)。" }, + "b": { "title": "信息 B", "body": "这是第二段信息。使用左右切换。" }, + "c": { "title": "信息 C", "body": "这是第三段信息。圆点表示当前页。" }, + "d": { "title": "信息 D", "body": "这是第四段信息。一个简单的信息页示例。" }, + "e": { "title": "信息 E", "body": "这是第五段信息。切换会循环。" } + }, + "p3": { + "title": "页面 3 - 控件列表", + "slider": "滑块", + "currentValue": "当前值:{value}%", + "checkbox": "复选框", + "option1": "选项 1", + "option2": "选项 2", + "buttonText": "按钮 + 文本", + "reset": "恢复默认", + "hint": "提示:本页控件纵向排列,容器可滚动。\n所有可操作控件都标记了 groupType。" + }, + "p4": { + "title": "页面 4 - 60 秒倒计时进度圆环(圆形进度条)", + "time": "剩余{remain}秒", + "restart": "重新开始" + } +} + + diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 5709468e3..0c8a22342 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -5,9 +5,12 @@ import { Button, Checkbox, Dimensions, + I18nProvider, Render, Slider, Text, + useI18n, + useT, View, } from "lvgljs-ui"; import { useAutoFocus } from "./useAutoFocus"; @@ -16,6 +19,12 @@ const { width, height } = Dimensions.window; type Page = "home" | "p1" | "p2" | "p3" | "p4"; +declare const require: any; +const messages = { + en: require("./i18n/en.json"), + zh: require("./i18n/zh.json"), +}; + function Header({ title, onBack, @@ -25,6 +34,7 @@ function Header({ onBack: () => void; autoFocusBack?: boolean; }) { + const t = useT(); const backRef = useRef(null); useAutoFocus(backRef, [autoFocusBack]); @@ -36,7 +46,7 @@ function Header({ onFocusedStyle={style.focused} onClick={onBack} > - {"<"} + {t("header.back")} {title} @@ -44,13 +54,14 @@ function Header({ } function Page1List({ onBack }: { onBack: () => void }) { + const t = useT(); const items = useMemo(() => Array.from({ length: 40 }).map((_, i) => i + 1), []); const firstItemRef = useRef(null); useAutoFocus(firstItemRef, []); return ( -
+
@@ -64,7 +75,7 @@ function Page1List({ onBack }: { onBack: () => void }) { // no-op (demo) }} > - {`Item ${n}`} + {t("p1.item", { n })} ))} @@ -74,13 +85,14 @@ function Page1List({ onBack }: { onBack: () => void }) { } function Page2Info({ onBack }: { onBack: () => void }) { + const t = useT(); const infos = useMemo( () => [ - { title: "Info A", body: "This is the first section of info (for demo switching)." }, - { title: "Info B", body: "This is the second section. Use Left/Right to switch." }, - { title: "Info C", body: "This is the third section. Dots indicate the current page." }, - { title: "Info D", body: "This is the fourth section. A simple info page example." }, - { title: "Info E", body: "This is the fifth section. Switching loops around." }, + { titleKey: "p2.a.title", bodyKey: "p2.a.body" }, + { titleKey: "p2.b.title", bodyKey: "p2.b.body" }, + { titleKey: "p2.c.title", bodyKey: "p2.c.body" }, + { titleKey: "p2.d.title", bodyKey: "p2.d.body" }, + { titleKey: "p2.e.title", bodyKey: "p2.e.body" }, ], [], ); @@ -92,12 +104,12 @@ function Page2Info({ onBack }: { onBack: () => void }) { const next = () => setIdx((i) => (i + 1) % infos.length); return ( -
+
- {cur.title} - {cur.body} + {t(cur.titleKey)} + {t(cur.bodyKey)} @@ -106,7 +118,7 @@ function Page2Info({ onBack }: { onBack: () => void }) { onFocusedStyle={style.focused} onClick={prev} > - {"<"} + {t("p2.prev")} @@ -132,16 +144,17 @@ function Page2Info({ onBack }: { onBack: () => void }) { } function Page3Controls({ onBack }: { onBack: () => void }) { + const t = useT(); const [slider, setSlider] = useState(30); const [checked1, setChecked1] = useState(false); const [checked2, setChecked2] = useState(true); return ( -
+
- Slider + {t("p3.slider")} void }) { value={slider} onChange={(e) => setSlider(e.value)} /> - {`Current Value: ${Math.round(slider)}%`} + + {t("p3.currentValue", { value: Math.round(slider) })} + - Checkbox + {t("p3.checkbox")} setChecked1(!!e.checked)} /> setChecked2(!!e.checked)} /> - Button + Text + {t("p3.buttonText")} - - {`Hint: This page's controls are vertically arranged, and the container is scrollable.\nAll operable controls are marked with groupType.`} - + {t("p3.hint")} @@ -193,6 +206,7 @@ function Page3Controls({ onBack }: { onBack: () => void }) { } function Page4Countdown({ onBack }: { onBack: () => void }) { + const t = useT(); const total = 60; const [remain, setRemain] = useState(total); @@ -208,7 +222,7 @@ function Page4Countdown({ onBack }: { onBack: () => void }) { const angle = Math.floor((elapsed / total) * 360); return ( -
+
void }) { // keep non-interactive for this demo }} /> - {`time${remain}s`} + {t("p4.time", { remain })} ); } +function LangSwitcher() { + const t = useT(); + const { locale, setLocale } = useI18n(); + return ( + + {t("nav.lang")} + + + + ); +} + function Home({ go }: { go: (p: Page) => void }) { + const t = useT(); const btnW = Math.floor((width - 24 * 2 - 12) / 2); const btnH = 72; return ( - Navigation Demo (5 Pages) - Four-grid to enter sub-pages, top-left return + {t("nav.title")} + {t("nav.subTitle")} + @@ -258,28 +302,28 @@ function Home({ go }: { go: (p: Page) => void }) { onFocusedStyle={style.focused} onClick={() => go("p1")} > - Page 1 + {t("nav.page1")} @@ -297,6 +341,14 @@ function App() { return ; } +function Root() { + return ( + + + + ); +} + const style: Record = { pageRoot: { width, @@ -484,6 +536,30 @@ const style: Record = { }, homeTitle: { "text-color": "white", "font-size": 20 }, homeSubTitle: { "text-color": "0xb0b0b0", "font-size": 12, "padding-top": 6 }, + langBar: { + width: "100%", + height: 32, + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "flex-start", + margin: "10px 0 0 0", + }, + langLabel: { "text-color": "0xb0b0b0", "font-size": 12, padding: "0 8px 0 0" }, + langBtn: { + width: 56, + height: 26, + "border-radius": 10, + margin: "0 8px 0 0", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + langBtnActive: { "background-color": "white" }, + langBtnInactive: { "background-color": "0x1d1d1d" }, + langBtnText: { "font-size": 12 }, + langBtnTextActive: { "text-color": "black" }, + langBtnTextInactive: { "text-color": "white" }, homeGrid: { width, height: height - 100, @@ -505,6 +581,6 @@ const style: Record = { homeBtnText: { "text-color": "white", "font-size": 16 }, }; -Render.render(); +Render.render(); diff --git a/src/render/react/i18n/index.ts b/src/render/react/i18n/index.ts new file mode 100644 index 000000000..01aa325cc --- /dev/null +++ b/src/render/react/i18n/index.ts @@ -0,0 +1,104 @@ +import * as React from "react"; + +export type I18nVars = Record; +export type I18nLocale = string; + +export interface I18nMessages { + [key: string]: string | I18nMessages; +} + +export type I18nAllMessages = Record; + +function getByPath(messages: I18nMessages | undefined, key: string): string | undefined { + if (!messages) return; + const parts = key.split("."); + let cur: any = messages; + for (const p of parts) { + if (!cur || typeof cur !== "object") return; + cur = cur[p]; + } + return typeof cur === "string" ? cur : undefined; +} + +function format(template: string, vars?: I18nVars): string { + if (!vars) return template; + return template.replace(/\{(\w+)\}/g, (_, k) => { + const v = vars[k]; + if (v === null || v === undefined) return ""; + return String(v); + }); +} + +export type TranslateFn = (key: string, vars?: I18nVars) => string; + +export type I18nContextValue = { + locale: I18nLocale; + fallbackLocale?: I18nLocale; + setLocale: (locale: I18nLocale) => void; + t: TranslateFn; +}; + +const I18nContext = React.createContext(null); + +export function I18nProvider({ + children, + messages, + defaultLocale = "en", + locale: controlledLocale, + fallbackLocale, + onMissingKey, +}: { + children: React.ReactNode; + messages: I18nAllMessages; + defaultLocale?: I18nLocale; + locale?: I18nLocale; + fallbackLocale?: I18nLocale; + onMissingKey?: (key: string, info: { locale: string; fallbackLocale?: string }) => void; +}) { + const [uncontrolledLocale, setUncontrolledLocale] = React.useState(defaultLocale); + const locale = controlledLocale ?? uncontrolledLocale; + const setLocale = React.useCallback( + (next: I18nLocale) => { + if (controlledLocale === undefined) setUncontrolledLocale(next); + }, + [controlledLocale], + ); + + const t: TranslateFn = React.useCallback( + (key: string, vars?: I18nVars) => { + const msg = + getByPath(messages?.[locale], key) ?? + (fallbackLocale ? getByPath(messages?.[fallbackLocale], key) : undefined); + if (msg === undefined) { + onMissingKey?.(key, { locale, fallbackLocale }); + return key; + } + return format(msg, vars); + }, + [messages, locale, fallbackLocale, onMissingKey], + ); + + const value = React.useMemo( + () => ({ + locale, + fallbackLocale, + setLocale, + t, + }), + [locale, fallbackLocale, setLocale, t], + ); + + return React.createElement(I18nContext.Provider, { value }, children); +} + +export function useI18n(): I18nContextValue { + const ctx = React.useContext(I18nContext); + if (!ctx) throw new Error("useI18n must be used within "); + return ctx; +} + +export function useT(): TranslateFn { + return useI18n().t; +} + + diff --git a/src/render/react/index.ts b/src/render/react/index.ts index 0305e7313..8e3303d3e 100644 --- a/src/render/react/index.ts +++ b/src/render/react/index.ts @@ -42,6 +42,8 @@ import { ViewComp, ViewProps } from "./components/View/comp"; import ViewConfig from "./components/View/config"; import { Renderer } from "./core/renderer"; import { registerWithRef } from "./ref"; +export { I18nProvider, useI18n, useT } from "./i18n"; +export type { I18nAllMessages, I18nLocale, I18nMessages, I18nVars, TranslateFn } from "./i18n"; export const View = registerWithRef(new ViewConfig()); // export const Window = registerComponent(new WindowConfig()); From e37d2700af3e67f28f9349c6dcb94d88af6cd2c3 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Sun, 18 Jan 2026 22:31:35 +0800 Subject: [PATCH 20/62] fix: update i18n message handling and improve localization performance - Refactored the messages handling in the I18nProvider to support dynamic loading of locale-specific messages. - Introduced caching for loaded messages to enhance performance and reduce redundant loading. - Updated the navigation demo to utilize the new message loading mechanism, ensuring proper fallback handling for translations. - Adjusted type definitions for better clarity and maintainability in the i18n module. --- demo/navigation/index.tsx | 8 +++---- package-lock.json | 14 +++++------- src/render/react/i18n/index.ts | 39 ++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 0c8a22342..37f1fdafc 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -20,9 +20,9 @@ const { width, height } = Dimensions.window; type Page = "home" | "p1" | "p2" | "p3" | "p4"; declare const require: any; -const messages = { - en: require("./i18n/en.json"), - zh: require("./i18n/zh.json"), +const messages = (locale: string) => { + if (locale === "zh") return require("./i18n/zh.json"); + return require("./i18n/en.json"); }; function Header({ @@ -343,7 +343,7 @@ function App() { function Root() { return ( - + ); diff --git a/package-lock.json b/package-lock.json index f851b4fc8..de39cb098 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,9 @@ "fetch-blob": "^3.2.0", "lvgljs-ui": "file:src/render/react", "nodemon": "^3.1.4", - "react": "^16.13.1", + "react": "16.14.0", "react-proxy": "^2.0.8", - "react-reconciler": "^0.25.1", + "react-reconciler": "0.25.1", "react-router": "^6.3.0", "text-encoding": "^0.7.0", "urlpattern-polyfill": "^5.0.3", @@ -2319,8 +2319,9 @@ } }, "node_modules/lvgljs-ui": { - "resolved": "src/render/react", - "link": true + "version": "0.0.1", + "resolved": "file:src/render/react", + "license": "ISC" }, "node_modules/media-typer": { "version": "0.3.0", @@ -4115,11 +4116,6 @@ "optional": true } } - }, - "src/render/react": { - "name": "lvgljs-ui", - "version": "0.0.1", - "license": "ISC" } } } diff --git a/src/render/react/i18n/index.ts b/src/render/react/i18n/index.ts index 01aa325cc..9aaf73189 100644 --- a/src/render/react/i18n/index.ts +++ b/src/render/react/i18n/index.ts @@ -8,6 +8,12 @@ export interface I18nMessages { } export type I18nAllMessages = Record; +export type I18nMessagesLoader = (locale: I18nLocale) => I18nMessages | undefined; +export type I18nMessagesSource = I18nAllMessages | I18nMessagesLoader; + +function isMessagesLoader(x: I18nMessagesSource): x is I18nMessagesLoader { + return typeof x === "function"; +} function getByPath(messages: I18nMessages | undefined, key: string): string | undefined { if (!messages) return; @@ -49,7 +55,7 @@ export function I18nProvider({ onMissingKey, }: { children: React.ReactNode; - messages: I18nAllMessages; + messages: I18nMessagesSource; defaultLocale?: I18nLocale; locale?: I18nLocale; fallbackLocale?: I18nLocale; @@ -64,18 +70,43 @@ export function I18nProvider({ [controlledLocale], ); + const loaderCacheRef = React.useRef>(new Map()); + + const getMessagesForLocale = React.useCallback( + (loc: I18nLocale): I18nMessages | undefined => { + if (!isMessagesLoader(messages)) return (messages as I18nAllMessages)?.[loc]; + + const cached = loaderCacheRef.current.get(loc); + if (cached) return cached; + const loaded = messages(loc); + if (loaded) loaderCacheRef.current.set(loc, loaded); + return loaded; + }, + [messages], + ); + + React.useEffect(() => { + if (!isMessagesLoader(messages)) return; + + const keep = new Set([locale]); + if (fallbackLocale) keep.add(fallbackLocale); + for (const k of loaderCacheRef.current.keys()) { + if (!keep.has(k)) loaderCacheRef.current.delete(k); + } + }, [messages, locale, fallbackLocale]); + const t: TranslateFn = React.useCallback( (key: string, vars?: I18nVars) => { const msg = - getByPath(messages?.[locale], key) ?? - (fallbackLocale ? getByPath(messages?.[fallbackLocale], key) : undefined); + getByPath(getMessagesForLocale(locale), key) ?? + (fallbackLocale ? getByPath(getMessagesForLocale(fallbackLocale), key) : undefined); if (msg === undefined) { onMissingKey?.(key, { locale, fallbackLocale }); return key; } return format(msg, vars); }, - [messages, locale, fallbackLocale, onMissingKey], + [getMessagesForLocale, locale, fallbackLocale, onMissingKey], ); const value = React.useMemo( From 68245747a7b5a2458ac7b3ba17423cee728cc210 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 19 Jan 2026 19:29:03 +0800 Subject: [PATCH 21/62] feat: upgrade React and related dependencies, enhance component finalization - Updated React to version 18.3.1 and react-reconciler to version 0.29.2 for improved performance and features. - Refactored component finalization methods to ensure proper cleanup and memory management, including logging during component destruction. - Enhanced the cleanup process in the reconciler to prevent potential memory leaks by managing child instances more effectively. - Updated type definitions for better clarity and maintainability in the React integration. --- package-lock.json | 3295 +++++++++++------ package.json | 6 +- src/render/native/components/arc/arc_wrap.cpp | 3 +- .../native/components/button/button_wrap.cpp | 3 +- .../components/calendar/calendar_wrap.cpp | 3 +- .../native/components/chart/chart_wrap.cpp | 3 +- .../components/checkbox/checkbox_wrap.cpp | 3 +- src/render/native/components/component.hpp | 5 +- .../dropdownlist/dropdownlist_wrap.cpp | 3 +- src/render/native/components/gif/gif_wrap.cpp | 3 +- .../native/components/image/image_wrap.cpp | 3 +- .../components/keyboard/keyboard_wrap.cpp | 3 +- .../native/components/line/line_wrap.cpp | 3 +- .../native/components/list/list_wrap.cpp | 3 +- .../native/components/mask/mask_wrap.cpp | 3 +- .../progressbar/progressbar_wrap.cpp | 3 +- .../native/components/roller/roller_wrap.cpp | 3 +- .../native/components/slider/slider_wrap.cpp | 3 +- .../native/components/switch/switch_wrap.cpp | 3 +- .../components/tabview/tabview_wrap.cpp | 3 +- .../native/components/text/text_wrap.cpp | 3 +- .../components/textarea/textarea_wrap.cpp | 3 +- .../native/components/view/view_wrap.cpp | 3 +- .../native/components/window/window_wrap.cpp | 3 +- src/render/native/core/basic/comp.cpp | 19 +- src/render/react/core/reconciler/index.js | 112 +- src/render/react/core/renderer/index.js | 15 +- 27 files changed, 2269 insertions(+), 1246 deletions(-) diff --git a/package-lock.json b/package-lock.json index de39cb098..373ddaf34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,9 @@ "fetch-blob": "^3.2.0", "lvgljs-ui": "file:src/render/react", "nodemon": "^3.1.4", - "react": "16.14.0", + "react": "18.3.1", "react-proxy": "^2.0.8", - "react-reconciler": "0.25.1", + "react-reconciler": "0.29.2", "react-router": "^6.3.0", "text-encoding": "^0.7.0", "urlpattern-polyfill": "^5.0.3", @@ -30,7 +30,7 @@ "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@txikijs/types": "^24.6.0", - "@types/react": "^16.3.1", + "@types/react": "^18.3.0", "@types/react-reconciler": "^0.18.0", "esbuild-plugin-alias": "^0.2.1", "glob": "^10.3.15", @@ -38,11 +38,15 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -50,6 +54,8 @@ }, "node_modules/@babel/generator": { "version": "7.17.7", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "dev": true, "license": "MIT", "dependencies": { @@ -61,97 +67,119 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", + "node_modules/@babel/helper-environment-visitor/node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.22.5", + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.22.5", + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.22.5", + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -159,76 +187,89 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.22.5", + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.0.0" } }, - "node_modules/@babel/parser": { - "version": "7.22.7", + "node_modules/@babel/parser/node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.22.5", + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.22.5", + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.17.3", + "version": "7.23.2", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -236,29 +277,54 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.4", + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=6.0" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", + "node_modules/@babel/traverse/node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, - "license": "MIT" + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } }, "node_modules/@babel/types": { "version": "7.17.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dev": true, "license": "MIT", "dependencies": { @@ -269,8 +335,26 @@ "node": ">=6.9.0" } }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", + "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { @@ -286,57 +370,60 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", + "version": "0.3.11", + "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "license": "MIT" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", "optional": true, @@ -345,20 +432,24 @@ } }, "node_modules/@remix-run/router": { - "version": "1.16.1", + "version": "1.23.2", + "resolved": "https://registry.npmmirror.com/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "4.2.0", + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz", + "integrity": "sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@babel/generator": "7.17.7", "@babel/parser": "^7.20.5", - "@babel/traverse": "7.17.3", + "@babel/traverse": "7.23.2", "@babel/types": "7.17.0", "javascript-natural-sort": "0.7.1", "lodash": "^4.17.21" @@ -374,14 +465,16 @@ } }, "node_modules/@txikijs/types": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/@txikijs/types/-/types-24.6.0.tgz", - "integrity": "sha512-BKQvQCUddJBVlAnBxdaaMpBhGKYUaaZVboRwasH6x8TMwMNOrRm+gHywUqLopHXLmIBevECg5L3pAjT2wS+iMg==", + "version": "24.12.0", + "resolved": "https://registry.npmmirror.com/@txikijs/types/-/types-24.12.0.tgz", + "integrity": "sha512-NllY8bX3sn2PLx83QlNuKpWNqbPXWEZk8Uwh4E0fhe0hGHiBzFemXb9KS0wq3ymfzyiOKOT5YohKf8+z60HCdg==", "dev": true, "license": "MIT" }, "node_modules/@types/body-parser": { - "version": "1.19.2", + "version": "1.19.6", + "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "license": "MIT", "dependencies": { "@types/connect": "*", @@ -389,21 +482,27 @@ } }, "node_modules/@types/bonjour": { - "version": "3.5.10", + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect": { - "version": "3.4.35", + "version": "3.4.38", + "resolved": "https://registry.npmmirror.com/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", @@ -411,7 +510,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.4.5", + "version": "9.6.1", + "resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "license": "MIT", "dependencies": { "@types/estree": "*", @@ -419,7 +520,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.4", + "version": "3.7.7", + "resolved": "https://registry.npmmirror.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "license": "MIT", "dependencies": { "@types/eslint": "*", @@ -427,76 +530,126 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.13", + "version": "4.17.25", + "resolved": "https://registry.npmmirror.com/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", "license": "MIT", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", - "@types/serve-static": "*" + "@types/serve-static": "^1" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.29", + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, "node_modules/@types/http-proxy": { - "version": "1.17.9", + "version": "1.17.17", + "resolved": "https://registry.npmmirror.com/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/json-schema": { - "version": "7.0.11", + "version": "7.0.15", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, "node_modules/@types/mime": { - "version": "1.3.2", + "version": "1.3.5", + "resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "license": "MIT" }, "node_modules/@types/node": { - "version": "18.0.3", - "license": "MIT" + "version": "25.0.9", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-25.0.9.tgz", + "integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.14", + "resolved": "https://registry.npmmirror.com/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/prop-types": { - "version": "15.7.14", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "version": "15.7.15", + "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "dev": true, "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.7", + "version": "6.14.0", + "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "license": "MIT" }, "node_modules/@types/range-parser": { - "version": "1.2.4", + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "license": "MIT" }, "node_modules/@types/react": { - "version": "16.14.62", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.62.tgz", - "integrity": "sha512-BWf7hqninZav6nerxXj+NeZT/mTpDeG6Lk2zREHAy63CrnXoOGPGtNqTFYFN/sqpSaREDP5otVV88axIXmKfGA==", + "version": "18.3.27", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "^0.16", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-reconciler": { "version": "0.18.0", + "resolved": "https://registry.npmmirror.com/@types/react-reconciler/-/react-reconciler-0.18.0.tgz", + "integrity": "sha512-hLVaxzL7cGgk/2C/sc8yyyvi+aeeimv7SKOFgyuPFYqNb2rnnQApHabcxo5Xp+GloUAfMe3tyQm2nkrmbLXq4w==", "dev": true, "license": "MIT", "dependencies": { @@ -505,24 +658,43 @@ }, "node_modules/@types/retry": { "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "license": "MIT" }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true, - "license": "MIT" + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/serve-index": { - "version": "1.9.1", + "version": "1.9.4", + "resolved": "https://registry.npmmirror.com/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.13.10", + "version": "1.15.10", + "resolved": "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmmirror.com/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -530,145 +702,185 @@ } }, "node_modules/@types/sockjs": { - "version": "0.3.33", + "version": "0.3.36", + "resolved": "https://registry.npmmirror.com/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/ws": { - "version": "8.5.3", + "version": "8.18.1", + "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", + "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "license": "Apache-2.0" }, "node_modules/accepts": { "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -678,9 +890,21 @@ "node": ">= 0.6" } }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { - "version": "8.7.1", + "version": "8.15.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -688,36 +912,68 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, "peerDependencies": { - "acorn": "^8" + "acorn": "^8.14.0" } }, "node_modules/ajv": { - "version": "6.12.6", + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ajv-keywords": { - "version": "3.5.2", + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, "peerDependencies": { - "ajv": "^6.9.1" + "ajv": "^8.8.2" } }, "node_modules/ansi-html-community": { "version": "0.0.8", + "resolved": "https://registry.npmmirror.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "engines": [ "node >= 0.8.0" ], @@ -727,7 +983,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.0.1", + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { @@ -738,18 +996,22 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { - "version": "3.1.2", + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -760,12 +1022,19 @@ } }, "node_modules/array-flatten": { - "version": "2.1.2", + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, "node_modules/available-typed-arrays": { - "version": "1.0.5", + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -775,10 +1044,14 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -795,58 +1068,86 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.15", + "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.15.tgz", + "integrity": "sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/batch": { "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "license": "MIT" }, "node_modules/binary-extensions": { - "version": "2.2.0", + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/body-parser": { - "version": "1.20.0", + "version": "1.20.4", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", + "bytes": "~3.1.2", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/bonjour-service": { - "version": "1.0.13", + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", "license": "MIT", "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "node_modules/brace-expansion": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -854,17 +1155,21 @@ } }, "node_modules/braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.21.1", + "version": "4.28.1", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -873,14 +1178,20 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", + "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001359", - "electron-to-chromium": "^1.4.172", - "node-releases": "^2.0.5", - "update-browserslist-db": "^1.0.4" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -891,6 +1202,8 @@ }, "node_modules/buffer": { "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -913,28 +1226,70 @@ }, "node_modules/buffer-from": { "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, "node_modules/bytes": { - "version": "3.0.0", + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001363", + "version": "1.0.30001765", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", + "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", "funding": [ { "type": "opencollective", @@ -943,97 +1298,83 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "2.4.2", - "dev": true, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=4" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6.0" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, "node_modules/colorette": { - "version": "2.0.19", + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "license": "MIT" }, "node_modules/commander": { "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, "node_modules/compressible": { "version": "2.0.18", + "resolved": "https://registry.npmmirror.com/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" @@ -1043,31 +1384,48 @@ } }, "node_modules/compression": { - "version": "1.7.4", + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "license": "MIT", "engines": { "node": ">=0.8" @@ -1075,6 +1433,8 @@ }, "node_modules/content-disposition": { "version": "0.5.4", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -1084,25 +1444,33 @@ } }, "node_modules/content-type": { - "version": "1.0.4", + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { - "version": "0.5.0", + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.0.6", + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, "node_modules/core-js": { - "version": "3.23.3", + "version": "3.47.0", + "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -1112,10 +1480,14 @@ }, "node_modules/core-util-is": { "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1127,19 +1499,33 @@ } }, "node_modules/csstype": { - "version": "3.1.3", + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, "node_modules/debug": { - "version": "2.6.9", + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/default-gateway": { "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" @@ -1148,19 +1534,15 @@ "node": ">= 10" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { + "node_modules/define-data-property": { "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "license": "MIT", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -1169,8 +1551,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/depd": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -1178,6 +1571,8 @@ }, "node_modules/destroy": { "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "license": "MIT", "engines": { "node": ">= 0.8", @@ -1186,14 +1581,14 @@ }, "node_modules/detect-node": { "version": "2.1.0", - "license": "MIT" - }, - "node_modules/dns-equal": { - "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "license": "MIT" }, "node_modules/dns-packet": { - "version": "5.4.0", + "version": "5.6.1", + "resolved": "https://registry.npmmirror.com/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -1202,33 +1597,59 @@ "node": ">=6" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.180", + "version": "1.5.267", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/enhanced-resolve": { - "version": "5.10.0", + "version": "5.18.4", + "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -1238,62 +1659,46 @@ "node": ">=10.13.0" } }, - "node_modules/es-abstract": { - "version": "1.20.1", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/es-module-lexer": { - "version": "0.9.3", + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "license": "MIT" }, - "node_modules/es-to-primitive": { - "version": "1.2.1", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/esbuild": { - "version": "0.14.48", + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz", + "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -1303,30 +1708,81 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-64": "0.14.48", - "esbuild-android-arm64": "0.14.48", - "esbuild-darwin-64": "0.14.48", - "esbuild-darwin-arm64": "0.14.48", - "esbuild-freebsd-64": "0.14.48", - "esbuild-freebsd-arm64": "0.14.48", - "esbuild-linux-32": "0.14.48", - "esbuild-linux-64": "0.14.48", - "esbuild-linux-arm": "0.14.48", - "esbuild-linux-arm64": "0.14.48", - "esbuild-linux-mips64le": "0.14.48", - "esbuild-linux-ppc64le": "0.14.48", - "esbuild-linux-riscv64": "0.14.48", - "esbuild-linux-s390x": "0.14.48", - "esbuild-netbsd-64": "0.14.48", - "esbuild-openbsd-64": "0.14.48", - "esbuild-sunos-64": "0.14.48", - "esbuild-windows-32": "0.14.48", - "esbuild-windows-64": "0.14.48", - "esbuild-windows-arm64": "0.14.48" + "@esbuild/linux-loong64": "0.14.54", + "esbuild-android-64": "0.14.54", + "esbuild-android-arm64": "0.14.54", + "esbuild-darwin-64": "0.14.54", + "esbuild-darwin-arm64": "0.14.54", + "esbuild-freebsd-64": "0.14.54", + "esbuild-freebsd-arm64": "0.14.54", + "esbuild-linux-32": "0.14.54", + "esbuild-linux-64": "0.14.54", + "esbuild-linux-arm": "0.14.54", + "esbuild-linux-arm64": "0.14.54", + "esbuild-linux-mips64le": "0.14.54", + "esbuild-linux-ppc64le": "0.14.54", + "esbuild-linux-riscv64": "0.14.54", + "esbuild-linux-s390x": "0.14.54", + "esbuild-netbsd-64": "0.14.54", + "esbuild-openbsd-64": "0.14.54", + "esbuild-sunos-64": "0.14.54", + "esbuild-windows-32": "0.14.54", + "esbuild-windows-64": "0.14.54", + "esbuild-windows-arm64": "0.14.54" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", + "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", + "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", + "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.48", + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", + "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", "cpu": [ "arm64" ], @@ -1339,32 +1795,288 @@ "node": ">=12" } }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", + "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", + "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", + "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", + "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", + "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", + "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", + "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", + "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", + "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", + "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", + "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", + "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/esbuild-plugin-alias": { "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz", + "integrity": "sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==", "dev": true, "license": "MIT" }, - "node_modules/escalade": { - "version": "3.1.1", + "node_modules/esbuild-sunos-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", + "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" + "node_modules/esbuild-windows-32": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", + "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, + "node_modules/esbuild-windows-64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", + "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.8.0" + "node": ">=12" } }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", + "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/eslint-scope": { "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -1376,6 +2088,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -1386,6 +2100,8 @@ }, "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -1393,6 +2109,8 @@ }, "node_modules/estraverse": { "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -1400,6 +2118,8 @@ }, "node_modules/etag": { "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -1407,10 +2127,14 @@ }, "node_modules/eventemitter3": { "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, "node_modules/events": { "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", "engines": { "node": ">=0.8.x" @@ -1418,6 +2142,8 @@ }, "node_modules/execa": { "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -1437,60 +2163,99 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/express": { - "version": "4.18.1", + "version": "4.22.1", + "resolved": "https://registry.npmmirror.com/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "license": "MIT" + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/faye-websocket": { "version": "0.11.4", + "resolved": "https://registry.npmmirror.com/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" @@ -1501,6 +2266,8 @@ }, "node_modules/fetch-blob": { "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "funding": [ { "type": "github", @@ -1521,7 +2288,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -1531,23 +2300,42 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/follow-redirects": { - "version": "1.15.1", + "version": "1.15.11", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -1565,31 +2353,30 @@ } }, "node_modules/for-each": { - "version": "0.3.3", + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "is-callable": "^1.2.7" }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, "engines": { "node": ">=14" }, @@ -1599,6 +2386,8 @@ }, "node_modules/forwarded": { "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -1606,21 +2395,30 @@ }, "node_modules/fresh": { "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fs-monkey": { - "version": "1.0.3", + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", "license": "Unlicense" }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.2", + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -1631,91 +2429,97 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.4" } }, "node_modules/get-intrinsic": { - "version": "1.1.2", + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/glob": { - "version": "10.3.15", + "version": "10.5.0", + "resolved": "https://registry.npmmirror.com/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -1726,60 +2530,69 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "license": "BSD-2-Clause" }, "node_modules/globals": { "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { - "version": "4.2.10", + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, "node_modules/handle-thing": { "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "license": "MIT" }, - "node_modules/has": { - "version": "1.0.3", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { - "version": "4.0.0", + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { - "version": "1.0.3", + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1789,10 +2602,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -1801,8 +2616,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hpack.js": { "version": "2.1.6", + "resolved": "https://registry.npmmirror.com/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "license": "MIT", "dependencies": { "inherits": "^2.0.1", @@ -1812,7 +2641,9 @@ } }, "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.7", + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -1826,43 +2657,71 @@ }, "node_modules/hpack.js/node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/html-entities": { - "version": "2.3.3", + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], "license": "MIT" }, "node_modules/http-deceiver": { "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-parser-js": { - "version": "0.5.8", + "version": "0.5.10", + "resolved": "https://registry.npmmirror.com/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", + "resolved": "https://registry.npmmirror.com/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", @@ -1874,7 +2733,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", + "version": "2.0.9", + "resolved": "https://registry.npmmirror.com/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", @@ -1897,6 +2758,8 @@ }, "node_modules/human-signals": { "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -1904,6 +2767,8 @@ }, "node_modules/iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -1914,6 +2779,8 @@ }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -1932,10 +2799,15 @@ }, "node_modules/ignore-by-default": { "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "license": "ISC" }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -1944,33 +2816,27 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/internal-slot": { - "version": "1.0.3", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/ipaddr.js": { - "version": "2.0.1", + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/is-arguments": { - "version": "1.1.1", + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -1979,18 +2845,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bigint": { - "version": "1.0.4", - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -1999,36 +2857,11 @@ "node": ">=8" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-callable": { - "version": "1.2.4", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, "engines": { "node": ">= 0.4" }, @@ -2038,6 +2871,8 @@ }, "node_modules/is-docker": { "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "license": "MIT", "bin": { "is-docker": "cli.js" @@ -2051,6 +2886,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2058,6 +2895,8 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", "engines": { @@ -2065,10 +2904,16 @@ } }, "node_modules/is-generator-function": { - "version": "1.0.10", + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2079,6 +2924,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -2087,38 +2934,19 @@ "node": ">=0.10.0" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-plain-obj": { "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "license": "MIT", "engines": { "node": ">=10" @@ -2128,44 +2956,15 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -2174,28 +2973,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-symbol": { - "version": "1.0.4", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-typed-array": { - "version": "1.1.9", + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -2204,18 +3000,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-wsl": { "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -2226,22 +3014,25 @@ }, "node_modules/isarray": { "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/jackspeak": { - "version": "2.3.6", + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -2251,11 +3042,15 @@ }, "node_modules/javascript-natural-sort": { "version": "0.7.1", + "resolved": "https://registry.npmmirror.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", "dev": true, "license": "MIT" }, "node_modules/jest-worker": { "version": "27.5.1", + "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -2266,12 +3061,40 @@ "node": ">= 10.13.0" } }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/jsesc": { "version": "2.5.2", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, "license": "MIT", "bin": { @@ -2283,25 +3106,49 @@ }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, + "node_modules/launch-editor": { + "version": "2.12.0", + "resolved": "https://registry.npmmirror.com/launch-editor/-/launch-editor-2.12.0.tgz", + "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, "node_modules/loader-runner": { - "version": "4.3.0", + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/lodash": { "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -2311,55 +3158,77 @@ } }, "node_modules/lru-cache": { - "version": "10.2.2", + "version": "10.4.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } + "license": "ISC" }, "node_modules/lvgljs-ui": { - "version": "0.0.1", - "resolved": "file:src/render/react", - "license": "ISC" + "resolved": "src/render/react", + "link": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, "node_modules/media-typer": { "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/memfs": { - "version": "3.4.7", + "version": "3.5.3", + "resolved": "https://registry.npmmirror.com/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "license": "Unlicense", "dependencies": { - "fs-monkey": "^1.0.3" + "fs-monkey": "^1.0.4" }, "engines": { "node": ">= 4.0.0" } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "license": "MIT" + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "license": "MIT" }, "node_modules/methods": { "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { - "version": "4.0.5", + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2368,6 +3237,8 @@ }, "node_modules/mime": { "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "license": "MIT", "bin": { "mime": "cli.js" @@ -2378,6 +3249,8 @@ }, "node_modules/mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -2385,6 +3258,8 @@ }, "node_modules/mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -2395,6 +3270,8 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", "engines": { "node": ">=6" @@ -2402,10 +3279,14 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC" }, "node_modules/minimatch": { - "version": "9.0.4", + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -2419,7 +3300,9 @@ } }, "node_modules/minipass": { - "version": "7.1.1", + "version": "7.1.2", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -2427,11 +3310,15 @@ } }, "node_modules/ms": { - "version": "2.0.0", + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", + "resolved": "https://registry.npmmirror.com/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", @@ -2442,7 +3329,9 @@ } }, "node_modules/negotiator": { - "version": "0.6.3", + "version": "0.6.4", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -2450,10 +3339,15 @@ }, "node_modules/neo-async": { "version": "2.6.2", + "resolved": "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, "node_modules/node-domexception": { "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", "funding": [ { "type": "github", @@ -2470,18 +3364,24 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-releases": { - "version": "2.0.5", + "version": "2.0.27", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/nodemon": { - "version": "3.1.9", + "version": "3.1.11", + "resolved": "https://registry.npmmirror.com/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", "license": "MIT", "dependencies": { "chokidar": "^3.5.2", @@ -2507,37 +3407,19 @@ } }, "node_modules/nodemon/node_modules/brace-expansion": { - "version": "1.1.11", + "version": "1.1.12", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.4.0", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/nodemon/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -2546,22 +3428,10 @@ "node": "*" } }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/normalize-path": { "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2569,6 +3439,8 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -2577,36 +3449,11 @@ "node": ">=8" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { - "version": "1.12.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", + "version": "1.13.4", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, "engines": { "node": ">= 0.4" }, @@ -2616,10 +3463,14 @@ }, "node_modules/obuf": { "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -2629,7 +3480,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -2637,6 +3490,8 @@ }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -2644,6 +3499,8 @@ }, "node_modules/onetime": { "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -2656,7 +3513,9 @@ } }, "node_modules/open": { - "version": "8.4.0", + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -2672,6 +3531,8 @@ }, "node_modules/p-retry": { "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "license": "MIT", "dependencies": { "@types/retry": "0.12.0", @@ -2681,8 +3542,17 @@ "node": ">=8" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parseurl": { "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -2690,6 +3560,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2697,6 +3569,8 @@ }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -2704,6 +3578,8 @@ }, "node_modules/path-scurry": { "version": "1.11.1", + "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -2718,15 +3594,21 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", + "version": "0.1.12", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.0", + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -2735,10 +3617,22 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prettier": { - "version": "3.0.1", + "version": "3.8.0", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.8.0.tgz", + "integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -2751,19 +3645,14 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, - "node_modules/prop-types": { - "version": "15.8.1", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -2775,6 +3664,8 @@ }, "node_modules/proxy-addr/node_modules/ipaddr.js": { "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -2782,20 +3673,17 @@ }, "node_modules/pstree.remy": { "version": "1.1.8", + "resolved": "https://registry.npmmirror.com/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "license": "MIT" }, - "node_modules/punycode": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/qs": { - "version": "6.10.3", + "version": "6.14.1", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -2806,6 +3694,8 @@ }, "node_modules/randombytes": { "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" @@ -2813,83 +3703,73 @@ }, "node_modules/range-parser": { "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "2.5.1", + "version": "2.5.3", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/react": { - "version": "16.14.0", + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/react-is": { - "version": "16.13.1", - "license": "MIT" - }, "node_modules/react-proxy": { "version": "2.0.8", + "resolved": "https://registry.npmmirror.com/react-proxy/-/react-proxy-2.0.8.tgz", + "integrity": "sha512-iYUKak7a+fGRk7mphfah9KnmIZ2l026tkge82Phicc82qltuiqz0lOpizg/7lO4n9ZSom0DpPVdSKLJYQnxOuA==", "license": "MIT", "dependencies": { "lodash": "^4.6.1" } }, "node_modules/react-reconciler": { - "version": "0.25.1", + "version": "0.29.2", + "resolved": "https://registry.npmmirror.com/react-reconciler/-/react-reconciler-0.29.2.tgz", + "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.23.2" }, "engines": { "node": ">=0.10.0" }, "peerDependencies": { - "react": "^16.13.1" - } - }, - "node_modules/react-reconciler/node_modules/scheduler": { - "version": "0.19.1", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "react": "^18.3.1" } }, "node_modules/react-router": { - "version": "6.23.1", + "version": "6.30.3", + "resolved": "https://registry.npmmirror.com/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.16.1" + "@remix-run/router": "1.23.2" }, "engines": { "node": ">=14.0.0" @@ -2899,7 +3779,9 @@ } }, "node_modules/readable-stream": { - "version": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -2912,6 +3794,8 @@ }, "node_modules/readdirp": { "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -2920,23 +3804,10 @@ "node": ">=8.10.0" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2944,10 +3815,14 @@ }, "node_modules/requires-port": { "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "license": "MIT" }, "node_modules/retry": { "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { "node": ">= 4" @@ -2955,6 +3830,9 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -2967,7 +3845,9 @@ } }, "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", + "version": "1.1.12", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2976,6 +3856,9 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -2994,6 +3877,8 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -3004,6 +3889,8 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -3020,17 +3907,48 @@ ], "license": "MIT" }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/schema-utils": { - "version": "3.1.1", + "version": "4.3.3", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -3042,12 +3960,17 @@ }, "node_modules/select-hose": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "license": "MIT" }, "node_modules/selfsigned": { - "version": "2.0.1", + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "license": "MIT", "dependencies": { + "@types/node-forge": "^1.3.0", "node-forge": "^1" }, "engines": { @@ -3055,7 +3978,9 @@ } }, "node_modules/semver": { - "version": "7.6.3", + "version": "7.7.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3065,33 +3990,48 @@ } }, "node_modules/send": { - "version": "0.18.0", + "version": "0.19.2", + "resolved": "https://registry.npmmirror.com/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/serialize-javascript": { - "version": "6.0.0", + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -3099,6 +4039,8 @@ }, "node_modules/serve-index": { "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "license": "MIT", "dependencies": { "accepts": "~1.3.4", @@ -3113,8 +4055,19 @@ "node": ">= 0.8.0" } }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3122,6 +4075,8 @@ }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "license": "MIT", "dependencies": { "depd": "~1.1.2", @@ -3135,38 +4090,73 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "license": "ISC" }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { - "version": "1.15.0", + "version": "1.16.3", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3177,29 +4167,114 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel": { - "version": "1.0.4", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/signal-exit": { - "version": "3.0.7", - "license": "ISC" + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/simple-update-notifier": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "license": "MIT", "dependencies": { "semver": "^7.5.3" @@ -3210,6 +4285,8 @@ }, "node_modules/sockjs": { "version": "0.3.24", + "resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", @@ -3218,7 +4295,10 @@ } }, "node_modules/source-map": { - "version": "0.6.1", + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -3226,14 +4306,27 @@ }, "node_modules/source-map-support": { "version": "0.5.21", + "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdy": { "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "license": "MIT", "dependencies": { "debug": "^4.1.0", @@ -3248,6 +4341,8 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "license": "MIT", "dependencies": { "debug": "^4.1.0", @@ -3258,46 +4353,10 @@ "wbuf": "^1.7.3" } }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "4.3.4", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/spdy/node_modules/debug": { - "version": "4.3.4", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy/node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, "node_modules/statuses": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -3305,6 +4364,8 @@ }, "node_modules/string_decoder": { "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -3312,6 +4373,8 @@ }, "node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { @@ -3329,6 +4392,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -3342,6 +4407,8 @@ }, "node_modules/string-width-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -3350,11 +4417,15 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -3364,32 +4435,10 @@ "node": ">=8" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { - "version": "7.1.0", + "version": "7.1.2", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", "dependencies": { @@ -3405,6 +4454,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -3416,6 +4467,8 @@ }, "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -3424,37 +4477,46 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/supports-color": { - "version": "8.1.1", + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=4" } }, "node_modules/tapable": { - "version": "2.2.1", + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/terser": { - "version": "5.14.1", + "version": "5.46.0", + "resolved": "https://registry.npmmirror.com/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "license": "BSD-2-Clause", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -3466,14 +4528,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.3", + "version": "5.3.16", + "resolved": "https://registry.npmmirror.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.7", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.7.2" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -3499,14 +4563,21 @@ }, "node_modules/text-encoding": { "version": "0.7.0", + "resolved": "https://registry.npmmirror.com/text-encoding/-/text-encoding-0.7.0.tgz", + "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==", + "deprecated": "no longer maintained", "license": "(Unlicense OR Apache-2.0)" }, "node_modules/thunky": { "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "license": "MIT" }, "node_modules/to-fast-properties": { "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, "license": "MIT", "engines": { @@ -3515,6 +4586,8 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -3525,6 +4598,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -3532,6 +4607,8 @@ }, "node_modules/touch": { "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" @@ -3539,6 +4616,8 @@ }, "node_modules/type-is": { "version": "1.6.18", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "license": "MIT", "dependencies": { "media-typer": "0.3.0", @@ -3548,32 +4627,31 @@ "node": ">= 0.6" } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/undefsafe": { "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/update-browserslist-db": { - "version": "1.0.4", + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -3582,49 +4660,53 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/urlpattern-polyfill": { - "version": "5.0.3", + "version": "5.0.9", + "resolved": "https://registry.npmmirror.com/urlpattern-polyfill/-/urlpattern-polyfill-5.0.9.tgz", + "integrity": "sha512-7MM/vXEZhbWtSBKPTWFb431QUxn9IKBN3HutHN+2JrO9UAusttvvCjEVB+7MZkAowduXCs2v0D/puv6sE9oyFA==", "license": "MIT" }, "node_modules/util": { - "version": "0.12.4", + "version": "0.12.5", + "resolved": "https://registry.npmmirror.com/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, "node_modules/util-deprecate": { "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -3632,6 +4714,8 @@ }, "node_modules/uuid": { "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -3639,13 +4723,17 @@ }, "node_modules/vary": { "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/watchpack": { - "version": "2.4.0", + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -3657,46 +4745,54 @@ }, "node_modules/wbuf": { "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } }, "node_modules/web-streams-polyfill": { - "version": "3.2.1", + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/webpack": { - "version": "5.73.0", - "license": "MIT", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "version": "5.104.1", + "resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.104.1.tgz", + "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.17.4", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -3715,7 +4811,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "license": "MIT", "dependencies": { "colorette": "^2.0.10", @@ -3735,68 +4833,10 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.11.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-formats": { - "version": "2.1.1", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-dev-server": { - "version": "4.9.3", + "version": "4.15.2", + "resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", @@ -3805,7 +4845,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -3818,16 +4858,17 @@ "html-entities": "^2.3.2", "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", "open": "^8.0.9", "p-retry": "^4.5.0", "rimraf": "^3.0.2", "schema-utils": "^4.0.0", - "selfsigned": "^2.0.1", + "selfsigned": "^2.1.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" @@ -3843,73 +4884,18 @@ "webpack": "^4.37.0 || ^5.0.0" }, "peerDependenciesMeta": { - "webpack-cli": { + "webpack": { "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.11.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-formats": { - "version": "2.1.1", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { + }, + "webpack-cli": { "optional": true } } }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-sources": { - "version": "3.2.3", + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "license": "MIT", "engines": { "node": ">=10.13.0" @@ -3917,6 +4903,8 @@ }, "node_modules/websocket-driver": { "version": "0.7.4", + "resolved": "https://registry.npmmirror.com/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", @@ -3929,17 +4917,23 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } }, "node_modules/whatwg-fetch": { - "version": "3.6.2", + "version": "3.6.20", + "resolved": "https://registry.npmmirror.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", "license": "MIT" }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -3951,30 +4945,19 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-typed-array": { - "version": "1.1.8", + "version": "1.1.20", + "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3985,6 +4968,8 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4002,6 +4987,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4018,6 +5005,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -4026,6 +5015,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4038,29 +5029,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -4074,6 +5053,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -4083,30 +5064,23 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/ws": { - "version": "8.8.0", + "version": "8.19.0", + "resolved": "https://registry.npmmirror.com/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -4116,6 +5090,11 @@ "optional": true } } + }, + "src/render/react": { + "name": "lvgljs-ui", + "version": "0.0.1", + "license": "ISC" } } } diff --git a/package.json b/package.json index d3f50b276..ac01e93a6 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,9 @@ "fetch-blob": "^3.2.0", "nodemon": "^3.1.4", "lvgljs-ui": "file:src/render/react", - "react": "16.14.0", + "react": "18.3.1", "react-proxy": "^2.0.8", - "react-reconciler": "0.25.1", + "react-reconciler": "0.29.2", "react-router": "^6.3.0", "text-encoding": "^0.7.0", "urlpattern-polyfill": "^5.0.3", @@ -37,7 +37,7 @@ "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@txikijs/types": "^24.6.0", - "@types/react": "^16.3.1", + "@types/react": "^18.3.0", "@types/react-reconciler": "^0.18.0", "esbuild-plugin-alias": "^0.2.1", "glob": "^10.3.15", diff --git a/src/render/native/components/arc/arc_wrap.cpp b/src/render/native/components/arc/arc_wrap.cpp index 07d5fd94e..0548c2b0f 100644 --- a/src/render/native/components/arc/arc_wrap.cpp +++ b/src/render/native/components/arc/arc_wrap.cpp @@ -156,9 +156,8 @@ static JSValue ArcConstructor(JSContext *ctx, JSValueConst new_target, int argc, static void ArcFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ArcClassID); - LV_LOG_USER("Arc %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Arc %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/button/button_wrap.cpp b/src/render/native/components/button/button_wrap.cpp index 821ac14b6..39b2c2d5a 100644 --- a/src/render/native/components/button/button_wrap.cpp +++ b/src/render/native/components/button/button_wrap.cpp @@ -87,9 +87,8 @@ static JSValue ButtonConstructor(JSContext *ctx, JSValueConst new_target, int ar static void ButtonFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ButtonClassID); - LV_LOG_USER("Button %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Button %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/calendar/calendar_wrap.cpp b/src/render/native/components/calendar/calendar_wrap.cpp index 0bb6dcddd..25933018d 100644 --- a/src/render/native/components/calendar/calendar_wrap.cpp +++ b/src/render/native/components/calendar/calendar_wrap.cpp @@ -156,9 +156,8 @@ static JSValue CalendarConstructor(JSContext *ctx, JSValueConst new_target, int static void CalendarFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, CalendarClassID); - LV_LOG_USER("Calendar %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Calendar %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/chart/chart_wrap.cpp b/src/render/native/components/chart/chart_wrap.cpp index 7cb064361..3430c4f5f 100644 --- a/src/render/native/components/chart/chart_wrap.cpp +++ b/src/render/native/components/chart/chart_wrap.cpp @@ -666,9 +666,8 @@ static JSValue ChartConstructor(JSContext *ctx, JSValueConst new_target, int arg static void ChartFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ChartClassID); - LV_LOG_USER("Chart %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Chart %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/checkbox/checkbox_wrap.cpp b/src/render/native/components/checkbox/checkbox_wrap.cpp index fb1253b16..b8200b355 100644 --- a/src/render/native/components/checkbox/checkbox_wrap.cpp +++ b/src/render/native/components/checkbox/checkbox_wrap.cpp @@ -121,9 +121,8 @@ static JSValue CheckboxConstructor(JSContext *ctx, JSValueConst new_target, int static void CheckboxFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, CheckboxClassID); - LV_LOG_USER("Checkbox %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Checkbox %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/component.hpp b/src/render/native/components/component.hpp index cb5420412..715ce4d9b 100644 --- a/src/render/native/components/component.hpp +++ b/src/render/native/components/component.hpp @@ -293,7 +293,10 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); #define WRAPPED_JS_CLOSE_COMPONENT(COMPONENT,COMPONENT_NAME) \ static JSValue NativeCompCloseComponent(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \ COMP_REF* s = (COMP_REF*)JS_GetOpaque(this_val, COMPONENT##ClassID); \ - lv_obj_del_async(((BasicComponent*)(s->comp))->instance); \ + if (s && s->comp) { \ + delete (BasicComponent*)(s->comp); \ + s->comp = nullptr; \ + } \ return JS_UNDEFINED; \ } \ \ diff --git a/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp b/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp index 234b5c90f..1c2d7b294 100644 --- a/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp +++ b/src/render/native/components/dropdownlist/dropdownlist_wrap.cpp @@ -174,9 +174,8 @@ static JSValue DropdownlistConstructor(JSContext *ctx, JSValueConst new_target, static void DropdownlistFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, DropdownlistClassID); - LV_LOG_USER("Dropdownlist %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Dropdownlist %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/gif/gif_wrap.cpp b/src/render/native/components/gif/gif_wrap.cpp index 9c5c2e2a6..029570e8c 100644 --- a/src/render/native/components/gif/gif_wrap.cpp +++ b/src/render/native/components/gif/gif_wrap.cpp @@ -97,9 +97,8 @@ static JSValue GIFConstructor(JSContext *ctx, JSValueConst new_target, int argc, static void GIFFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, GIFClassID); - LV_LOG_USER("GIF %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("GIF %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/image/image_wrap.cpp b/src/render/native/components/image/image_wrap.cpp index c9449ea20..929b3802d 100644 --- a/src/render/native/components/image/image_wrap.cpp +++ b/src/render/native/components/image/image_wrap.cpp @@ -117,9 +117,8 @@ static JSValue ImageConstructor(JSContext *ctx, JSValueConst new_target, int arg static void ImageFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ImageClassID); - LV_LOG_USER("Image %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Image %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/keyboard/keyboard_wrap.cpp b/src/render/native/components/keyboard/keyboard_wrap.cpp index b4da2f8e2..78084f9ce 100644 --- a/src/render/native/components/keyboard/keyboard_wrap.cpp +++ b/src/render/native/components/keyboard/keyboard_wrap.cpp @@ -103,9 +103,8 @@ static JSValue KeyboardConstructor(JSContext *ctx, JSValueConst new_target, int static void KeyboardFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, KeyboardClassID); - LV_LOG_USER("Keyboard %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Keyboard %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/line/line_wrap.cpp b/src/render/native/components/line/line_wrap.cpp index 351237e91..ff84cf8a4 100644 --- a/src/render/native/components/line/line_wrap.cpp +++ b/src/render/native/components/line/line_wrap.cpp @@ -118,9 +118,8 @@ static JSValue LineConstructor(JSContext *ctx, JSValueConst new_target, int argc static void LineFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, LineClassID); - LV_LOG_USER("Line %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Line %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/list/list_wrap.cpp b/src/render/native/components/list/list_wrap.cpp index 9e0683096..7ddbc65ea 100644 --- a/src/render/native/components/list/list_wrap.cpp +++ b/src/render/native/components/list/list_wrap.cpp @@ -103,9 +103,8 @@ static JSValue ListConstructor(JSContext *ctx, JSValueConst new_target, int argc static void ListFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ListClassID); - LV_LOG_USER("List %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("List %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/mask/mask_wrap.cpp b/src/render/native/components/mask/mask_wrap.cpp index 1d6e290f2..022421729 100644 --- a/src/render/native/components/mask/mask_wrap.cpp +++ b/src/render/native/components/mask/mask_wrap.cpp @@ -73,9 +73,8 @@ static JSValue MaskConstructor(JSContext *ctx, JSValueConst new_target, int argc static void MaskFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, MaskClassID); - LV_LOG_USER("Mask %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Mask %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/progressbar/progressbar_wrap.cpp b/src/render/native/components/progressbar/progressbar_wrap.cpp index c42c18465..987f9cf0e 100644 --- a/src/render/native/components/progressbar/progressbar_wrap.cpp +++ b/src/render/native/components/progressbar/progressbar_wrap.cpp @@ -108,9 +108,8 @@ static JSValue ProgressBarConstructor(JSContext *ctx, JSValueConst new_target, i static void ProgressBarFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ProgressBarClassID); - LV_LOG_USER("ProgressBar %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("ProgressBar %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/roller/roller_wrap.cpp b/src/render/native/components/roller/roller_wrap.cpp index a3a86df0c..822133388 100644 --- a/src/render/native/components/roller/roller_wrap.cpp +++ b/src/render/native/components/roller/roller_wrap.cpp @@ -135,9 +135,8 @@ static JSValue RollerConstructor(JSContext *ctx, JSValueConst new_target, int ar static void RollerFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, RollerClassID); - LV_LOG_USER("Roller %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Roller %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/slider/slider_wrap.cpp b/src/render/native/components/slider/slider_wrap.cpp index a0f09db07..5cdbbae0f 100644 --- a/src/render/native/components/slider/slider_wrap.cpp +++ b/src/render/native/components/slider/slider_wrap.cpp @@ -112,9 +112,8 @@ static JSValue SliderConstructor(JSContext *ctx, JSValueConst new_target, int ar static void SliderFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, SliderClassID); - LV_LOG_USER("Slider %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Slider %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/switch/switch_wrap.cpp b/src/render/native/components/switch/switch_wrap.cpp index a3663c630..2ea3f3a8b 100644 --- a/src/render/native/components/switch/switch_wrap.cpp +++ b/src/render/native/components/switch/switch_wrap.cpp @@ -129,9 +129,8 @@ static JSValue SwitchConstructor(JSContext *ctx, JSValueConst new_target, int ar static void ViewFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, SwitchClassID); - LV_LOG_USER("Switch %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Switch %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/tabview/tabview_wrap.cpp b/src/render/native/components/tabview/tabview_wrap.cpp index 221dd50ec..2b1239a56 100644 --- a/src/render/native/components/tabview/tabview_wrap.cpp +++ b/src/render/native/components/tabview/tabview_wrap.cpp @@ -154,9 +154,8 @@ static JSValue TabViewConstructor(JSContext *ctx, JSValueConst new_target, int a static void TabViewFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, TabViewClassID); - LV_LOG_USER("TabView %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("TabView %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/text/text_wrap.cpp b/src/render/native/components/text/text_wrap.cpp index c1365d377..9c49b74e5 100644 --- a/src/render/native/components/text/text_wrap.cpp +++ b/src/render/native/components/text/text_wrap.cpp @@ -93,9 +93,8 @@ static JSValue TextConstructor(JSContext *ctx, JSValueConst new_target, int argc static void TextFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, TextClassID); - LV_LOG_USER("Text %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Text %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/textarea/textarea_wrap.cpp b/src/render/native/components/textarea/textarea_wrap.cpp index 7095301ba..51cc467af 100644 --- a/src/render/native/components/textarea/textarea_wrap.cpp +++ b/src/render/native/components/textarea/textarea_wrap.cpp @@ -159,9 +159,8 @@ static JSValue TextareaConstructor(JSContext *ctx, JSValueConst new_target, int static void TextareaFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, TextareaClassID); - LV_LOG_USER("Textarea %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Textarea %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/view/view_wrap.cpp b/src/render/native/components/view/view_wrap.cpp index 2ad68b538..afcbed8bc 100644 --- a/src/render/native/components/view/view_wrap.cpp +++ b/src/render/native/components/view/view_wrap.cpp @@ -100,9 +100,8 @@ static JSValue ViewConstructor(JSContext *ctx, JSValueConst new_target, int argc static void ViewFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, ViewClassID); - LV_LOG_USER("View %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("View %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/components/window/window_wrap.cpp b/src/render/native/components/window/window_wrap.cpp index c6a8ed40e..b7fa3a1d4 100644 --- a/src/render/native/components/window/window_wrap.cpp +++ b/src/render/native/components/window/window_wrap.cpp @@ -73,9 +73,8 @@ static JSValue WindowConstructor(JSContext *ctx, JSValueConst new_target, int ar static void WindowFinalizer(JSRuntime *rt, JSValue val) { COMP_REF *th = (COMP_REF *)JS_GetOpaque(val, WindowClassID); - LV_LOG_USER("Window %s release", th->uid); if (th) { - delete static_cast(th->comp); + LV_LOG_USER("Window %s release", th->uid); js_free_rt(rt, th); } }; diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index aa0586468..9f249108d 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -47,10 +47,7 @@ void BasicComponent::insertChildBefore(void *child) { } }; -void BasicComponent::removeChild(void* child) { - BasicComponent* childComp = static_cast(child); - lv_obj_del_async(childComp->instance); -}; +void BasicComponent::removeChild(void* child) {}; void BasicComponent::appendChild (void* child) { BasicComponent* childComp = static_cast(child); @@ -272,8 +269,18 @@ BasicComponent::~BasicComponent () { if (ptr2) { free((lv_coord_t*)(ptr2)); } - // do not del here, remove child will do the action - // lv_obj_del(this->instance); + + for(auto& trans : this->trans_props_map) + if (trans.second != nullptr) + free(trans.second); + + for(auto &style : style_map) { + lv_style_reset(style.second); + style_pool.deallocate(style.second); + } + + lv_obj_remove_event_cb(instance, &BasicComponent::EventCallback); + lv_obj_del(this->instance); }; void BasicComponent::setAlign (int32_t align_type, int32_t x, int32_t y) { diff --git a/src/render/react/core/reconciler/index.js b/src/render/react/core/reconciler/index.js index 7b0a190bb..456ea547f 100644 --- a/src/render/react/core/reconciler/index.js +++ b/src/render/react/core/reconciler/index.js @@ -1,6 +1,7 @@ import { getComponentByTagName } from "../../components/config"; import { unRegistEvent } from "../event"; import Reconciler from "react-reconciler"; +import { DefaultEventPriority } from "react-reconciler/constants"; let id = 1; @@ -14,24 +15,21 @@ export const getInstance = (uid) => { return instanceMap.get(uid); }; -const cleanupInstance = (child, { destroy } = { destroy: false }) => { +const cleanupInstance = (child) => { if (!child) return; const uid = child.uid; if (uid) { unRegistEvent(uid); instanceMap.delete(uid); } - // IMPORTANT: - // For nested children, the native `parent.removeChild(child)` implementation may already - // delete/detach the underlying LVGL object. Calling `child.close()` again can double-free/hang. - // Only destroy on root-container removal where we own the lifetime explicitly. - if (destroy && child.close) { - child.close(); - } + child.style = null; + child.dataset = null; + child.uid = null; + child.close?.(); }; const HostConfig = { - now: Date.now, + // --- Core Methods --- getPublicInstance: (instance) => { //for supporting refs return instance; @@ -42,11 +40,36 @@ const HostConfig = { }; return context; }, - prepareForCommit: () => {}, - resetAfterCommit: () => {}, getChildHostContext: () => { return {}; }, + prepareForCommit: () => { + return null; + }, + resetAfterCommit: () => {}, + preparePortalMount: () => {}, + + // --- Scheduling --- + scheduleTimeout: setTimeout, + cancelTimeout: clearTimeout, + noTimeout: -1, + supportsMicrotasks: true, + scheduleMicrotask: typeof queueMicrotask === 'function' + ? queueMicrotask + : (fn) => Promise.resolve().then(fn), + + // --- Mode Configuration --- + isPrimaryRenderer: true, + supportsMutation: true, + supportsPersistence: false, + supportsHydration: false, + + // --- Event Priority --- + getCurrentEventPriority: () => { + return DefaultEventPriority; + }, + + // --- Instance Lifecycle --- shouldSetTextContent: function (type, props) { // Keep text as a prop for our `Text` host component, not as separate text children. if (type === "Text") { @@ -74,7 +97,6 @@ const HostConfig = { workInProgress, uid, ); - instanceMap.set(uid, instance); return instance; }, createTextInstance: ( @@ -92,34 +114,45 @@ const HostConfig = { workInProgress, uid, ); - instanceMap.set(uid, instance); return instance; }, appendInitialChild: (parent, child) => { parent.appendChild(child); }, - appendChild(parent, child) { - parent.appendChild(child); - }, finalizeInitialChildren: (yueElement, type, props) => { return true; }, - insertBefore: (parent, child, beforeChild) => { - parent.insertBefore(child, beforeChild); + prepareUpdate(instance, type, oldProps, newProps, rootContainer, hostContext) { + return true; + }, + + // --- Mutation Methods --- + appendChild(parent, child) { + parent.appendChild(child); }, - supportsMutation: true, appendChildToContainer: function (container, child) { container.add(child); }, + insertBefore: (parent, child, beforeChild) => { + parent.insertBefore(child, beforeChild); + }, insertInContainerBefore: (container, child, beforeChild) => { container.insertBefore(child, beforeChild); }, + removeChild(parent, child) { + parent?.removeChild(child); + }, removeChildFromContainer: (container, child) => { container.delete(child); - cleanupInstance(child, { destroy: true }); }, - prepareUpdate(instance, oldProps, newProps) { - return true; + resetTextContent: (instance) => {}, + commitTextUpdate(textInstance, oldText, newText) { + textInstance.setText(newText); + }, + commitMount: function (instance, type, newProps, internalInstanceHandle) { + instanceMap.set(instance.uid, instance); + const { commitMount } = getComponentByTagName(type); + return commitMount(instance, newProps, internalInstanceHandle); }, commitUpdate: function ( instance, @@ -138,17 +171,36 @@ const HostConfig = { finishedWork, ); }, - commitTextUpdate(textInstance, oldText, newText) { - textInstance.setText(newText); + + // --- Visibility Methods (for Suspense) --- + hideInstance: (instance) => { + instance.setStyle?.({ opa: 0 }); }, - removeChild(parent, child) { - parent?.removeChild(child); - cleanupInstance(child, { destroy: false }); + hideTextInstance: (textInstance) => { + textInstance.setStyle?.({ opa: 0 }); }, - commitMount: function (instance, type, newProps, internalInstanceHandle) { - const { commitMount } = getComponentByTagName(type); - return commitMount(instance, newProps, internalInstanceHandle); + unhideInstance: (instance, props) => { + instance.setStyle?.({ opa: 255 }); + }, + unhideTextInstance: (textInstance, text) => { + textInstance.setStyle?.({ opa: 255 }); + }, + + // --- Cleanup --- + clearContainer: (container) => { + // Clear all children from the container + container.clear?.(); }, + detachDeletedInstance: (instance) => { + cleanupInstance(instance); + }, + + // --- Other required methods --- + getInstanceFromNode: () => null, + beforeActiveInstanceBlur: () => {}, + afterActiveInstanceBlur: () => {}, + prepareScopeUpdate: () => {}, + getInstanceFromScope: () => null, }; export default Reconciler(HostConfig); diff --git a/src/render/react/core/renderer/index.js b/src/render/react/core/renderer/index.js index 50f24995c..8a51c8d88 100644 --- a/src/render/react/core/renderer/index.js +++ b/src/render/react/core/renderer/index.js @@ -31,14 +31,17 @@ export class Renderer { static portalContainer; static render(element, options) { - const isConcurrent = false; - const hydrate = false; const containerInfo = new RootContainer(); - + + // react-reconciler 0.29.x API: Renderer.container = reconciler.createContainer( - containerInfo, - isConcurrent, - hydrate, + containerInfo, // containerInfo + 0, // tag (LegacyRoot) + null, // hydrationCallbacks + false, // isStrictMode + false, // concurrentUpdatesByDefaultOverride + '', // identifierPrefix + (error) => console.error('React error:', error), // onRecoverableError ); const parentComponent = null; From dfd947a08612160c07db2219d4ade54a82a8132c Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 19 Jan 2026 19:31:29 +0800 Subject: [PATCH 22/62] feat: enhance navigation demo with React Router integration --- build.js | 1 + demo/navigation/index.tsx | 53 ++++++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/build.js b/build.js index be01ecc07..56ec12b59 100644 --- a/build.js +++ b/build.js @@ -13,6 +13,7 @@ function build(pattern){ entryPoints: [entry], bundle: true, platform: 'neutral', + mainFields: ['module', 'main'], external: ['tjs:path'], outfile: path.resolve(path.dirname(entry), 'index.js'), define: { diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 37f1fdafc..7a6d61be5 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; +import { MemoryRouter, Route, Routes, useNavigate } from "react-router"; import { AddChildToDefGroup, Arc, @@ -17,8 +18,6 @@ import { useAutoFocus } from "./useAutoFocus"; const { width, height } = Dimensions.window; -type Page = "home" | "p1" | "p2" | "p3" | "p4"; - declare const require: any; const messages = (locale: string) => { if (locale === "zh") return require("./i18n/zh.json"); @@ -53,15 +52,16 @@ function Header({ ); } -function Page1List({ onBack }: { onBack: () => void }) { +function Page1List() { const t = useT(); + const navigate = useNavigate(); const items = useMemo(() => Array.from({ length: 40 }).map((_, i) => i + 1), []); const firstItemRef = useRef(null); useAutoFocus(firstItemRef, []); return ( -
+
navigate("/")} autoFocusBack={false} /> @@ -84,8 +84,9 @@ function Page1List({ onBack }: { onBack: () => void }) { ); } -function Page2Info({ onBack }: { onBack: () => void }) { +function Page2Info() { const t = useT(); + const navigate = useNavigate(); const infos = useMemo( () => [ { titleKey: "p2.a.title", bodyKey: "p2.a.body" }, @@ -104,7 +105,7 @@ function Page2Info({ onBack }: { onBack: () => void }) { const next = () => setIdx((i) => (i + 1) % infos.length); return ( -
+
navigate("/")} autoFocusBack /> @@ -143,14 +144,15 @@ function Page2Info({ onBack }: { onBack: () => void }) { ); } -function Page3Controls({ onBack }: { onBack: () => void }) { +function Page3Controls() { const t = useT(); + const navigate = useNavigate(); const [slider, setSlider] = useState(30); const [checked1, setChecked1] = useState(false); const [checked2, setChecked2] = useState(true); return ( -
+
navigate("/p1")} autoFocusBack /> @@ -205,8 +207,9 @@ function Page3Controls({ onBack }: { onBack: () => void }) { ); } -function Page4Countdown({ onBack }: { onBack: () => void }) { +function Page4Countdown() { const t = useT(); + const navigate = useNavigate(); const total = 60; const [remain, setRemain] = useState(total); @@ -222,7 +225,7 @@ function Page4Countdown({ onBack }: { onBack: () => void }) { const angle = Math.floor((elapsed / total) * 360); return ( -
+
navigate("/")} autoFocusBack /> void }) { +function Home() { const t = useT(); + const navigate = useNavigate(); const btnW = Math.floor((width - 24 * 2 - 12) / 2); const btnH = 72; @@ -300,28 +304,28 @@ function Home({ go }: { go: (p: Page) => void }) { @@ -331,14 +335,17 @@ function Home({ go }: { go: (p: Page) => void }) { } function App() { - const [page, setPage] = useState("home"); - const backToHome = () => setPage("home"); - - if (page === "p1") return ; - if (page === "p2") return ; - if (page === "p3") return ; - if (page === "p4") return ; - return ; + return ( + + + } /> + } /> + } /> + } /> + } /> + + + ); } function Root() { From e1747314a621f7446ba13f773c8702ee84aab71a Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 19 Jan 2026 20:48:05 +0800 Subject: [PATCH 23/62] refactor: remove useAutoFocus hook and enhance focus management in components - Eliminated the useAutoFocus hook to streamline focus handling. - Updated components to utilize autoFocus and addToFocusGroup props for improved focus management. - Refactored GroupManager to introduce addToFocusGroup and reorderFocusGroup methods for better focus group handling. - Removed deprecated groupType prop from View component and adjusted related logic in the reconciler. - Cleaned up unused imports and improved overall code clarity. --- demo/navigation/index.tsx | 17 +++----- demo/navigation/useAutoFocus.ts | 14 ------ .../components/calendar/calendar_wrap.cpp | 2 + src/render/native/components/component.hpp | 20 +++++++++ .../dropdownlist/dropdownlist_wrap.cpp | 2 + .../native/components/roller/roller_wrap.cpp | 2 + .../native/components/switch/switch_wrap.cpp | 2 + .../components/textarea/textarea_wrap.cpp | 2 + .../native/components/view/view_wrap.cpp | 16 ++----- src/render/native/core/basic/comp.cpp | 5 --- .../native/core/group/group_manager.cpp | 43 ++++--------------- .../native/core/group/group_manager.hpp | 15 +------ src/render/react/components/View/comp.ts | 9 +--- src/render/react/components/common/index.ts | 8 ++++ src/render/react/core/group/index.ts | 11 ----- src/render/react/core/reconciler/index.js | 6 ++- src/render/react/index.ts | 1 - test/group/1/index.jsx | 15 +++---- 18 files changed, 72 insertions(+), 118 deletions(-) delete mode 100644 demo/navigation/useAutoFocus.ts delete mode 100644 src/render/react/core/group/index.ts diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 7a6d61be5..d832788aa 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { MemoryRouter, Route, Routes, useNavigate } from "react-router"; import { - AddChildToDefGroup, Arc, Button, Checkbox, @@ -14,7 +13,6 @@ import { useT, View, } from "lvgljs-ui"; -import { useAutoFocus } from "./useAutoFocus"; const { width, height } = Dimensions.window; @@ -34,13 +32,11 @@ function Header({ autoFocusBack?: boolean; }) { const t = useT(); - const backRef = useRef(null); - useAutoFocus(backRef, [autoFocusBack]); return ( @@ -50,12 +49,11 @@ function Header({ function Page1List() { const t = useT(); - const navigate = useNavigate(); const items = useMemo(() => Array.from({ length: 40 }).map((_, i) => i + 1), []); return ( -
navigate("/")} autoFocusBack={false} /> +
@@ -81,7 +79,6 @@ function Page1List() { function Page2Info() { const t = useT(); - const navigate = useNavigate(); const infos = useMemo( () => [ { titleKey: "p2.a.title", bodyKey: "p2.a.body" }, @@ -100,7 +97,7 @@ function Page2Info() { const next = () => setIdx((i) => (i + 1) % infos.length); return ( -
navigate("/")} autoFocusBack /> +
@@ -141,13 +138,12 @@ function Page2Info() { function Page3Controls() { const t = useT(); - const navigate = useNavigate(); const [slider, setSlider] = useState(30); const [checked1, setChecked1] = useState(false); const [checked2, setChecked2] = useState(true); return ( -
navigate("/p1")} autoFocusBack /> +
@@ -204,7 +200,6 @@ function Page3Controls() { function Page4Countdown() { const t = useT(); - const navigate = useNavigate(); const total = 60; const [remain, setRemain] = useState(total); @@ -220,7 +215,7 @@ function Page4Countdown() { const angle = Math.floor((elapsed / total) * 360); return ( -
navigate("/")} autoFocusBack /> +
Date: Tue, 20 Jan 2026 12:00:05 +0800 Subject: [PATCH 26/62] refactor: remove LV_OBJ_FLAG_SCROLL_ON_FOCUS from multiple components, add LV_OBJ_FLAG_SCROLL_ON_FOCUS when invoke NativeCompAddToFocusGroup --- src/render/native/components/arc/arc.cpp | 1 - src/render/native/components/button/button.cpp | 1 - src/render/native/components/calendar/calendar.cpp | 2 -- src/render/native/components/chart/chart.cpp | 1 - src/render/native/components/checkbox/checkbox.cpp | 1 - src/render/native/components/component.hpp | 1 + src/render/native/components/dropdownlist/dropdownlist.cpp | 1 - src/render/native/components/gif/gif.cpp | 1 - src/render/native/components/image/image.cpp | 1 - src/render/native/components/keyboard/keyboard.cpp | 1 - src/render/native/components/line/line.cpp | 1 - src/render/native/components/list/list.cpp | 1 - src/render/native/components/mask/mask.cpp | 1 - src/render/native/components/progressbar/progressbar.cpp | 1 - src/render/native/components/roller/roller.cpp | 1 - src/render/native/components/slider/slider.cpp | 1 - src/render/native/components/switch/switch.cpp | 1 - src/render/native/components/tabview/tabview.cpp | 1 - src/render/native/components/text/text.cpp | 1 - src/render/native/components/textarea/textarea.cpp | 1 - src/render/native/components/view/view.cpp | 1 - 21 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/render/native/components/arc/arc.cpp b/src/render/native/components/arc/arc.cpp index 2bff9d317..e0f3a9768 100644 --- a/src/render/native/components/arc/arc.cpp +++ b/src/render/native/components/arc/arc.cpp @@ -7,7 +7,6 @@ Arc::Arc(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_arc_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); diff --git a/src/render/native/components/button/button.cpp b/src/render/native/components/button/button.cpp index 466433a9f..2ffefba05 100644 --- a/src/render/native/components/button/button.cpp +++ b/src/render/native/components/button/button.cpp @@ -8,7 +8,6 @@ Button::Button(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->instance = lv_btn_create(parent != nullptr ? parent : GetWindowInstance()); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); }; diff --git a/src/render/native/components/calendar/calendar.cpp b/src/render/native/components/calendar/calendar.cpp index 9e604cfe8..89b06cab9 100644 --- a/src/render/native/components/calendar/calendar.cpp +++ b/src/render/native/components/calendar/calendar.cpp @@ -9,8 +9,6 @@ Calendar::Calendar(std::string uid, lv_obj_t* parent): BasicComponent(uid) { lv_calendar_header_dropdown_create(this->instance); lv_calendar_header_arrow_create(this->instance); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); - lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/chart/chart.cpp b/src/render/native/components/chart/chart.cpp index 28784f49a..970aaf479 100644 --- a/src/render/native/components/chart/chart.cpp +++ b/src/render/native/components/chart/chart.cpp @@ -7,7 +7,6 @@ Chart::Chart(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->instance = lv_chart_create(parent != nullptr ? parent : GetWindowInstance()); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); diff --git a/src/render/native/components/checkbox/checkbox.cpp b/src/render/native/components/checkbox/checkbox.cpp index 03096a504..5eb41de4e 100644 --- a/src/render/native/components/checkbox/checkbox.cpp +++ b/src/render/native/components/checkbox/checkbox.cpp @@ -7,7 +7,6 @@ Checkbox::Checkbox(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->instance = lv_checkbox_create(parent != nullptr ? parent : GetWindowInstance()); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); }; diff --git a/src/render/native/components/component.hpp b/src/render/native/components/component.hpp index c1a746f8c..718f787f1 100644 --- a/src/render/native/components/component.hpp +++ b/src/render/native/components/component.hpp @@ -162,6 +162,7 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); BasicComponent* comp = (BasicComponent*)(ref->comp); \ if (comp->instance) { \ lv_group_add_obj(lv_group_get_default(), comp->instance); \ + lv_obj_add_flag(comp->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); \ } \ } \ return JS_UNDEFINED; \ diff --git a/src/render/native/components/dropdownlist/dropdownlist.cpp b/src/render/native/components/dropdownlist/dropdownlist.cpp index 2c5e93d1d..4c66eb0b2 100644 --- a/src/render/native/components/dropdownlist/dropdownlist.cpp +++ b/src/render/native/components/dropdownlist/dropdownlist.cpp @@ -7,7 +7,6 @@ Dropdownlist::Dropdownlist(std::string uid, lv_obj_t* parent): BasicComponent(ui this->uid = uid; this->instance = lv_dropdown_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/gif/gif.cpp b/src/render/native/components/gif/gif.cpp index ef6403b99..b3e1e8fb8 100644 --- a/src/render/native/components/gif/gif.cpp +++ b/src/render/native/components/gif/gif.cpp @@ -7,7 +7,6 @@ GIF::GIF(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_gif_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICKABLE); lv_img_set_size_mode(this->instance, LV_IMG_SIZE_MODE_REAL); lv_obj_set_user_data(this->instance, this); diff --git a/src/render/native/components/image/image.cpp b/src/render/native/components/image/image.cpp index 3deee7d78..24485c0a5 100644 --- a/src/render/native/components/image/image.cpp +++ b/src/render/native/components/image/image.cpp @@ -8,7 +8,6 @@ Image::Image(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->instance = lv_img_create(parent != nullptr ? parent : GetWindowInstance()); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICKABLE); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); }; diff --git a/src/render/native/components/keyboard/keyboard.cpp b/src/render/native/components/keyboard/keyboard.cpp index bb5719ef1..10fae6700 100644 --- a/src/render/native/components/keyboard/keyboard.cpp +++ b/src/render/native/components/keyboard/keyboard.cpp @@ -6,7 +6,6 @@ Keyboard::Keyboard(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_keyboard_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/line/line.cpp b/src/render/native/components/line/line.cpp index 4b1e73ed0..00813007e 100644 --- a/src/render/native/components/line/line.cpp +++ b/src/render/native/components/line/line.cpp @@ -7,7 +7,6 @@ Line::Line(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_line_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/list/list.cpp b/src/render/native/components/list/list.cpp index 1ad9a7794..7c7b0504b 100644 --- a/src/render/native/components/list/list.cpp +++ b/src/render/native/components/list/list.cpp @@ -7,6 +7,5 @@ List::List(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_list_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/mask/mask.cpp b/src/render/native/components/mask/mask.cpp index 2cc6055de..12c0eb10e 100644 --- a/src/render/native/components/mask/mask.cpp +++ b/src/render/native/components/mask/mask.cpp @@ -8,7 +8,6 @@ Mask::Mask(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->instance = lv_obj_create(lv_layer_top()); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); }; diff --git a/src/render/native/components/progressbar/progressbar.cpp b/src/render/native/components/progressbar/progressbar.cpp index 1aabe418e..aa3ff0b89 100644 --- a/src/render/native/components/progressbar/progressbar.cpp +++ b/src/render/native/components/progressbar/progressbar.cpp @@ -7,7 +7,6 @@ ProgressBar::ProgressBar(std::string uid, lv_obj_t* parent): BasicComponent(uid) this->uid = uid; this->instance = lv_bar_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/roller/roller.cpp b/src/render/native/components/roller/roller.cpp index 11da9b36f..dce38e6a6 100644 --- a/src/render/native/components/roller/roller.cpp +++ b/src/render/native/components/roller/roller.cpp @@ -6,7 +6,6 @@ Roller::Roller(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_roller_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/slider/slider.cpp b/src/render/native/components/slider/slider.cpp index 9b47cf907..06489de61 100644 --- a/src/render/native/components/slider/slider.cpp +++ b/src/render/native/components/slider/slider.cpp @@ -7,7 +7,6 @@ Slider::Slider(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_slider_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); diff --git a/src/render/native/components/switch/switch.cpp b/src/render/native/components/switch/switch.cpp index 9ddcc8e83..751a5a9a9 100644 --- a/src/render/native/components/switch/switch.cpp +++ b/src/render/native/components/switch/switch.cpp @@ -6,7 +6,6 @@ Switch::Switch(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_switch_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); }; diff --git a/src/render/native/components/tabview/tabview.cpp b/src/render/native/components/tabview/tabview.cpp index bb9746cd2..a0acf7673 100644 --- a/src/render/native/components/tabview/tabview.cpp +++ b/src/render/native/components/tabview/tabview.cpp @@ -7,7 +7,6 @@ TabView::TabView(std::string uid, uint32_t pos, uint32_t size, lv_obj_t* parent) this->uid = uid; this->instance = lv_tabview_create(parent != nullptr ? parent : GetWindowInstance(), pos, size); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); diff --git a/src/render/native/components/text/text.cpp b/src/render/native/components/text/text.cpp index 0f479248e..b42871a2b 100644 --- a/src/render/native/components/text/text.cpp +++ b/src/render/native/components/text/text.cpp @@ -7,7 +7,6 @@ Text::Text(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_label_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); this->initStyle(LV_PART_MAIN); diff --git a/src/render/native/components/textarea/textarea.cpp b/src/render/native/components/textarea/textarea.cpp index 4091dd1f5..892c69fb8 100644 --- a/src/render/native/components/textarea/textarea.cpp +++ b/src/render/native/components/textarea/textarea.cpp @@ -8,7 +8,6 @@ Textarea::Textarea(std::string uid, lv_obj_t* parent): BasicComponent(uid) { lv_obj_set_user_data(this->instance, this); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_CLICK_FOCUSABLE); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); this->initStyle(LV_PART_MAIN); this->initStyle(LV_STATE_FOCUSED); diff --git a/src/render/native/components/view/view.cpp b/src/render/native/components/view/view.cpp index bbbbe8678..52934c5c4 100644 --- a/src/render/native/components/view/view.cpp +++ b/src/render/native/components/view/view.cpp @@ -6,7 +6,6 @@ View::View(std::string uid, lv_obj_t* parent): BasicComponent(uid) { this->uid = uid; this->instance = lv_obj_create(parent != nullptr ? parent : GetWindowInstance()); - lv_obj_clear_flag(this->instance, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); // this->initStyle(LV_PART_MAIN); From f87334d5f1aeaee20877e11d79911d9506fbdc44 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 20 Jan 2026 14:38:56 +0800 Subject: [PATCH 27/62] chore(deps): upgrade lvgl from v8.3.0-dev to v8.4.0 This upgrade includes the fix for horizontal scroll-to-view bug: - fix(scroll): fix scroll to view to the left (commit 7c74f65) The bug caused focus_prev not working properly on horizontal scrollable containers (e.g., ViewPager with flex-row layout). --- deps/lvgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/lvgl b/deps/lvgl index 23c7b2dbf..4495f4286 160000 --- a/deps/lvgl +++ b/deps/lvgl @@ -1 +1 @@ -Subproject commit 23c7b2dbf2bf91ceb2a731fb428a9a796c6f36e2 +Subproject commit 4495f428630cc1741bd8bfd977f080e8460e8e8d From 0905a98144162be392ff6484700dec1be937d0c9 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 20 Jan 2026 14:41:55 +0800 Subject: [PATCH 28/62] feat: add addToFocusGroup prop to View component in ViewPager for improved focus management --- demo/viewpager/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/viewpager/index.tsx b/demo/viewpager/index.tsx index 451b4b3bc..86d955066 100644 --- a/demo/viewpager/index.tsx +++ b/demo/viewpager/index.tsx @@ -49,6 +49,7 @@ function App() { {Array.from({ length: pageCount }).map((_, i) => ( (pageRefs.current[i] = ins)} style={[ From 416d8fadc0c7ec2404114f3ecd92141cd594b2a6 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 20 Jan 2026 15:16:36 +0800 Subject: [PATCH 29/62] refactor: update ViewPager styles and enhance scrollbar behavior - Set default scrollbar mode to off for the window instance to streamline UI experience. --- demo/viewpager/index.tsx | 8 ++------ src/render/native/components/window/window.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/demo/viewpager/index.tsx b/demo/viewpager/index.tsx index 86d955066..47a36206b 100644 --- a/demo/viewpager/index.tsx +++ b/demo/viewpager/index.tsx @@ -117,19 +117,15 @@ const style: Record = { "border-width": 0, "border-radius": 0, - // flex 横向排布 display: "flex", - "flex-flow": 0, // LV_FLEX_FLOW_ROW(用数值是为了符合你们 style.cpp 的 JS_ToInt32) + "flex-direction": "column", - // 开启滚动 + 惯性 overflow: 0, // 0 -> add_flag(SCROLLABLE) "overflow-scrolling": 1, - // 开启 X 方向 snap(枚举值见 LV_SCROLL_SNAP_*) "scroll-snap-x": 3, // LV_SCROLL_SNAP_CENTER(本仓库 lvgl: NONE=0 START=1 END=2 CENTER=3) }, - // 每一页:固定为一屏大小,并允许被 snap page: { width, height: height - 80, @@ -151,7 +147,7 @@ const style: Record = { height: 80, display: "flex", "flex-flow": 0, // row - "justify-content": 3, // space-evenly(你们 style.cpp 直接把 int cast 成 lv_flex_align_t) + "justify-content": 3, // space-evenly "align-items": 2, // center "background-color": "grey", }, diff --git a/src/render/native/components/window/window.cpp b/src/render/native/components/window/window.cpp index 5c0b89579..7fb3d1349 100644 --- a/src/render/native/components/window/window.cpp +++ b/src/render/native/components/window/window.cpp @@ -14,6 +14,14 @@ lv_obj_t* GetWindowInstance () { // // this->initStyle(LV_PART_MAIN); // }; +static void scrollbar_mode_event_cb(lv_event_t * e) { + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CHILD_CREATED) { + lv_obj_t * child = (lv_obj_t *)lv_event_get_param(e); + if (child) lv_obj_set_scrollbar_mode(child, LV_SCROLLBAR_MODE_OFF); + } +} + void WindowInit () { lv_disp_t* disp_default = lv_disp_get_default(); window_instance = lv_obj_create(lv_scr_act()); @@ -22,4 +30,7 @@ void WindowInit () { lv_obj_set_style_pad_all(window_instance, 0, 0); lv_obj_set_style_radius(window_instance, 0, 0); lv_obj_set_style_border_width(window_instance, 0, 0); + + lv_obj_set_scrollbar_mode(window_instance, LV_SCROLLBAR_MODE_OFF); + lv_obj_add_event_cb(lv_scr_act(), scrollbar_mode_event_cb, LV_EVENT_CHILD_CREATED, NULL); }; From 1390ac76571ebd2267eb93eb0365612f184ce894 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 20 Jan 2026 17:21:50 +0800 Subject: [PATCH 30/62] fix: compile warnings --- src/render/native/components/chart/chart.cpp | 17 +++++++------ .../native/components/chart/chart_wrap.cpp | 6 ++--- .../components/dropdownlist/dropdownlist.cpp | 4 ++-- src/render/native/components/gif/gif_wrap.cpp | 4 +--- .../native/components/image/image_wrap.cpp | 7 ++---- .../native/components/line/line_wrap.cpp | 1 - src/render/native/components/mask/mask.cpp | 1 - .../native/components/roller/roller.cpp | 2 +- .../native/components/switch/switch_wrap.cpp | 24 ------------------- .../native/components/textarea/textarea.cpp | 3 +-- .../native/components/window/window.cpp | 2 ++ .../native/components/window/window.hpp | 2 -- src/render/native/core/basic/comp.cpp | 4 ++-- src/render/native/core/basic/comp.hpp | 2 +- src/render/native/core/event/click/click.cpp | 7 +++++- src/render/native/core/event/event.hpp | 1 + .../native/core/event/select/select.cpp | 2 ++ .../core/event/value_change/value_change.cpp | 5 +++- src/render/native/core/img/img.cpp | 1 - src/render/native/core/img/png/lodepng.cpp | 2 +- src/render/native/core/theme/theme.cpp | 3 +++ src/render/native/core/theme/theme.hpp | 4 ---- src/render/native/core/utils/utils.hpp | 2 +- 23 files changed, 43 insertions(+), 63 deletions(-) diff --git a/src/render/native/components/chart/chart.cpp b/src/render/native/components/chart/chart.cpp index 970aaf479..f4df5cd4f 100644 --- a/src/render/native/components/chart/chart.cpp +++ b/src/render/native/components/chart/chart.cpp @@ -62,7 +62,8 @@ void Chart::setBottomAxisOption ( }; void Chart::setLeftAxisData (std::vector& data) { - int32_t i, j, color; + size_t i,j; + int32_t color; axis_data item; for (i=0; ileft_axis.size(); i++) { @@ -88,7 +89,8 @@ void Chart::setLeftAxisData (std::vector& data) { }; void Chart::setRightAxisData (std::vector& data) { - int32_t i, j, color; + size_t i, j; + int32_t color; axis_data item; for (i=0; iright_axis.size(); i++) { @@ -159,13 +161,13 @@ void Chart::draw_event_cb (lv_event_t * e) { Chart* comp = (Chart*)e->user_data; - if(comp->bottom_axis_labels.size() > dsc->value && dsc->id == LV_CHART_AXIS_PRIMARY_X && dsc->text) { + if(comp->bottom_axis_labels.size() > static_cast(dsc->value) && dsc->id == LV_CHART_AXIS_PRIMARY_X && dsc->text) { lv_snprintf(dsc->text, dsc->text_length, "%s", comp->bottom_axis_labels[dsc->value].c_str()); - } else if (comp->left_axis_labels.size() > dsc->value && dsc->id == LV_CHART_AXIS_PRIMARY_Y && dsc->text) { + } else if (comp->left_axis_labels.size() > static_cast(dsc->value) && dsc->id == LV_CHART_AXIS_PRIMARY_Y && dsc->text) { lv_snprintf(dsc->text, dsc->text_length, "%s", comp->left_axis_labels[dsc->value].c_str()); - } else if (comp->right_axis_labels.size() > dsc->value && dsc->id == LV_CHART_AXIS_SECONDARY_Y && dsc->text) { + } else if (comp->right_axis_labels.size() > static_cast(dsc->value) && dsc->id == LV_CHART_AXIS_SECONDARY_Y && dsc->text) { lv_snprintf(dsc->text, dsc->text_length, "%s", comp->right_axis_labels[dsc->value].c_str()); - } else if (comp->top_axis_labels.size() > dsc->value && dsc->id == LV_CHART_AXIS_SECONDARY_X && dsc->text) { + } else if (comp->top_axis_labels.size() > static_cast(dsc->value) && dsc->id == LV_CHART_AXIS_SECONDARY_X && dsc->text) { lv_snprintf(dsc->text, dsc->text_length, "%s", comp->top_axis_labels[dsc->value].c_str()); } }; @@ -187,7 +189,8 @@ void Chart::setBottomAxisRange (int32_t min, int32_t max) { }; void Chart::setScatterData (std::vector& data) { - int32_t i, j, color; + size_t i, j; + int32_t color; axis_data item; for (i=0; ileft_axis.size(); i++) { diff --git a/src/render/native/components/chart/chart_wrap.cpp b/src/render/native/components/chart/chart_wrap.cpp index 3430c4f5f..f63f9242a 100644 --- a/src/render/native/components/chart/chart_wrap.cpp +++ b/src/render/native/components/chart/chart_wrap.cpp @@ -347,7 +347,7 @@ static JSValue NativeCompSetLeftAxisData(JSContext *ctx, JSValueConst this_val, COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); std::vector data; - int32_t len1, len2, i, color, data_item; + int32_t len1, len2, color, data_item; JSValue item_value; JSValue color_value; JSValue data_value; @@ -396,7 +396,7 @@ static JSValue NativeCompSetRightAxisData(JSContext *ctx, JSValueConst this_val, COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); std::vector data; - int32_t len1, len2, i, color, data_item; + int32_t len1, len2, color, data_item; JSValue item_value; JSValue color_value; JSValue data_value; @@ -445,7 +445,7 @@ static JSValue NativeCompSetScatterData (JSContext *ctx, JSValueConst this_val, COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, ChartClassID); std::vector data; - int32_t len1, len2, i, color, data_item; + int32_t len1, len2, color, data_item; JSValue item_value; JSValue color_value; JSValue data_value; diff --git a/src/render/native/components/dropdownlist/dropdownlist.cpp b/src/render/native/components/dropdownlist/dropdownlist.cpp index 4c66eb0b2..c96a5e218 100644 --- a/src/render/native/components/dropdownlist/dropdownlist.cpp +++ b/src/render/native/components/dropdownlist/dropdownlist.cpp @@ -16,7 +16,7 @@ void Dropdownlist::setItems (std::vector& items) { lv_dropdown_clear_options(this->instance); } else { std::string str; - for(int i=0; i < items.size(); i++) { + for(size_t i=0; i < items.size(); i++) { std::string item = items[i]; item.append("\n"); str.append(item.c_str()); @@ -40,7 +40,7 @@ void Dropdownlist::setDir (lv_dir_t dir) { }; void Dropdownlist::setArrowDir (int32_t dir) { - const void* arrow; + const void* arrow = nullptr; switch (dir) { case DROPDOWNLIST_UP: diff --git a/src/render/native/components/gif/gif_wrap.cpp b/src/render/native/components/gif/gif_wrap.cpp index 029570e8c..df35df80c 100644 --- a/src/render/native/components/gif/gif_wrap.cpp +++ b/src/render/native/components/gif/gif_wrap.cpp @@ -25,10 +25,8 @@ static JSValue NativeCompSetGIFBinary(JSContext *ctx, JSValueConst this_val, int LV_LOG_USER("GIF %s setGIF", s->uid); return JS_NewBool(ctx, 1); - fail: - return JS_ThrowInternalError(ctx, "GIF setBinary fail"); } - return JS_UNDEFINED; + return JS_ThrowInternalError(ctx, "GIF setBinary fail"); }; static const JSCFunctionListEntry ComponentProtoFuncs[] = { diff --git a/src/render/native/components/image/image_wrap.cpp b/src/render/native/components/image/image_wrap.cpp index 929b3802d..b592599ec 100644 --- a/src/render/native/components/image/image_wrap.cpp +++ b/src/render/native/components/image/image_wrap.cpp @@ -25,10 +25,8 @@ static JSValue NativeCompSetImageBinary(JSContext *ctx, JSValueConst this_val, i LV_LOG_USER("Image %s setImage", s->uid); return JS_NewBool(ctx, 1); - fail: - return JS_ThrowInternalError(ctx, "image setBinary fail"); } - return JS_UNDEFINED; + return JS_ThrowInternalError(ctx, "image setBinary fail"); }; static JSValue NativeCompSetSymbol(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -44,9 +42,8 @@ static JSValue NativeCompSetSymbol(JSContext *ctx, JSValueConst this_val, int ar JS_FreeCString(ctx, str); return JS_NewBool(ctx, 1); - fail: - return JS_ThrowInternalError(ctx, "image setSymbol fail"); } + return JS_ThrowInternalError(ctx, "image setSymbol fail"); return JS_UNDEFINED; }; diff --git a/src/render/native/components/line/line_wrap.cpp b/src/render/native/components/line/line_wrap.cpp index ff84cf8a4..416d565a0 100644 --- a/src/render/native/components/line/line_wrap.cpp +++ b/src/render/native/components/line/line_wrap.cpp @@ -7,7 +7,6 @@ WRAPPED_JS_AddEventListener(Line, "Line") WRAPPED_JS_Align(Line, "Line") WRAPPED_JS_Align_To(Line, "Line") STYLE_INFO(Line, "Line") -WRAPPED_JS_BACKGROUND_IMAGE(Line,"Line") WRAPPED_MOVE_TO_FRONT(Line, "Line") WRAPPED_MOVE_TO_BACKGROUND(Line, "Line") WRAPPED_SCROLL_INTO_VIEW(Line, "Line") diff --git a/src/render/native/components/mask/mask.cpp b/src/render/native/components/mask/mask.cpp index 12c0eb10e..ef0e8d667 100644 --- a/src/render/native/components/mask/mask.cpp +++ b/src/render/native/components/mask/mask.cpp @@ -14,7 +14,6 @@ Mask::Mask(std::string uid, lv_obj_t* parent): BasicComponent(uid) { void Mask::initCompStyle (int32_t type) { this->ensureStyle(type); - lv_style_t* style = this->style_map.at(type); uint32_t width, height; lv_disp_t* disp_default = lv_disp_get_default(); diff --git a/src/render/native/components/roller/roller.cpp b/src/render/native/components/roller/roller.cpp index dce38e6a6..7b1583a56 100644 --- a/src/render/native/components/roller/roller.cpp +++ b/src/render/native/components/roller/roller.cpp @@ -15,7 +15,7 @@ void Roller::setOptions (std::vector& options, uint32_t mode) { lv_roller_set_options(this->instance, "\0", mode); } else { std::string str; - for(int i=0; i < options.size(); i++) { + for(size_t i=0; i < options.size(); i++) { std::string item = options[i]; str.append(item.c_str()); if (i != options.size() - 1) { diff --git a/src/render/native/components/switch/switch_wrap.cpp b/src/render/native/components/switch/switch_wrap.cpp index 4ac9c251e..b2945fcc0 100644 --- a/src/render/native/components/switch/switch_wrap.cpp +++ b/src/render/native/components/switch/switch_wrap.cpp @@ -14,30 +14,6 @@ WRAPPED_SCROLL_INTO_VIEW(Switch, "Switch") WRAPPED_FOCUS(Switch, "Switch") WRAPPED_JS_CLOSE_COMPONENT(Switch, "Switch") -static JSValue NativeCompRemoveChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsObject(argv[0])) { - JSClassID _class_id; - COMP_REF* child = (COMP_REF*)JS_GetAnyOpaque(argv[0], &_class_id); - COMP_REF* parent = (COMP_REF*)JS_GetOpaque(this_val, SwitchClassID); - - ((Switch*)(parent->comp))->removeChild((void*)(child->comp)); - LV_LOG_USER("Switch %s remove child %s", parent->uid, child->uid); - } - return JS_UNDEFINED; -}; - -static JSValue NativeCompAppendChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc >= 1 && JS_IsObject(argv[0])) { - JSClassID _class_id; - COMP_REF* child = (COMP_REF*)JS_GetAnyOpaque(argv[0], &_class_id); - COMP_REF* parent = (COMP_REF*)JS_GetOpaque(this_val, SwitchClassID); - - ((Switch*)(parent->comp))->appendChild((void*)(child->comp)); - LV_LOG_USER("Switch %s append child %s", parent->uid, child->uid); - } - return JS_UNDEFINED; -}; - static JSValue NativeCompSetChecked(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { if (argc >= 1 && JS_IsBool(argv[0])) { COMP_REF* ref = (COMP_REF*)JS_GetOpaque(this_val, SwitchClassID); diff --git a/src/render/native/components/textarea/textarea.cpp b/src/render/native/components/textarea/textarea.cpp index 892c69fb8..7fff21c42 100644 --- a/src/render/native/components/textarea/textarea.cpp +++ b/src/render/native/components/textarea/textarea.cpp @@ -21,9 +21,8 @@ void Textarea::raiseKeyboard (lv_event_t* event) { lv_obj_t* keyboard = lv_keyboard_create(lv_layer_top()); comp->keyboard = keyboard; - uint32_t width, height; + uint32_t height; lv_disp_t* disp_default = lv_disp_get_default(); - width = disp_default->driver->hor_res; height = disp_default->driver->ver_res; lv_keyboard_set_textarea(keyboard, comp->instance); diff --git a/src/render/native/components/window/window.cpp b/src/render/native/components/window/window.cpp index 7fb3d1349..8c3e7d0bb 100644 --- a/src/render/native/components/window/window.cpp +++ b/src/render/native/components/window/window.cpp @@ -1,6 +1,8 @@ #include "window.hpp" +lv_obj_t* window_instance = nullptr; + lv_obj_t* GetWindowInstance () { return window_instance; }; diff --git a/src/render/native/components/window/window.hpp b/src/render/native/components/window/window.hpp index f8c6ad844..324b86b6a 100644 --- a/src/render/native/components/window/window.hpp +++ b/src/render/native/components/window/window.hpp @@ -4,8 +4,6 @@ #include "native/components/component.hpp" #include "native/core/basic/comp.hpp" -static lv_obj_t* window_instance; - // class Window : public BasicComponent { // public: // Window(std::string uid); diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index b53de054d..d44211f94 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -165,7 +165,7 @@ void BasicComponent::setStyle(JSContext* ctx, JSValue& obj, std::vectorinitStyle(type); // } - for(int i=0; i < keys.size(); i++) { + for(size_t i=0; i < keys.size(); i++) { std::string key = keys[i]; if (StyleManager::styles.count(key) > 0) { @@ -176,7 +176,7 @@ void BasicComponent::setStyle(JSContext* ctx, JSValue& obj, std::vectorinstance); if(id == LV_CHART_POINT_NONE) break; JSValue result = JS_NewArray(ctx); @@ -63,6 +65,9 @@ static JSValue GetPressedPointPos (JSContext* ctx, JSValueConst this_val) { return result; break; + } + default: + break; } return JS_UNDEFINED; diff --git a/src/render/native/core/event/event.hpp b/src/render/native/core/event/event.hpp index 4c25065f1..2d9db91c1 100644 --- a/src/render/native/core/event/event.hpp +++ b/src/render/native/core/event/event.hpp @@ -56,6 +56,7 @@ static std::map WrapEventDict { if (ref) { \ ref->stop_bubbling = 1; \ } \ + return JS_UNDEFINED; \ }; \ \ diff --git a/src/render/native/core/event/select/select.cpp b/src/render/native/core/event/select/select.cpp index 37aa3db0e..3e32ce76a 100644 --- a/src/render/native/core/event/select/select.cpp +++ b/src/render/native/core/event/select/select.cpp @@ -27,6 +27,8 @@ static JSValue GetValue (JSContext* ctx, JSValueConst this_val) { if(value_num == LV_CHART_POINT_NONE) break; return JS_NewInt32(ctx, value_num); break; + default: + break; } return JS_UNDEFINED; diff --git a/src/render/native/core/event/value_change/value_change.cpp b/src/render/native/core/event/value_change/value_change.cpp index a72056a88..f20f73011 100644 --- a/src/render/native/core/event/value_change/value_change.cpp +++ b/src/render/native/core/event/value_change/value_change.cpp @@ -70,7 +70,7 @@ static JSValue GetValue (JSContext* ctx, JSValueConst this_val) { lv_roller_get_selected_str(comp->instance, buf, sizeof(buf)); return JS_NewString(ctx, buf); - case COMP_TYPE_CALENDAR: + case COMP_TYPE_CALENDAR: { lv_calendar_date_t date; std::string result; lv_calendar_get_pressed_date(comp->instance, &date); @@ -80,6 +80,9 @@ static JSValue GetValue (JSContext* ctx, JSValueConst this_val) { result.append("-"); result.append(std::to_string(date.day)); return JS_NewString(ctx, result.c_str()); + } + default: + break; } return JS_UNDEFINED; diff --git a/src/render/native/core/img/img.cpp b/src/render/native/core/img/img.cpp index 326085d31..64da77154 100644 --- a/src/render/native/core/img/img.cpp +++ b/src/render/native/core/img/img.cpp @@ -29,7 +29,6 @@ uint8_t* GetImgDesc (uint8_t* buf, size_t len, lv_img_dsc_t_1* image_desc) { return nullptr; } - lv_img_dsc_t_1* prev_desc = image_desc; image_desc->type = image_type; image_desc->header.always_zero = 0; diff --git a/src/render/native/core/img/png/lodepng.cpp b/src/render/native/core/img/png/lodepng.cpp index eafbb9a9b..5b2c8e443 100644 --- a/src/render/native/core/img/png/lodepng.cpp +++ b/src/render/native/core/img/png/lodepng.cpp @@ -612,7 +612,7 @@ static unsigned readBits(LodePNGBitReader* reader, size_t nbits) { } /* Public for testing only. steps and result must have numsteps values. */ -static unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, +[[maybe_unused]] static unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, size_t numsteps, const size_t* steps, unsigned* result) { size_t i; LodePNGBitReader reader; diff --git a/src/render/native/core/theme/theme.cpp b/src/render/native/core/theme/theme.cpp index 819d9b06d..588093837 100644 --- a/src/render/native/core/theme/theme.cpp +++ b/src/render/native/core/theme/theme.cpp @@ -1,5 +1,8 @@ #include "./theme.hpp" +static lv_theme_t theme_default; +static bool theme_default_init = false; + static void ThemeDefaultInit () { if (theme_default_init == false) { theme_default_init = true; diff --git a/src/render/native/core/theme/theme.hpp b/src/render/native/core/theme/theme.hpp index 09e0c32b2..b684acf41 100644 --- a/src/render/native/core/theme/theme.hpp +++ b/src/render/native/core/theme/theme.hpp @@ -8,8 +8,4 @@ extern "C" { #include "native/core/style/font/font.hpp" -static lv_theme_t theme_default; - -static bool theme_default_init = false; - void NativeThemeInit (JSContext* ctx, JSValue& ns); \ No newline at end of file diff --git a/src/render/native/core/utils/utils.hpp b/src/render/native/core/utils/utils.hpp index 1fe495d01..2cabd43d3 100644 --- a/src/render/native/core/utils/utils.hpp +++ b/src/render/native/core/utils/utils.hpp @@ -54,7 +54,7 @@ class MemoryPool { free_block_head = &(new_chunk->blocks[0]); // link the new chunk's all blocks - for (int i = 1; i < BlockNum; i++) + for (size_t i = 1; i < BlockNum; i++) new_chunk->blocks[i - 1].next = &(new_chunk->blocks[i]); new_chunk->blocks[BlockNum - 1].next = NULL; // final block next is NULL From 189655c915853364bdf278b92d3b90f52d16e203 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 20 Jan 2026 19:00:23 +0800 Subject: [PATCH 31/62] feat: enhance child insertion logic in BasicComponent - Updated insertChildBefore method to accept an additional parameter for specifying the child before which to insert. - Modified the corresponding native component wrapper to support the new insertion logic. - Introduced reorderFocusGroup utility to manage focus order after child insertion. --- src/render/native/components/component.hpp | 5 +- src/render/native/core/basic/comp.cpp | 8 ++- src/render/native/core/basic/comp.hpp | 2 +- src/render/native/core/utils/utils.cpp | 67 ++++++++++++++++++++++ src/render/native/core/utils/utils.hpp | 3 +- 5 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/render/native/components/component.hpp b/src/render/native/components/component.hpp index 718f787f1..aec0d99c2 100644 --- a/src/render/native/components/component.hpp +++ b/src/render/native/components/component.hpp @@ -104,12 +104,13 @@ void NativeComponentMaskInit (JSContext* ctx, JSValue ns); #define WRAPPED_INSERT_CHILD(COMPONENT,COMPONENT_NAME) \ static JSValue NativeCompInsertChildBefore(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \ - if (argc >= 1 && JS_IsObject(argv[0])) { \ + if (argc >= 1 && JS_IsObject(argv[0]) && JS_IsObject(argv[1])) { \ JSClassID _class_id; \ COMP_REF* child = (COMP_REF*)JS_GetAnyOpaque(argv[0], &_class_id); \ + COMP_REF* beforeChild = (COMP_REF*)JS_GetAnyOpaque(argv[1], &_class_id); \ COMP_REF* parent = (COMP_REF*)JS_GetAnyOpaque(this_val, &_class_id); \ \ - ((COMPONENT*)(parent->comp))->insertChildBefore((void*)(child->comp)); \ + ((COMPONENT*)(parent->comp))->insertChildBefore((void*)(child->comp), (void*)(beforeChild->comp)); \ LV_LOG_USER("%s %s insertChildBefore %s", COMPONENT_NAME, parent->uid, child->uid); \ } \ return JS_UNDEFINED; \ diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index d44211f94..bf2a64041 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -35,13 +35,15 @@ bool BasicComponent::isEventRegist(int eventType) { return this->registeEvents.count(eventType) > 0; }; -void BasicComponent::insertChildBefore(void *child) { - BasicComponent* childComp = static_cast(child); +void BasicComponent::insertChildBefore(void *child, void *beforeChild) { + BasicComponent* childComp = static_cast(child); + BasicComponent* beforeChildComp = static_cast(beforeChild); childComp->parent_instance = this->instance; if (!childComp->is_fixed && childComp->type != COMP_TYPE_MASK) { lv_obj_set_parent(childComp->instance, this->instance); - uint32_t index = lv_obj_get_index(childComp->instance); + uint32_t index = lv_obj_get_index(beforeChildComp->instance); lv_obj_move_to_index(childComp->instance, index); + reorderFocusGroup(this->instance); } }; diff --git a/src/render/native/core/basic/comp.hpp b/src/render/native/core/basic/comp.hpp index 140b84064..9d4c44a16 100644 --- a/src/render/native/core/basic/comp.hpp +++ b/src/render/native/core/basic/comp.hpp @@ -79,7 +79,7 @@ class BasicComponent { void appendChild(void* child); void removeChild(void* child); - void insertChildBefore(void *child); + void insertChildBefore(void *child, void *beforeChild); void moveToFront (); void moveToBackground (); diff --git a/src/render/native/core/utils/utils.cpp b/src/render/native/core/utils/utils.cpp index e69de29bb..4f162c499 100644 --- a/src/render/native/core/utils/utils.cpp +++ b/src/render/native/core/utils/utils.cpp @@ -0,0 +1,67 @@ +#include "./utils.hpp" +#include +#include +#include +#include +#include + +extern "C" { + #include "lvgl.h" + #include "private.h" +}; + +static void getDesiredOrder(lv_obj_t* parent, std::vector& desired, lv_group_t* def_group) { + // Desired order: parent's children order, but only those currently in default group. + if (!parent || !def_group) return; + uint32_t child_cnt = lv_obj_get_child_cnt(parent); + for (uint32_t i = 0; i < child_cnt; i++) { + lv_obj_t* child = lv_obj_get_child(parent, i); + if (!child) continue; + if (lv_obj_get_group(child) == def_group) desired.push_back(child); + } +} + +static size_t getMatchedSize(lv_group_t* def_group, std::vector& desired, + std::unordered_map& node_of +) { + size_t matched_size = 0; + node_of.reserve(desired.size()); + + void* node; + _LV_LL_READ(&def_group->obj_ll, node) { + lv_obj_t** obj_i = static_cast(node); + lv_obj_t* obj = *obj_i; + if (std::find(desired.begin(), desired.end(), obj) != desired.end()) { + if (desired[matched_size] == obj) matched_size++; + node_of[obj] = node; + if (matched_size == desired.size()) break; + } + } + return matched_size; +} + +static void startReorder(lv_group_t* def_group, std::vector& desired, + std::unordered_map& node_of +) { + for (size_t i = desired.size() - 1; i > 0; i--) { + void* n_act = node_of[desired[i - 1]]; + void* n_after = node_of[desired[i]]; + if (n_act && n_after && n_act != n_after) { + _lv_ll_move_before(&def_group->obj_ll, n_act, n_after); + } + } +} + +void reorderFocusGroup(lv_obj_t * parent) { + if (!parent) return; + + std::vector desired; + getDesiredOrder(parent, desired, lv_group_get_default()); + if (desired.size() < 2) return; + + std::unordered_map node_of; + size_t matched_size = getMatchedSize(lv_group_get_default(), desired, node_of); + if (matched_size == desired.size()) return; + + startReorder(lv_group_get_default(), desired, node_of); +} \ No newline at end of file diff --git a/src/render/native/core/utils/utils.hpp b/src/render/native/core/utils/utils.hpp index 2cabd43d3..7cfe150d7 100644 --- a/src/render/native/core/utils/utils.hpp +++ b/src/render/native/core/utils/utils.hpp @@ -7,10 +7,11 @@ extern "C" { #include "lvgl.h" - #include "private.h" }; +void reorderFocusGroup(lv_obj_t * parent); + template class MemoryPool { public: From cb5499a0cd76a57db51d5031fc890b343a45d6be Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 21 Jan 2026 14:39:58 +0800 Subject: [PATCH 32/62] refactor: simplify Window component by removing unused code - Updated GetWindowInstance to return the active screen directly. --- .../native/components/window/window.cpp | 22 +------------------ .../native/components/window/window.hpp | 5 ----- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/src/render/native/components/window/window.cpp b/src/render/native/components/window/window.cpp index 8c3e7d0bb..e4a40e4ff 100644 --- a/src/render/native/components/window/window.cpp +++ b/src/render/native/components/window/window.cpp @@ -1,21 +1,10 @@ #include "window.hpp" -lv_obj_t* window_instance = nullptr; - lv_obj_t* GetWindowInstance () { - return window_instance; + return lv_scr_act(); }; -// Window::Window(std::string uid): BasicComponent(uid) { -// this->uid = uid; -// this->instance = lv_obj_create(lv_scr_act()); -// window_instance = this->instance; -// lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); -// lv_obj_set_user_data(this->instance, this); -// // this->initStyle(LV_PART_MAIN); -// }; - static void scrollbar_mode_event_cb(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); if (code == LV_EVENT_CHILD_CREATED) { @@ -25,14 +14,5 @@ static void scrollbar_mode_event_cb(lv_event_t * e) { } void WindowInit () { - lv_disp_t* disp_default = lv_disp_get_default(); - window_instance = lv_obj_create(lv_scr_act()); - lv_obj_set_style_height(window_instance, disp_default->driver->ver_res, 0); - lv_obj_set_style_width(window_instance, disp_default->driver->hor_res, 0); - lv_obj_set_style_pad_all(window_instance, 0, 0); - lv_obj_set_style_radius(window_instance, 0, 0); - lv_obj_set_style_border_width(window_instance, 0, 0); - - lv_obj_set_scrollbar_mode(window_instance, LV_SCROLLBAR_MODE_OFF); lv_obj_add_event_cb(lv_scr_act(), scrollbar_mode_event_cb, LV_EVENT_CHILD_CREATED, NULL); }; diff --git a/src/render/native/components/window/window.hpp b/src/render/native/components/window/window.hpp index 324b86b6a..3b8003196 100644 --- a/src/render/native/components/window/window.hpp +++ b/src/render/native/components/window/window.hpp @@ -3,8 +3,3 @@ #include "native/components/component.hpp" #include "native/core/basic/comp.hpp" - -// class Window : public BasicComponent { -// public: -// Window(std::string uid); -// }; \ No newline at end of file From 1b333c4c83619507b9efbddec0d7bb1b77728636 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 21 Jan 2026 14:49:13 +0800 Subject: [PATCH 33/62] feat: implement new Page2Info component with enhanced navigation and styling - Introduced Page2Info component to manage a paginated view with scrollable pages. - Replaced previous ViewPager implementation with a more streamlined approach using refs for page management. --- demo/navigation/index.tsx | 176 +++++++++++++++++++++++---------- demo/viewpager/index.tsx | 199 -------------------------------------- 2 files changed, 125 insertions(+), 250 deletions(-) delete mode 100644 demo/viewpager/index.tsx diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 61c6a47bf..db92dcc8f 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -78,59 +78,81 @@ function Page1List() { } function Page2Info() { + const pageCount = 4; + const pagerRef = useRef(); + const pageRefs = useRef([]); + + const [active, setActive] = useState(0); const t = useT(); - const infos = useMemo( - () => [ - { titleKey: "p2.a.title", bodyKey: "p2.a.body" }, - { titleKey: "p2.b.title", bodyKey: "p2.b.body" }, - { titleKey: "p2.c.title", bodyKey: "p2.c.body" }, - { titleKey: "p2.d.title", bodyKey: "p2.d.body" }, - { titleKey: "p2.e.title", bodyKey: "p2.e.body" }, - ], - [], + + const pageColors = useMemo( + () => ["red", "blue", "green", "orange"], + [] ); - const [idx, setIdx] = useState(0); - const cur = infos[idx]; + const scrollTo = (idx: number) => { + if (idx < 0 || idx >= pageCount) return; + setActive(idx); + const target = pageRefs.current[idx]; + target?.scrollIntoView?.(); + }; + + useEffect(() => { + scrollTo(0); + }, []); - const prev = () => setIdx((i) => (i - 1 + infos.length) % infos.length); - const next = () => setIdx((i) => (i + 1) % infos.length); return (
- - - - {t(cur.titleKey)} - {t(cur.bodyKey)} - - - - + Page {i + 1} + + flex-row + scroll-snap-x + scrollIntoView() + + + ))} + - - + + - {infos.map((_, i) => ( + {Array.from({ length: pageCount }).map((_, i) => ( ))} + + ); @@ -443,31 +465,83 @@ const style: Record = { "align-items": "center", }, navBtn: { - width: 64, - height: 44, - "border-radius": 12, + width: 60, + height: 50, + "border-radius": 25, "background-color": "white", - display: "flex", - "align-items": "center", - "justify-content": "center", }, navBtnText: { "text-color": "black", "font-size": 18 }, dots: { - width: width - 24, - height: 30, display: "flex", - "flex-direction": "row", - "justify-content": "center", - "align-items": "center", + "flex-flow": 0, // row + "justify-content": 3, + "align-items": 2, + width: width - 140, + height: 50, }, dot: { width: 10, height: 10, "border-radius": 0x7fff, - margin: "0 4px", }, - dotActive: { "background-color": "white", opacity: 255 }, - dotInactive: { "background-color": "grey", opacity: 80 }, + dotActive: { + "background-color": "white", + opacity: 255, + }, + dotInactive: { + "background-color": "grey", + opacity: 80, + }, + pageFocused: { + "background-color": "white", + opacity: 255, + }, + // 横向滚动容器 + pager: { + width, + height: height - 80, + "border-width": 0, + "border-radius": 0, + + display: "flex", + "flex-direction": "column", + + overflow: 0, // 0 -> add_flag(SCROLLABLE) + "overflow-scrolling": 1, + + "scroll-snap-x": 3, // LV_SCROLL_SNAP_CENTER(本仓库 lvgl: NONE=0 START=1 END=2 CENTER=3) + }, + page: { + width, + height: height - 80, + "border-radius": 0, + "border-width": 0, + "padding": 16, + "scroll-enable-snap": 1, + }, + pageTitle: { + "text-color": "white", + }, + pageDesc: { + "text-color": "white", + }, + controls: { + width, + height: 80, + display: "flex", + "flex-flow": 0, // row + "justify-content": 3, // space-evenly + "align-items": 2, // center + "background-color": "grey", + }, + debugBar: { + width, + height: 40, + "background-color": "black", + }, + debugText: { + "text-color": "white", + }, sectionTitle: { "text-color": "white", diff --git a/demo/viewpager/index.tsx b/demo/viewpager/index.tsx deleted file mode 100644 index 47a36206b..000000000 --- a/demo/viewpager/index.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { AddChildToDefGroup, Button, Dimensions, Render, Text, View } from "lvgljs-ui"; - -const { width, height } = Dimensions.window; - -/** - * 纯 View + flex + scroll-snap 的 “ViewPager” demo - * - * - pager: 横向 flex 容器,可滚动 - * - page: 每页固定宽高,并开启 snappable - * - 导航点: 底部一排小圆点 + prev/next 按钮(方便在没手势时测试) - */ -function App() { - const pageCount = 4; - const pagerRef = useRef(); - const pageRefs = useRef([]); - - const [active, setActive] = useState(0); - const [debug, setDebug] = useState(""); - - const pageColors = useMemo( - () => ["red", "blue", "green", "orange"], - [] - ); - - const scrollTo = (idx: number) => { - if (idx < 0 || idx >= pageCount) return; - setActive(idx); - // 让对应 page 滚动进可视区域(LVGL 内部会按 snap 对齐) - const target = pageRefs.current[idx]; - const left = target?.style?.left; - target?.scrollIntoView?.(); - const lefts = pageRefs.current.map((p) => p?.style?.left); - setDebug(JSON.stringify({ idx, hasRef: !!target, left, lefts })); - }; - - useEffect(() => { - // 初始定位到第 0 页 - scrollTo(0); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - - - {Array.from({ length: pageCount }).map((_, i) => ( - (pageRefs.current[i] = ins)} - style={[ - style.page, - { "background-color": pageColors[i % pageColors.length] }, - ]} - > - Page {i + 1} - - flex-row + scroll-snap-x + scrollIntoView() - - - ))} - - - - - - - {Array.from({ length: pageCount }).map((_, i) => ( - - ))} - - - - - - - {debug} - - - ); -} - -const style: Record = { - root: { - width, - height, - padding: 0, - "border-width": 0, - "border-radius": 0, - "background-color": "black", - }, - - // 横向滚动容器 - pager: { - width, - height: height - 80, - "border-width": 0, - "border-radius": 0, - - display: "flex", - "flex-direction": "column", - - overflow: 0, // 0 -> add_flag(SCROLLABLE) - "overflow-scrolling": 1, - - "scroll-snap-x": 3, // LV_SCROLL_SNAP_CENTER(本仓库 lvgl: NONE=0 START=1 END=2 CENTER=3) - }, - - page: { - width, - height: height - 80, - "border-radius": 0, - "border-width": 0, - "padding": 16, - "scroll-enable-snap": 1, - }, - - pageTitle: { - "text-color": "white", - }, - pageDesc: { - "text-color": "white", - }, - - controls: { - width, - height: 80, - display: "flex", - "flex-flow": 0, // row - "justify-content": 3, // space-evenly - "align-items": 2, // center - "background-color": "grey", - }, - - navBtn: { - width: 60, - height: 50, - "border-radius": 25, - "background-color": "white", - }, - - dots: { - display: "flex", - "flex-flow": 0, // row - "justify-content": 3, - "align-items": 2, - width: width - 140, - height: 50, - }, - - dot: { - width: 10, - height: 10, - "border-radius": 0x7fff, - }, - dotActive: { - "background-color": "white", - opacity: 255, - }, - dotInactive: { - "background-color": "grey", - opacity: 80, - }, - pageFocused: { - "background-color": "white", - opacity: 255, - }, - debugBar: { - width, - height: 40, - "background-color": "black", - }, - debugText: { - "text-color": "white", - }, -}; - -Render.render(); - From 60caf8ab3bca915ed5cea74ac29d3a9a603cde60 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 21 Jan 2026 14:51:32 +0800 Subject: [PATCH 34/62] style: add overflow hidden to navigation container for improved layout management --- demo/navigation/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index db92dcc8f..34756ce5f 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -376,6 +376,7 @@ const style: Record = { "background-color": "black", display: "flex", "flex-direction": "column", + overflow: "hidden", }, header: { From dd1992b5391d44cf86791d7042de6b603b1cba4f Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 21 Jan 2026 18:32:12 +0800 Subject: [PATCH 35/62] refactor: replace CommonComponentApi with setComponentProps in multiple components - Updated components including Arc, Button, Calendar, Canvas, Chart, Checkbox, Dropdownlist, GIF, Image, Input, Keyboard, Line, Mask, ProgressBar, Roller, Slider, Switch, Tabs, Text, Textarea, View, and Window to utilize setComponentProps for improved property management. - This change enhances consistency across components and simplifies the property setting logic. --- src/render/react/components/Arc/comp.ts | 219 +++++---- src/render/react/components/Button/comp.ts | 73 ++- src/render/react/components/Calendar/comp.ts | 76 ++- src/render/react/components/Canvas/comp.ts | 63 +-- src/render/react/components/Chart/comp.ts | 441 +++++++++--------- src/render/react/components/Checkbox/comp.ts | 117 +++-- .../react/components/Dropdownlist/comp.ts | 100 ++-- src/render/react/components/GIF/comp.ts | 81 ++-- src/render/react/components/Image/comp.ts | 80 ++-- src/render/react/components/Input/comp.ts | 117 +++-- src/render/react/components/Keyboard/comp.ts | 60 +-- src/render/react/components/Line/comp.ts | 48 +- src/render/react/components/Mask/comp.ts | 73 ++- .../react/components/ProgressBar/comp.ts | 99 ++-- src/render/react/components/Roller/comp.ts | 87 ++-- src/render/react/components/Slider/comp.ts | 151 +++--- src/render/react/components/Switch/comp.ts | 72 ++- src/render/react/components/Tabs/comp.ts | 57 +-- src/render/react/components/Text/comp.ts | 56 +-- src/render/react/components/Textarea/comp.ts | 101 ++-- src/render/react/components/View/comp.ts | 33 +- src/render/react/components/Window/comp.ts | 42 +- src/render/react/components/common/index.ts | 247 +++++----- 23 files changed, 1111 insertions(+), 1382 deletions(-) diff --git a/src/render/react/components/Arc/comp.ts b/src/render/react/components/Arc/comp.ts index 5a5b6ef05..e3a0d8d54 100644 --- a/src/render/react/components/Arc/comp.ts +++ b/src/render/react/components/Arc/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -35,120 +35,108 @@ export type ArcProps = CommonProps & { changeRate?: number; }; -function setArcProps(comp, newProps: ArcProps, oldProps: ArcProps) { - const setter = { - ...CommonComponentApi({ compName: "Arc", comp, newProps, oldProps }), - indicatorStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Arc", - styleType: STYLE_TYPE.PART_INDICATOR, - oldStyleSheet: oldProps.indicatorStyle, - }); - }, - onIndicatorPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Arc", - styleType: STYLE_TYPE.PART_INDICATOR | STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onIndicatorPressedStyle, - }); - }, - onPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Arc", - styleType: STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onPressedStyle, - }); - }, - knobStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Arc", - styleType: STYLE_TYPE.PART_KNOB, - oldStyleSheet: oldProps.knobStyle, - }); - }, - onKnobPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Arc", - styleType: STYLE_TYPE.PART_KNOB | STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onKnobPressedStyle, - }); - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - range(arr) { - if (!Array.isArray(arr)) return; - const [min, max] = arr; - if (min === oldProps.range?.[0] && max === oldProps.range?.[1]) return; - if (isNaN(min) || isNaN(max)) return; - comp.setRange([min, max]); - }, - value(val) { - if (isNaN(val)) return; - if (val == oldProps.value) return; - comp.setValue(val); - }, - startAngle(val) { - if (isNaN(val)) return; - if (val == oldProps.startAngle) return; - comp.setStartAngle(val); - }, - endAngle(val) { - if (isNaN(val)) return; - if (val == oldProps.endAngle) return; - comp.setEndAngle(val); - }, - backgroundStartAngle(val) { - if (isNaN(val)) return; - if (val == oldProps.backgroundStartAngle) return; - comp.setBackgroundStartAngle(val); - }, - backgroundEndAngle(val) { - if (isNaN(val)) return; - if (val == oldProps.backgroundEndAngle) return; - comp.setBackgroundEndAngle(val); - }, - rotation(val) { - if (isNaN(val)) return; - if (val == oldProps.rotation) return; - comp.setRotation(val); - }, - mode(val) { - if (val !== oldProps.mode && typeof modes[val] !== "undefined") { - comp.setMode(modes[val]); - } - }, - changeRate(val) { - if (isNaN(val)) return; - if (val == oldProps.changeRate) return; - comp.setChangeRate(val); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; +const arcSetters = { + indicatorStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Arc", + styleType: STYLE_TYPE.PART_INDICATOR, + oldStyleSheet: oldProps.indicatorStyle, + }); + }, + onIndicatorPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Arc", + styleType: STYLE_TYPE.PART_INDICATOR | STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onIndicatorPressedStyle, + }); + }, + onPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Arc", + styleType: STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onPressedStyle, + }); + }, + knobStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Arc", + styleType: STYLE_TYPE.PART_KNOB, + oldStyleSheet: oldProps.knobStyle, + }); + }, + onKnobPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Arc", + styleType: STYLE_TYPE.PART_KNOB | STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onKnobPressedStyle, + }); + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, + range(comp, arr, oldProps) { + if (!Array.isArray(arr)) return; + const [min, max] = arr; + if (min === oldProps.range?.[0] && max === oldProps.range?.[1]) return; + if (isNaN(min) || isNaN(max)) return; + comp.setRange([min, max]); + }, + value(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.value) return; + comp.setValue(val); + }, + startAngle(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.startAngle) return; + comp.setStartAngle(val); + }, + endAngle(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.endAngle) return; + comp.setEndAngle(val); + }, + backgroundStartAngle(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.backgroundStartAngle) return; + comp.setBackgroundStartAngle(val); + }, + backgroundEndAngle(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.backgroundEndAngle) return; + comp.setBackgroundEndAngle(val); + }, + rotation(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.rotation) return; + comp.setRotation(val); + }, + mode(comp, val, oldProps) { + if (val !== oldProps.mode && typeof modes[val] !== "undefined") { + comp.setMode(modes[val]); } - }); -} + }, + changeRate(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.changeRate) return; + comp.setChangeRate(val); + }, +}; export class ArcComp extends NativeArc { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -157,14 +145,15 @@ export class ArcComp extends NativeArc { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: ArcProps, oldProps: ArcProps) { - setArcProps(this, newProps, oldProps); + setComponentProps(this, "Arc", newProps, oldProps, arcSetters); } insertBefore(child, beforeChild) {} static tagName = "Arc"; diff --git a/src/render/react/components/Button/comp.ts b/src/render/react/components/Button/comp.ts index 5040543c5..5ee90b033 100644 --- a/src/render/react/components/Button/comp.ts +++ b/src/render/react/components/Button/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnClickEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnClickEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -31,46 +31,34 @@ export type ButtonProps = CommonProps & { }) => void; }; -function setButtonProps(comp, newProps: ButtonProps, oldProps: ButtonProps) { - const setter = { - ...CommonComponentApi({ compName: "Button", comp, newProps, oldProps }), - onPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Button", - styleType: STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onPressedStyle, - }); - }, - onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - onPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); - }, - onLongPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); - }, - onLongPressRepeat(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} +const buttonSetters = { + onPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Button", + styleType: STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onPressedStyle, + }); + }, + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, + onPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); + }, + onLongPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); + }, + onLongPressRepeat(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); + }, +}; export class ButtonComp extends NativeButton { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -79,14 +67,15 @@ export class ButtonComp extends NativeButton { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: ButtonProps, oldProps: ButtonProps) { - setButtonProps(this, newProps, oldProps); + setComponentProps(this, "Button", newProps, oldProps, buttonSetters); } insertBefore(child, beforeChild) {} static tagName = "Button"; diff --git a/src/render/react/components/Calendar/comp.ts b/src/render/react/components/Calendar/comp.ts index 416062322..cd63c3c48 100644 --- a/src/render/react/components/Calendar/comp.ts +++ b/src/render/react/components/Calendar/comp.ts @@ -1,8 +1,7 @@ -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, - setStyle, styleGetterProp, } from "../config"; @@ -16,49 +15,37 @@ export type CalendarProps = CommonProps & { onChange?: (event: OnChangeEvent) => void; }; -function setCalendarProps(comp, newProps: CalendarProps, oldProps: CalendarProps) { - const setter = { - ...CommonComponentApi({ compName: "Calendar", comp, newProps, oldProps }), - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - today(today) { - if (today && today !== oldProps.today) { - const date = new Date(today); - comp.setToday(date.getFullYear(), date.getMonth() + 1, date.getDate()); - } - }, - shownMonth(month) { - if (month && month !== oldProps.shownMonth) { - const date = new Date(month); - comp.setShownMonth(date.getFullYear(), date.getMonth() + 1); - } - }, - highLightDates(dates) { - if (Array.isArray(dates) && dates !== oldProps.highLightDates) { - dates = dates.map((item) => { - const date = new Date(item); - return [date.getFullYear(), date.getMonth() + 1, date.getDate()]; - }); - comp.setHighlightDates(dates, dates.length); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const calendarSetters = { + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, + today(comp, today, oldProps) { + if (today && today !== oldProps.today) { + const date = new Date(today); + comp.setToday(date.getFullYear(), date.getMonth() + 1, date.getDate()); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + shownMonth(comp, month, oldProps) { + if (month && month !== oldProps.shownMonth) { + const date = new Date(month); + comp.setShownMonth(date.getFullYear(), date.getMonth() + 1); } - }); -} + }, + highLightDates(comp, dates, oldProps) { + if (Array.isArray(dates) && dates !== oldProps.highLightDates) { + dates = dates.map((item) => { + const date = new Date(item); + return [date.getFullYear(), date.getMonth() + 1, date.getDate()]; + }); + comp.setHighlightDates(dates, dates.length); + } + }, +}; export class CalendarComp extends NativeCalendar { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -67,14 +54,15 @@ export class CalendarComp extends NativeCalendar { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: CalendarProps, oldProps: CalendarProps) { - setCalendarProps(this, newProps, oldProps); + setComponentProps(this, "Calendar", newProps, oldProps, calendarSetters); } insertBefore(child, beforeChild) {} static tagName = "Calendar"; diff --git a/src/render/react/components/Canvas/comp.ts b/src/render/react/components/Canvas/comp.ts index dc3fc485a..82d149bd4 100644 --- a/src/render/react/components/Canvas/comp.ts +++ b/src/render/react/components/Canvas/comp.ts @@ -1,8 +1,7 @@ -import { CommonProps, OnClickEvent } from "../common"; +import { setComponentProps, CommonProps, OnClickEvent } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, - setStyle, styleGetterProp, } from "../config"; import CanvasContext from "./context"; @@ -16,53 +15,16 @@ export type CanvasProps = CommonProps & { alignTo?: { type: number; pos: [number, number]; parent: any }; }; -function setCanvasProps(comp, newProps: CanvasProps, oldProps: CanvasProps) { - const setter = { - set style(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Canvas", - styleType: 0x0000, - oldStyleSheet: oldProps.style, - }); - }, - set onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - set align({ type, pos = [0, 0] }) { - if ( - !type || - (type === oldProps.align?.type && - pos[0] === oldProps.align?.pos?.[0] && - pos[1] === oldProps.align?.pos?.[1]) - ) - return; - comp.align(type, pos); - }, - set alignTo({ type, pos = [0, 0], parent }) { - if ( - !type || - (type === oldProps.alignTo?.type && - pos[0] === (oldProps.alignTo?.pos?.[0] || 0) && - pos[1] === (oldProps.alignTo?.pos?.[1] || 0) && - parent?.uid === oldProps.alignTo?.parent?.uid) - ) - return; - comp.alignTo(type, pos, parent); - }, - }; - Object.assign(setter, newProps); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} +const canvasSetters = { + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, +}; export class CanvasComp extends NativeButton { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -71,14 +33,15 @@ export class CanvasComp extends NativeButton { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: CanvasProps, oldProps: CanvasProps) { - setCanvasProps(this, newProps, oldProps); + setComponentProps(this, "Canvas", newProps, oldProps, canvasSetters); } insertBefore(child, beforeChild) {} static tagName = "Canvas"; diff --git a/src/render/react/components/Chart/comp.ts b/src/render/react/components/Chart/comp.ts index 5f4edaddc..b8fc04416 100644 --- a/src/render/react/components/Chart/comp.ts +++ b/src/render/react/components/Chart/comp.ts @@ -1,10 +1,8 @@ import { StyleProps } from "../../core/style"; import { colorTransform } from "../../core/style/color"; -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { - EVENTTYPE_MAP, STYLE_TYPE, - handleEvent, setStyle, styleGetterProp, } from "../config"; @@ -46,236 +44,218 @@ export type ChartProps = CommonProps & { bottomAxisRange?: [number, number]; }; -function setChartProps(comp, newProps: ChartProps, oldProps: ChartProps) { - const setter = { - ...CommonComponentApi({ compName: "Chart", comp, newProps, oldProps }), - onPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Chart", - styleType: STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onPressedStyle, - }); - }, - indicatorStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Chart", - styleType: STYLE_TYPE.PART_INDICATOR, - oldStyleSheet: oldProps.pointStyle, - }); - }, - itemStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Chart", - styleType: STYLE_TYPE.PART_ITEMS, - oldStyleSheet: oldProps.pointStyle, - }); - }, - type(type) { - if (chartType[type] !== void 0) { - comp.setType(chartType[type]); - } - }, - divLineCount(arr) { - if ( - arr?.[0] !== oldProps?.divLineCount?.[0] || - arr?.[1] !== oldProps?.divLineCount?.[1] - ) { - comp.setDivLineCount(arr); - } - }, - pointNum(num) { - if (num !== oldProps?.pointNum) { - comp.setPointNum(num); - } - }, - scatterData(data) { - if (data !== oldProps?.scatterData) { - data = data.map((item) => { - const arr = []; - item.data.forEach((item1) => { - arr.push(item1[0]); - arr.push(item1[1]); - }); - return { - color: item.color === void 0 ? -1 : colorTransform(item.color), - data: arr, - }; +const chartSetters = { + onPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Chart", + styleType: STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onPressedStyle, + }); + }, + indicatorStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Chart", + styleType: STYLE_TYPE.PART_INDICATOR, + oldStyleSheet: oldProps.indicatorStyle, + }); + }, + itemStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Chart", + styleType: STYLE_TYPE.PART_ITEMS, + oldStyleSheet: oldProps.itemStyle, + }); + }, + type(comp, type) { + if (chartType[type] !== void 0) { + comp.setType(chartType[type]); + } + }, + divLineCount(comp, arr, oldProps) { + if ( + arr?.[0] !== oldProps?.divLineCount?.[0] || + arr?.[1] !== oldProps?.divLineCount?.[1] + ) { + comp.setDivLineCount(arr); + } + }, + pointNum(comp, num, oldProps) { + if (num !== oldProps?.pointNum) { + comp.setPointNum(num); + } + }, + scatterData(comp, data, oldProps) { + if (data !== oldProps?.scatterData) { + data = data.map((item) => { + const arr = []; + item.data.forEach((item1) => { + arr.push(item1[0]); + arr.push(item1[1]); }); - - comp.setScatterData(data); - } - }, - leftAxisOption(options) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - if (options != oldProps?.leftAxisOption) { - comp.setLeftAxisOption(options); - } - }, - leftAxisData(data) { - if (data !== oldProps?.leftAxisData) { - data = data.map((item) => ({ - ...item, - color: item.color === void 0 ? -1 : colorTransform(item.color), - })); - comp.setLeftAxisData(data); - } - }, - bottomAxisOption(options) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - - if (options != oldProps?.bottomAxisOption) { - comp.setBottomAxisOption(options); - } - }, - bottomAxisData(data) { - if (data !== oldProps?.bottomAxisData) { - data = data.map((item) => ({ - ...item, - color: item.color === void 0 ? -1 : colorTransform(item.color), - })); - comp.setBottomAxisData(data); - } - }, - rightAxisOption(options) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - - if (options != oldProps?.rightAxisOption) { - comp.setRightAxisOption(options); - } - }, - rightAxisData(data) { - if (data !== oldProps?.rightAxisData) { - data = data.map((item) => ({ - ...item, - color: item.color === void 0 ? -1 : colorTransform(item.color), - })); - comp.setRightAxisData(data); - } - }, - topAxisOption(options) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - - if (options != oldProps?.topAxisOption) { - comp.setTopAxisOption(options); - } - }, - topAxisData(data) { - if (data !== oldProps?.topAxisData) { - data = data.map((item) => ({ - ...item, + return { color: item.color === void 0 ? -1 : colorTransform(item.color), - })); - comp.setTopAxisData(data); - } - }, - leftAxisLabels(arr) { - if (arr !== oldProps?.leftAxisLabels) { - comp.setLeftAxisLabels(arr); - } - }, - rightAxisLabels(arr) { - if (arr !== oldProps?.rightAxisLabels) { - comp.setRightAxisLabels(arr); - } - }, - topAxisLabels(arr) { - if (arr !== oldProps?.topAxisLabels) { - comp.setTopAxisLabels(arr); - } - }, - bottomAxisLabels(arr) { - if (arr !== oldProps?.bottomAxisLabels) { - comp.setBottomAxisLabels(arr); - } - }, - leftAxisRange(arr) { - if ( - arr?.[0] !== oldProps?.leftAxisRange?.[0] || - arr?.[1] !== oldProps?.leftAxisRange?.[1] - ) { - comp.setLeftAxisRange(arr); - } - }, - rightAxisRange(arr) { - if ( - arr?.[0] !== oldProps?.rightAxisRange?.[0] || - arr?.[1] !== oldProps?.rightAxisRange?.[1] - ) { - comp.setRightAxisRange(arr); - } - }, - topAxisRange(arr) { - if ( - arr?.[0] !== oldProps?.topAxisRange?.[0] || - arr?.[1] !== oldProps?.topAxisRange?.[1] - ) { - comp.setTopAxisRange(arr); - } - }, - bottomAxisRange(arr) { - if ( - arr?.[0] !== oldProps?.bottomAxisRange?.[0] || - arr?.[1] !== oldProps?.bottomAxisRange?.[1] - ) { - comp.setBottomAxisRange(arr); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); + data: arr, + }; + }); + comp.setScatterData(data); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + leftAxisOption(comp, options, oldProps) { + if ( + options.majorLen == void 0 || + options.minorLen == void 0 || + options.majorNum == void 0 || + options.minorNum == void 0 || + !options.drawSize + ) { + return; } - }); - // This gives issues: invalid call to setPointNum? - // comp.refresh(); -} + if (options != oldProps?.leftAxisOption) { + comp.setLeftAxisOption(options); + } + }, + leftAxisData(comp, data, oldProps) { + if (data !== oldProps?.leftAxisData) { + data = data.map((item) => ({ + ...item, + color: item.color === void 0 ? -1 : colorTransform(item.color), + })); + comp.setLeftAxisData(data); + } + }, + bottomAxisOption(comp, options, oldProps) { + if ( + options.majorLen == void 0 || + options.minorLen == void 0 || + options.majorNum == void 0 || + options.minorNum == void 0 || + !options.drawSize + ) { + return; + } + if (options != oldProps?.bottomAxisOption) { + comp.setBottomAxisOption(options); + } + }, + bottomAxisData(comp, data, oldProps) { + if (data !== oldProps?.bottomAxisData) { + data = data.map((item) => ({ + ...item, + color: item.color === void 0 ? -1 : colorTransform(item.color), + })); + comp.setBottomAxisData(data); + } + }, + rightAxisOption(comp, options, oldProps) { + if ( + options.majorLen == void 0 || + options.minorLen == void 0 || + options.majorNum == void 0 || + options.minorNum == void 0 || + !options.drawSize + ) { + return; + } + if (options != oldProps?.rightAxisOption) { + comp.setRightAxisOption(options); + } + }, + rightAxisData(comp, data, oldProps) { + if (data !== oldProps?.rightAxisData) { + data = data.map((item) => ({ + ...item, + color: item.color === void 0 ? -1 : colorTransform(item.color), + })); + comp.setRightAxisData(data); + } + }, + topAxisOption(comp, options, oldProps) { + if ( + options.majorLen == void 0 || + options.minorLen == void 0 || + options.majorNum == void 0 || + options.minorNum == void 0 || + !options.drawSize + ) { + return; + } + if (options != oldProps?.topAxisOption) { + comp.setTopAxisOption(options); + } + }, + topAxisData(comp, data, oldProps) { + if (data !== oldProps?.topAxisData) { + data = data.map((item) => ({ + ...item, + color: item.color === void 0 ? -1 : colorTransform(item.color), + })); + comp.setTopAxisData(data); + } + }, + leftAxisLabels(comp, arr, oldProps) { + if (arr !== oldProps?.leftAxisLabels) { + comp.setLeftAxisLabels(arr); + } + }, + rightAxisLabels(comp, arr, oldProps) { + if (arr !== oldProps?.rightAxisLabels) { + comp.setRightAxisLabels(arr); + } + }, + topAxisLabels(comp, arr, oldProps) { + if (arr !== oldProps?.topAxisLabels) { + comp.setTopAxisLabels(arr); + } + }, + bottomAxisLabels(comp, arr, oldProps) { + if (arr !== oldProps?.bottomAxisLabels) { + comp.setBottomAxisLabels(arr); + } + }, + leftAxisRange(comp, arr, oldProps) { + if ( + arr?.[0] !== oldProps?.leftAxisRange?.[0] || + arr?.[1] !== oldProps?.leftAxisRange?.[1] + ) { + comp.setLeftAxisRange(arr); + } + }, + rightAxisRange(comp, arr, oldProps) { + if ( + arr?.[0] !== oldProps?.rightAxisRange?.[0] || + arr?.[1] !== oldProps?.rightAxisRange?.[1] + ) { + comp.setRightAxisRange(arr); + } + }, + topAxisRange(comp, arr, oldProps) { + if ( + arr?.[0] !== oldProps?.topAxisRange?.[0] || + arr?.[1] !== oldProps?.topAxisRange?.[1] + ) { + comp.setTopAxisRange(arr); + } + }, + bottomAxisRange(comp, arr, oldProps) { + if ( + arr?.[0] !== oldProps?.bottomAxisRange?.[0] || + arr?.[1] !== oldProps?.bottomAxisRange?.[1] + ) { + comp.setBottomAxisRange(arr); + } + }, +}; export class ChartComp extends NativeChart { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -284,14 +264,15 @@ export class ChartComp extends NativeChart { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: ChartProps, oldProps: ChartProps) { - setChartProps(this, newProps, oldProps); + setComponentProps(this, "Chart", newProps, oldProps, chartSetters); } insertBefore(child, beforeChild) {} static tagName = "Chart"; diff --git a/src/render/react/components/Checkbox/comp.ts b/src/render/react/components/Checkbox/comp.ts index 7a3c5d939..c462dcbb3 100644 --- a/src/render/react/components/Checkbox/comp.ts +++ b/src/render/react/components/Checkbox/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -21,70 +21,58 @@ export type CheckboxProps = CommonProps & { onChange?: (event: OnChangeEvent) => void; }; -function setCheckboxProps(comp, newProps: CheckboxProps, oldProps: CheckboxProps) { - const setter = { - ...CommonComponentApi({ compName: "Checkbox", comp, newProps, oldProps }), - checked(val) { - if (val !== oldProps.checked) { - comp.setChecked(val); - } - }, - disabled(val) { - if (val !== oldProps.disabled) { - comp.setDisabled(val); - } - }, - text(val) { - if (val !== oldProps.text) { - comp.setText(val); - } - }, - checkedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Checkbox", - styleType: STYLE_TYPE.STATE_CHECKED, - oldStyleSheet: oldProps.checkedStyle, - }); - }, - indicatorStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Checkbox", - styleType: STYLE_TYPE.PART_INDICATOR, - oldStyleSheet: oldProps.indicatorStyle, - }); - }, - indicatorCheckedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Checkbox", - styleType: STYLE_TYPE.PART_INDICATOR | STYLE_TYPE.STATE_CHECKED, - oldStyleSheet: oldProps.indicatorCheckedStyle, - }); - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const checkboxSetters = { + checked(comp, val, oldProps) { + if (val !== oldProps.checked) { + comp.setChecked(val); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + disabled(comp, val, oldProps) { + if (val !== oldProps.disabled) { + comp.setDisabled(val); } - }); -} + }, + text(comp, val, oldProps) { + if (val !== oldProps.text) { + comp.setText(val); + } + }, + checkedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Checkbox", + styleType: STYLE_TYPE.STATE_CHECKED, + oldStyleSheet: oldProps.checkedStyle, + }); + }, + indicatorStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Checkbox", + styleType: STYLE_TYPE.PART_INDICATOR, + oldStyleSheet: oldProps.indicatorStyle, + }); + }, + indicatorCheckedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Checkbox", + styleType: STYLE_TYPE.PART_INDICATOR | STYLE_TYPE.STATE_CHECKED, + oldStyleSheet: oldProps.indicatorCheckedStyle, + }); + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, +}; export class CheckboxComp extends NativeView { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -93,14 +81,15 @@ export class CheckboxComp extends NativeView { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: CheckboxProps, oldProps: CheckboxProps) { - setCheckboxProps(this, newProps, oldProps); + setComponentProps(this, "Checkbox", newProps, oldProps, checkboxSetters); } insertBefore(child, beforeChild) { this.insertChildBefore(child, beforeChild); diff --git a/src/render/react/components/Dropdownlist/comp.ts b/src/render/react/components/Dropdownlist/comp.ts index aee1d275c..bc6c44a7e 100644 --- a/src/render/react/components/Dropdownlist/comp.ts +++ b/src/render/react/components/Dropdownlist/comp.ts @@ -1,11 +1,9 @@ -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EDropdownListArrowDirection, EDropdownlistDirection, EVENTTYPE_MAP, - STYLE_TYPE, handleEvent, - setStyle, styleGetterProp, } from "../config"; @@ -23,63 +21,46 @@ export type DropdownListProps = CommonProps & { onChange?: (event: OnChangeEvent) => void; }; -function setListProps(comp, newProps: DropdownListProps, oldProps: DropdownListProps) { - const setter = { - ...CommonComponentApi({ - compName: "Dropdownlist", - comp, - newProps, - oldProps, - }), - items(items) { - if (items !== oldProps.items && Array.isArray(items)) { - comp.setItems(items, items.length); - } - }, - arrow(arrow) { - if (arrow != oldProps.arrow && typeof arrow === "number") { - comp.setArrowDir(arrow); - } - }, - selectIndex(selectIndex) { - if (selectIndex !== oldProps.selectIndex) { - comp.setselectIndex(selectIndex); - } - }, - text(text) { - if (text !== oldProps.text) { - comp.setText(text); - } - }, - direction(direction) { - if (direction !== oldProps.direction) { - comp.setDir(direction); - } - }, - highlightSelect(payload) { - if (payload != oldProps.highlightSelect) { - comp.setHighLightSelect(payload); - } - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const dropdownlistSetters = { + items(comp, items, oldProps) { + if (items !== oldProps.items && Array.isArray(items)) { + comp.setItems(items, items.length); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + arrow(comp, arrow, oldProps) { + if (arrow != oldProps.arrow && typeof arrow === "number") { + comp.setArrowDir(arrow); } - }); -} + }, + selectIndex(comp, selectIndex, oldProps) { + if (selectIndex !== oldProps.selectIndex) { + comp.setselectIndex(selectIndex); + } + }, + text(comp, text, oldProps) { + if (text !== oldProps.text) { + comp.setText(text); + } + }, + direction(comp, direction, oldProps) { + if (direction !== oldProps.direction) { + comp.setDir(direction); + } + }, + highlightSelect(comp, payload, oldProps) { + if (payload != oldProps.highlightSelect) { + comp.setHighLightSelect(payload); + } + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, +}; export class DropdownlistComp extends NativeDropdownlist { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -88,14 +69,15 @@ export class DropdownlistComp extends NativeDropdownlist { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: DropdownListProps, oldProps: DropdownListProps) { - setListProps(this, newProps, oldProps); + setComponentProps(this, "Dropdownlist", newProps, oldProps, dropdownlistSetters); } insertBefore(child, beforeChild) {} static tagName = "Dropdownlist"; diff --git a/src/render/react/components/GIF/comp.ts b/src/render/react/components/GIF/comp.ts index 5851b5328..97d2c190d 100644 --- a/src/render/react/components/GIF/comp.ts +++ b/src/render/react/components/GIF/comp.ts @@ -1,12 +1,12 @@ import { BUILT_IN_SYMBOL } from "../../core/style/symbol"; import { isValidUrl, fetchBinary } from "../../utils/helpers"; -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, - setStyle, styleGetterProp, } from "../config"; +import path from 'tjs:path'; const bridge = globalThis[Symbol.for('lvgljs')]; const NativeGIF = bridge.NativeRender.NativeComponents.GIF; @@ -15,52 +15,40 @@ export type GIFProps = CommonProps & { src: string; } -function setGIFProps(comp, newProps: GIFProps, oldProps: GIFProps) { - const setter = { - ...CommonComponentApi({ compName: "GIF", comp, newProps, oldProps }), - onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - src(url) { - if (url && url !== oldProps.src) { - if (BUILT_IN_SYMBOL[url]) { - comp.setSymbol(BUILT_IN_SYMBOL[url]); - return; - } - if (!isValidUrl(url)) { - if (!path.isAbsolute(url)) { - url = path.resolve(__dirname, url); - } - fs.readFile(url, { encoding: "binary" }) - .then((data) => { - comp.setGIFBinary(data.buffer); - }) - .catch((e) => { - console.log("setGIF error", e); - }); - } else { - fetchBinary(url) - .then((buffer) => comp.setGIFBinary(buffer)) - .catch(console.warn); +const gifSetters = { + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, + src(comp, url, oldProps) { + if (url && url !== oldProps.src) { + if (BUILT_IN_SYMBOL[url]) { + comp.setSymbol(BUILT_IN_SYMBOL[url]); + return; + } + if (!isValidUrl(url)) { + if (!path.isAbsolute(url)) { + url = path.resolve(__dirname, url); } + tjs.readFile(url) + .then((data) => { + comp.setGIFBinary(data.buffer); + }) + .catch((e) => { + console.log("setGIF error", e); + }); + } else { + fetchBinary(url) + .then((buffer) => comp.setGIFBinary(buffer)) + .catch(console.warn); } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} + }, +}; export class GIFComp extends NativeGIF { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -69,14 +57,15 @@ export class GIFComp extends NativeGIF { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: GIFProps, oldProps: GIFProps) { - setGIFProps(this, newProps, oldProps); + setComponentProps(this, "GIF", newProps, oldProps, gifSetters); } insertBefore(child, beforeChild) {} static tagName = "GIF"; diff --git a/src/render/react/components/Image/comp.ts b/src/render/react/components/Image/comp.ts index 9ddd23e83..c1f45596b 100644 --- a/src/render/react/components/Image/comp.ts +++ b/src/render/react/components/Image/comp.ts @@ -1,10 +1,9 @@ import { BUILT_IN_SYMBOL } from "../../core/style/symbol"; import { isValidUrl, fetchBinary } from "../../utils/helpers"; -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, - setStyle, styleGetterProp, } from "../config"; import path from 'tjs:path'; @@ -17,52 +16,40 @@ export type ImageProps = CommonProps & { src: string; }; -function setImageProps(comp, newProps: ImageProps, oldProps: ImageProps) { - const setter = { - ...CommonComponentApi({ compName: "Image", comp, newProps, oldProps }), - onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - src(url) { - if (url && url !== oldProps.src) { - if (BUILT_IN_SYMBOL[url]) { - comp.setSymbol(BUILT_IN_SYMBOL[url]); - return; - } - if (!isValidUrl(url)) { - if (!path.isAbsolute(url)) { - url = path.resolve(url); - } - tjs.readFile(url) - .then((data) => { - comp.setImageBinary(data.buffer); - }) - .catch((e) => { - console.log("setImage error", e); - }); - } else { - fetchBinary(url) - .then((buffer) => comp.setImageBinary(buffer)) - .catch(console.warn); +const imageSetters = { + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, + src(comp, url, oldProps) { + if (url && url !== oldProps.src) { + if (BUILT_IN_SYMBOL[url]) { + comp.setSymbol(BUILT_IN_SYMBOL[url]); + return; + } + if (!isValidUrl(url)) { + if (!path.isAbsolute(url)) { + url = path.resolve(url); } + tjs.readFile(url) + .then((data) => { + comp.setImageBinary(data.buffer); + }) + .catch((e) => { + console.log("setImage error", e); + }); + } else { + fetchBinary(url) + .then((buffer) => comp.setImageBinary(buffer)) + .catch(console.warn); } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; } - }); -} + }, +}; export class ImageComp extends NativeImage { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -71,14 +58,15 @@ export class ImageComp extends NativeImage { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: ImageProps, oldProps: ImageProps) { - setImageProps(this, newProps, oldProps); + setComponentProps(this, "Image", newProps, oldProps, imageSetters); } insertBefore(child, beforeChild) {} static tagName = "Image"; diff --git a/src/render/react/components/Input/comp.ts b/src/render/react/components/Input/comp.ts index 86df585a6..67fb6f0df 100644 --- a/src/render/react/components/Input/comp.ts +++ b/src/render/react/components/Input/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, @@ -33,71 +33,59 @@ export type InputProps = CommonProps & { autoKeyBoard: boolean; }; -function setInputProps(comp, newProps: InputProps, oldProps: InputProps) { - const setter = { - ...CommonComponentApi({ compName: "Input", comp, newProps, oldProps }), - placeholder(str) { - if (str !== oldProps.placeholder) { - comp.setPlaceHolder(str); - } - }, - mode(mode) { - if (mode == oldProps.mode) return; - if (mode === "password") { - comp.setPasswordMode(true); - } else if (oldProps.mode === "password") { - comp.setPasswordMode(false); - } - }, - maxlength(len) { - if (len === oldProps.maxlength) return; - comp.setMaxLength(len); - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - onFocus(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_FOCUSED); - }, - onBlur(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_DEFOCUSED); - }, - onFocusStyle(styleSheet) { - setStyle({ - comp, - compName: "Input", - styleType: 0x0002, - oldStyleSheet: oldProps.onFocusStyle, - styleSheet, - }); - }, - value(str) { - if (str !== oldProps.value) { - comp.setText(str); - } - }, - autoKeyBoard(payload) { - if (payload !== oldProps?.autoKeyBoard) { - comp.setAutoKeyboard(payload); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const inputSetters = { + placeholder(comp, str, oldProps) { + if (str !== oldProps.placeholder) { + comp.setPlaceHolder(str); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + mode(comp, mode, oldProps) { + if (mode == oldProps.mode) return; + if (mode === "password") { + comp.setPasswordMode(true); + } else if (oldProps.mode === "password") { + comp.setPasswordMode(false); } - }); -} + }, + maxlength(comp, len, oldProps) { + if (len === oldProps.maxlength) return; + comp.setMaxLength(len); + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, + onFocus(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_FOCUSED); + }, + onBlur(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_DEFOCUSED); + }, + onFocusStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + compName: "Input", + styleType: 0x0002, + oldStyleSheet: oldProps.onFocusStyle, + styleSheet, + }); + }, + value(comp, str, oldProps) { + if (str !== oldProps.value) { + comp.setText(str); + } + }, + autoKeyBoard(comp, payload, oldProps) { + if (payload !== oldProps?.autoKeyBoard) { + comp.setAutoKeyboard(payload); + } + }, +}; /** A one line mode of Textarea */ export class InputComp extends NativeView { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -108,14 +96,15 @@ export class InputComp extends NativeView { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: InputProps, oldProps: InputProps) { - setInputProps(this, newProps, oldProps); + setComponentProps(this, "Input", newProps, oldProps, inputSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Keyboard/comp.ts b/src/render/react/components/Keyboard/comp.ts index c6b9f1649..bf21ede0f 100644 --- a/src/render/react/components/Keyboard/comp.ts +++ b/src/render/react/components/Keyboard/comp.ts @@ -1,8 +1,7 @@ -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, - setStyle, styleGetterProp, } from "../config"; import { InputComp } from "../Input/comp"; @@ -30,41 +29,29 @@ export type KeyboardProps = CommonProps & { onOk?: () => void; }; -function setKeyboardProps(comp, newProps: KeyboardProps, oldProps: KeyboardProps) { - const setter = { - ...CommonComponentApi({ compName: "Keyboard", comp, newProps, oldProps }), - mode(mode) { - if (mode !== oldProps.mode && typeof modes[mode] !== "undefined") { - comp.setMode(modes[mode]); - } - }, - textarea(textarea) { - if (textarea?.uid !== oldProps.textarea?.uid) { - comp.setTextarea(textarea); - } - }, - onClose(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CANCEL); - }, - onOk(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_READY); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const keyboardSetters = { + mode(comp, mode, oldProps) { + if (mode !== oldProps.mode && typeof modes[mode] !== "undefined") { + comp.setMode(modes[mode]); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + textarea(comp, textarea, oldProps) { + if (textarea?.uid !== oldProps.textarea?.uid) { + comp.setTextarea(textarea); } - }); -} + }, + onClose(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CANCEL); + }, + onOk(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_READY); + }, +}; export class KeyboardComp extends NativeView { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -73,14 +60,15 @@ export class KeyboardComp extends NativeView { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: KeyboardProps, oldProps: KeyboardProps) { - setKeyboardProps(this, newProps, oldProps); + setComponentProps(this, "Keyboard", newProps, oldProps, keyboardSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Line/comp.ts b/src/render/react/components/Line/comp.ts index d0c75510e..4ad8d0a9d 100644 --- a/src/render/react/components/Line/comp.ts +++ b/src/render/react/components/Line/comp.ts @@ -1,8 +1,5 @@ -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { - EVENTTYPE_MAP, - handleEvent, - setStyle, styleGetterProp, } from "../config"; @@ -13,33 +10,21 @@ export type LineProps = CommonProps & { points: [number, number][]; }; -function setLineProps(comp, newProps, oldProps) { - const setter = { - ...CommonComponentApi({ compName: "Keyboard", comp, newProps, oldProps }), - points(points) { - if ( - (Array.isArray(points) && points !== oldProps?.points) || - points?.length !== oldProps?.points?.length - ) { - comp.setPoints(points, points.length); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const lineSetters = { + points(comp, points, oldProps) { + if ( + (Array.isArray(points) && points !== oldProps?.points) || + points?.length !== oldProps?.points?.length + ) { + comp.setPoints(points, points.length); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} + }, +}; export class LineComp extends NativeLine { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -48,14 +33,15 @@ export class LineComp extends NativeLine { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: LineProps, oldProps: LineProps) { - setLineProps(this, newProps, oldProps); + setComponentProps(this, "Line", newProps, oldProps, lineSetters); } insertBefore(child, beforeChild) {} static tagName = "Line"; diff --git a/src/render/react/components/Mask/comp.ts b/src/render/react/components/Mask/comp.ts index e0bad5474..bed3eabe0 100644 --- a/src/render/react/components/Mask/comp.ts +++ b/src/render/react/components/Mask/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnClickEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnClickEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -31,46 +31,34 @@ export type MaskProps = CommonProps & { }) => void; }; -function setMaskProps(comp, newProps: MaskProps, oldProps: MaskProps) { - const setter = { - ...CommonComponentApi({ compName: "Mask", comp, newProps, oldProps }), - onPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Mask", - styleType: STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onPressedStyle, - }); - }, - onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - onPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); - }, - onLongPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); - }, - onLongPressRepeat(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} +const maskSetters = { + onPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Mask", + styleType: STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onPressedStyle, + }); + }, + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, + onPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); + }, + onLongPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); + }, + onLongPressRepeat(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); + }, +}; export class MaskComp extends NativeMask { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -79,14 +67,15 @@ export class MaskComp extends NativeMask { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: MaskProps, oldProps: MaskProps) { - setMaskProps(this, newProps, oldProps); + setComponentProps(this, "Mask", newProps, oldProps, maskSetters); } insertBefore(child, beforeChild) {} static tagName = "Mask"; diff --git a/src/render/react/components/ProgressBar/comp.ts b/src/render/react/components/ProgressBar/comp.ts index 6976eaecb..360225ebf 100644 --- a/src/render/react/components/ProgressBar/comp.ts +++ b/src/render/react/components/ProgressBar/comp.ts @@ -1,6 +1,6 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps } from "../common/index"; -import { STYLE_TYPE, handleEvent, setStyle, styleGetterProp } from "../config"; +import { setComponentProps, CommonProps } from "../common/index"; +import { STYLE_TYPE, setStyle, styleGetterProp } from "../config"; const bridge = globalThis[Symbol.for('lvgljs')]; const NativeProgressBar = bridge.NativeRender.NativeComponents.ProgressBar; @@ -13,61 +13,27 @@ export type ProgressBarProps = CommonProps & { indicatorStyle?: StyleProps; }; -function setProgressBarProps(comp, newProps: ProgressBarProps, oldProps: ProgressBarProps) { - const setter = { - ...CommonComponentApi({ - compName: "ProgressBar", +const progressBarSetters = { + indicatorStyle(comp, styleSheet, oldProps) { + setStyle({ comp, - newProps, - oldProps, - }), - style(styleSheet) { - if (newProps.animationTime) { - styleSheet["style-transition-time"] = newProps.animationTime; - } - setStyle({ - comp, - styleSheet, - compName: "ProgressBar", - styleType: STYLE_TYPE.PART_MAIN, - oldStyleSheet: oldProps.style, - }); - }, - indicatorStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "ProgressBar", - styleType: STYLE_TYPE.PART_INDICATOR, - oldStyleSheet: oldProps.style, - }); - }, - value(value) { - if (value !== oldProps.value) { - comp.setValue(value, !!newProps.useAnimation); - } - }, - range(arr) { - if (arr?.[0] !== oldProps?.arr?.[0] || arr?.[1] !== oldProps?.arr?.[1]) { - comp.setRange(arr[0], arr[1]); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + styleSheet, + compName: "ProgressBar", + styleType: STYLE_TYPE.PART_INDICATOR, + oldStyleSheet: oldProps.indicatorStyle, + }); + }, + range(comp, arr, oldProps) { + if (arr?.[0] !== oldProps.range?.[0] || arr?.[1] !== oldProps.range?.[1]) { + comp.setRange(arr[0], arr[1]); } - }); -} + }, +}; export class ProgressBarComp extends NativeProgressBar { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -76,14 +42,35 @@ export class ProgressBarComp extends NativeProgressBar { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: ProgressBarProps, oldProps: ProgressBarProps) { - setProgressBarProps(this, newProps, oldProps); + const customSetters = { + ...progressBarSetters, + style(comp, styleSheet, compName, oldProps) { + if (newProps.animationTime) { + styleSheet["style-transition-time"] = newProps.animationTime; + } + setStyle({ + comp, + styleSheet, + compName: "ProgressBar", + styleType: STYLE_TYPE.PART_MAIN, + oldStyleSheet: oldProps.style, + }); + }, + value(comp, value, oldProps) { + if (value !== oldProps.value) { + comp.setValue(value, !!newProps.useAnimation); + } + }, + }; + setComponentProps(this, "ProgressBar", newProps, oldProps, customSetters); } insertBefore(child, beforeChild) {} static tagName = "ProgressBar"; diff --git a/src/render/react/components/Roller/comp.ts b/src/render/react/components/Roller/comp.ts index febf15895..1134bc5fc 100644 --- a/src/render/react/components/Roller/comp.ts +++ b/src/render/react/components/Roller/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -21,52 +21,40 @@ export type RollerProps = CommonProps & { onChange?: (event: OnChangeEvent) => void; }; -function setRollerProps(comp, newProps: RollerProps, oldProps: RollerProps) { - const setter = { - ...CommonComponentApi({ compName: "Roller", comp, newProps, oldProps }), - selectedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Roller", - styleType: STYLE_TYPE.PART_SELECTED, - oldStyleSheet: oldProps.selectedStyle, - }); - }, - options(options) { - if (options !== oldProps.options && Array.isArray(options)) { - comp.setOptions(options, options.length, !!newProps.infinity); - } - }, - selectIndex(selectIndex) { - if (selectIndex !== oldProps.selectIndex) { - comp.setSelectIndex(selectIndex); - } - }, - visibleRowCount(count) { - if (count !== oldProps.visibleRowCount) { - comp.setVisibleRowCount(count); - } - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const rollerSetters = { + selectedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Roller", + styleType: STYLE_TYPE.PART_SELECTED, + oldStyleSheet: oldProps.selectedStyle, + }); + }, + options(comp, options, oldProps, newProps) { + if (options !== oldProps.options && Array.isArray(options)) { + comp.setOptions(options, options.length, !!newProps.infinity); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + selectIndex(comp, selectIndex, oldProps) { + if (selectIndex !== oldProps.selectIndex) { + comp.setSelectIndex(selectIndex); } - }); -} + }, + visibleRowCount(comp, count, oldProps) { + if (count !== oldProps.visibleRowCount) { + comp.setVisibleRowCount(count); + } + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, +}; export class RollerComp extends NativeRoller { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -75,14 +63,21 @@ export class RollerComp extends NativeRoller { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: RollerProps, oldProps: RollerProps) { - setRollerProps(this, newProps, oldProps); + const customSetters = { + ...rollerSetters, + options(comp, options, oldProps) { + rollerSetters.options(comp, options, oldProps, newProps); + }, + }; + setComponentProps(this, "Roller", newProps, oldProps, customSetters); } insertBefore(child, beforeChild) {} static tagName = "Roller"; diff --git a/src/render/react/components/Slider/comp.ts b/src/render/react/components/Slider/comp.ts index bda7b395b..60db7d213 100644 --- a/src/render/react/components/Slider/comp.ts +++ b/src/render/react/components/Slider/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -22,85 +22,73 @@ export type SliderProps = CommonProps & { value: number; }; -function setSliderProps(comp, newProps: SliderProps, oldProps: SliderProps) { - const setter = { - ...CommonComponentApi({ compName: "Slider", comp, newProps, oldProps }), - indicatorStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Slider", - styleType: STYLE_TYPE.PART_INDICATOR, - oldStyleSheet: oldProps.indicatorStyle, - }); - }, - onIndicatorPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Slider", - styleType: STYLE_TYPE.PART_INDICATOR | STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onIndicatorPressedStyle, - }); - }, - onPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Slider", - styleType: STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onPressedStyle, - }); - }, - knobStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Slider", - styleType: STYLE_TYPE.PART_KNOB, - oldStyleSheet: oldProps.knobStyle, - }); - }, - onKnobPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Slider", - styleType: STYLE_TYPE.PART_KNOB | STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onKnobPressedStyle, - }); - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - range(arr) { - if (!Array.isArray(arr)) return; - const [min, max] = arr; - if (min === oldProps.range?.[0] && max === oldProps.range?.[1]) return; - if (isNaN(min) || isNaN(max)) return; - comp.setRange([min, max]); - }, - value(val) { - if (isNaN(val)) return; - if (val == oldProps.value) return; - comp.setValue(val); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} +const sliderSetters = { + indicatorStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Slider", + styleType: STYLE_TYPE.PART_INDICATOR, + oldStyleSheet: oldProps.indicatorStyle, + }); + }, + onIndicatorPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Slider", + styleType: STYLE_TYPE.PART_INDICATOR | STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onIndicatorPressedStyle, + }); + }, + onPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Slider", + styleType: STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onPressedStyle, + }); + }, + knobStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Slider", + styleType: STYLE_TYPE.PART_KNOB, + oldStyleSheet: oldProps.knobStyle, + }); + }, + onKnobPressedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Slider", + styleType: STYLE_TYPE.PART_KNOB | STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onKnobPressedStyle, + }); + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, + range(comp, arr, oldProps) { + if (!Array.isArray(arr)) return; + const [min, max] = arr; + if (min === oldProps.range?.[0] && max === oldProps.range?.[1]) return; + if (isNaN(min) || isNaN(max)) return; + comp.setRange([min, max]); + }, + value(comp, val, oldProps) { + if (isNaN(val)) return; + if (val == oldProps.value) return; + comp.setValue(val); + }, +}; export class SliderComp extends NativeSlider { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -109,14 +97,15 @@ export class SliderComp extends NativeSlider { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: SliderProps, oldProps: SliderProps) { - setSliderProps(this, newProps, oldProps); + setComponentProps(this, "Slider", newProps, oldProps, sliderSetters); } insertBefore(child, beforeChild) {} static tagName = "Slider"; diff --git a/src/render/react/components/Switch/comp.ts b/src/render/react/components/Switch/comp.ts index cd004b418..2331aa8de 100644 --- a/src/render/react/components/Switch/comp.ts +++ b/src/render/react/components/Switch/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -18,47 +18,34 @@ export type SwitchProps = CommonProps & { disabled?: boolean; }; -function setSwitchProps(comp, newProps: SwitchProps, oldProps: SwitchProps) { - const setter = { - ...CommonComponentApi({ compName: "Switch", comp, newProps, oldProps }), - checkedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Switch", - styleType: STYLE_TYPE.STATE_CHECKED, - oldStyleSheet: oldProps.checkedStyle, - }); - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - checked(val) { - if (isNaN(val)) return; - if (val == oldProps.value) return; - comp.setChecked(val); - }, - disabled(val) { - if (val !== oldProps.disabled) { - comp.setDisabled(val); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; +const switchSetters = { + checkedStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Switch", + styleType: STYLE_TYPE.STATE_CHECKED, + oldStyleSheet: oldProps.checkedStyle, + }); + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, + checked(comp, val, oldProps) { + if (val === oldProps.checked) return; + comp.setChecked(val); + }, + disabled(comp, val, oldProps) { + if (val !== oldProps.disabled) { + comp.setDisabled(val); } - }); -} + }, +}; export class SwitchComp extends NativeComp { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -67,14 +54,15 @@ export class SwitchComp extends NativeComp { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps, oldProps) { - setSwitchProps(this, newProps, oldProps); + setComponentProps(this, "Switch", newProps, oldProps, switchSetters); } insertBefore(child, beforeChild) { this.insertChildBefore(child, beforeChild); diff --git a/src/render/react/components/Tabs/comp.ts b/src/render/react/components/Tabs/comp.ts index 28a3e657f..6803bcab0 100644 --- a/src/render/react/components/Tabs/comp.ts +++ b/src/render/react/components/Tabs/comp.ts @@ -1,9 +1,7 @@ -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, - STYLE_TYPE, handleEvent, - setStyle, styleGetterProp, } from "../config"; @@ -16,35 +14,20 @@ export type TabsProps = CommonProps & { tabSize?: number; }; -function setTabsProps(comp, newProps: TabsProps, oldProps: TabsProps) { - const setter = { - ...CommonComponentApi({ compName: "Tabs", comp, newProps, oldProps }), - onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - onPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); - }, - onLongPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); - }, - onLongPressRepeat(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} +const tabsSetters = { + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, + onPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); + }, + onLongPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); + }, + onLongPressRepeat(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); + }, +}; const tabPositionObj = { left: 1 << 0, @@ -54,6 +37,9 @@ const tabPositionObj = { }; export class TabsComp extends NativeTabs { + uid: string; + style: any; + constructor({ uid, tabPosition, tabSize = 0 }) { tabPosition = tabPositionObj[tabPosition] || tabPositionObj.top; super({ uid, tabPosition, tabSize }); @@ -63,8 +49,9 @@ export class TabsComp extends NativeTabs { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); @@ -72,7 +59,7 @@ export class TabsComp extends NativeTabs { } setProps(newProps: TabsProps, oldProps: TabsProps) { this.tabs = newProps.tabs; - setTabsProps(this, newProps, oldProps); + setComponentProps(this, "Tabs", newProps, oldProps, tabsSetters); } insertBefore(child, beforeChild) {} static tagName = "Tabs"; diff --git a/src/render/react/components/Text/comp.ts b/src/render/react/components/Text/comp.ts index f47114a00..d320e5cae 100644 --- a/src/render/react/components/Text/comp.ts +++ b/src/render/react/components/Text/comp.ts @@ -1,8 +1,5 @@ -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { - EVENTTYPE_MAP, - STYLE_TYPE, - handleEvent, setStyle, styleGetterProp, } from "../config"; @@ -14,38 +11,26 @@ export type TextProps = CommonProps & { children: string | number | (string | number)[]; }; -function setTextProps(comp, newProps: TextProps, oldProps: TextProps) { - const setter = { - ...CommonComponentApi({ compName: "Text", comp, newProps, oldProps }), - children(str) { - const type = typeof str; - if ((type == "string" || type == "number") && oldProps.children !== str) { - comp.setText(String(str)); - } else if (Array.isArray(str)) { - const isStringArr = str.every( - (item) => typeof item === "string" || typeof item === "number", - ); - if (isStringArr) { - comp.setText(str.join("")); - } +const textSetters = { + children(comp, str, oldProps) { + const type = typeof str; + if ((type == "string" || type == "number") && oldProps.children !== str) { + comp.setText(String(str)); + } else if (Array.isArray(str)) { + const isStringArr = str.every( + (item) => typeof item === "string" || typeof item === "number", + ); + if (isStringArr) { + comp.setText(str.join("")); } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; } - }); -} + }, +}; export class TextComp extends NativeText { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -54,14 +39,15 @@ export class TextComp extends NativeText { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: TextProps, oldProps: TextProps) { - setTextProps(this, newProps, oldProps); + setComponentProps(this, "Text", newProps, oldProps, textSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Textarea/comp.ts b/src/render/react/components/Textarea/comp.ts index 2b5f0bfec..305e65bfc 100644 --- a/src/render/react/components/Textarea/comp.ts +++ b/src/render/react/components/Textarea/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { CommonComponentApi, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, @@ -26,62 +26,50 @@ export type TextAreaProps = CommonProps & { autoKeyBoard: boolean; }; -function setTextareaProps(comp, newProps: TextAreaProps, oldProps: TextAreaProps) { - const setter = { - ...CommonComponentApi({ compName: "Textarea", comp, newProps, oldProps }), - placeholder(str) { - if (str !== oldProps.placeholder) { - comp.setPlaceHolder(str); - } - }, - mode(mode) { - if (mode === "password") { - comp.setPasswordMode(true); - } else if (oldProps.mode === "password") { - comp.setPasswordMode(false); - } - }, - onFocusStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName: "Textarea", - styleType: 0x0002, - oldStyleSheet: oldProps.onFocusStyle, - }); - }, - onChange(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); - }, - onFocus(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_FOCUSED); - }, - value(str) { - if (str !== oldProps.value) { - comp.setText(str); - } - }, - autoKeyBoard(payload) { - if (payload !== oldProps?.autoKeyBoard) { - comp.setAutoKeyboard(payload); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const textareaSetters = { + placeholder(comp, str, oldProps) { + if (str !== oldProps.placeholder) { + comp.setPlaceHolder(str); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + }, + mode(comp, mode, oldProps) { + if (mode === "password") { + comp.setPasswordMode(true); + } else if (oldProps.mode === "password") { + comp.setPasswordMode(false); } - }); -} + }, + onFocusStyle(comp, styleSheet, oldProps) { + setStyle({ + comp, + styleSheet, + compName: "Textarea", + styleType: 0x0002, + oldStyleSheet: oldProps.onFocusStyle, + }); + }, + onChange(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); + }, + onFocus(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_FOCUSED); + }, + value(comp, str, oldProps) { + if (str !== oldProps.value) { + comp.setText(str); + } + }, + autoKeyBoard(comp, payload, oldProps) { + if (payload !== oldProps?.autoKeyBoard) { + comp.setAutoKeyboard(payload); + } + }, +}; export class TextareaComp extends NativeView { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -92,14 +80,15 @@ export class TextareaComp extends NativeView { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: TextAreaProps, oldProps: TextAreaProps) { - setTextareaProps(this, newProps, oldProps); + setComponentProps(this, "Textarea", newProps, oldProps, textareaSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/View/comp.ts b/src/render/react/components/View/comp.ts index 937bbfe58..4330d6039 100644 --- a/src/render/react/components/View/comp.ts +++ b/src/render/react/components/View/comp.ts @@ -1,8 +1,5 @@ -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { - EVENTTYPE_MAP, - STYLE_TYPE, - handleEvent, setStyle, styleGetterProp, } from "../config"; @@ -12,25 +9,12 @@ const NativeView = bridge.NativeRender.NativeComponents.View; export type ViewProps = CommonProps -function setViewProps(comp, newProps: ViewProps, oldProps: ViewProps) { - const setter = { - ...CommonComponentApi({ compName: "View", comp, newProps, oldProps }), - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); - } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} +const viewSetters = {}; export class ViewComp extends NativeView { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -39,14 +23,15 @@ export class ViewComp extends NativeView { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: ViewProps, oldProps: ViewProps) { - setViewProps(this, newProps, oldProps); + setComponentProps(this, "View", newProps, oldProps, viewSetters); } insertBefore(child, beforeChild) { super.insertChildBefore(child, beforeChild); diff --git a/src/render/react/components/Window/comp.ts b/src/render/react/components/Window/comp.ts index a6af15b95..dec25e85e 100644 --- a/src/render/react/components/Window/comp.ts +++ b/src/render/react/components/Window/comp.ts @@ -1,8 +1,5 @@ -import { CommonComponentApi, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps } from "../common/index"; import { - EVENTTYPE_MAP, - handleEvent, - setStyle, styleGetterProp, } from "../config"; @@ -13,30 +10,18 @@ export type WindowProps = CommonProps & { title: string; }; -function setWindowProps(comp, newProps: WindowProps, oldProps: WindowProps) { - const setter = { - ...CommonComponentApi({ compName: "Window", comp, newProps, oldProps }), - title(title) { - if (oldProps.title != title) { - comp.setTitle(title); - } - }, - }; - Object.keys(setter).forEach((key) => { - if (newProps.hasOwnProperty(key)) { - setter[key](newProps[key]); +const windowSetters = { + title(comp, title, oldProps) { + if (oldProps.title != title) { + comp.setTitle(title); } - }); - comp.dataset = {}; - Object.keys(newProps).forEach((prop) => { - const index = prop.indexOf("data-"); - if (index === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; - } - }); -} + }, +}; export class Window extends NativeComp { + uid: string; + style: any; + constructor({ uid }) { super({ uid }); this.uid = uid; @@ -45,14 +30,15 @@ export class Window extends NativeComp { const that = this; this.style = new Proxy(this, { get(obj, prop) { - if (styleGetterProp.includes(prop)) { - return style[prop].call(that); + const propStr = String(prop); + if (styleGetterProp.includes(propStr)) { + return style[propStr].call(that); } }, }); } setProps(newProps: WindowProps, oldProps: WindowProps) { - setWindowProps(this, newProps, oldProps); + setComponentProps(this, "Window", newProps, oldProps, windowSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) { diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index 6ce8529d2..5994d1a0a 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -80,114 +80,141 @@ export type OnClickEvent = { stopPropogation: () => void, } -export const CommonComponentApi = function ({ - compName, - comp, - newProps, - oldProps, -}: {compName: any, comp: any, newProps: CommonProps, oldProps: CommonProps}) { - return { - style(styleSheet) { - setStyle({ - comp, - styleSheet, - compName, - styleType: STYLE_TYPE.PART_MAIN, - oldStyleSheet: oldProps.style, - }); - }, - align({ type, pos = [0, 0] }) { - if ( - !type || - (type === oldProps.align?.type && - newProps.align?.pos?.[0] === oldProps.align?.pos?.[0] && - newProps.align?.pos?.[1] === oldProps.align?.pos?.[1]) - ) - return; - comp.align(type, pos); - }, - alignTo({ type, pos = [0, 0], parent }) { - if ( - !type || - (type === oldProps.alignTo?.type && - newProps.alignTo?.pos?.[0] === oldProps.alignTo?.pos?.[0] && - newProps.alignTo?.pos?.[1] === oldProps.alignTo?.pos?.[1] && - parent?.uid === oldProps.alignTo?.parent?.uid) - ) - return; - comp.alignTo(type, pos, parent); - }, - scrollbarStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName, - styleType: STYLE_TYPE.PART_SCROLLBAR, - oldStyleSheet: oldProps.scrollbarStyle, - }); - }, - onScrollbarPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName, - styleType: STYLE_TYPE.PART_SCROLLBAR | STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onScrollbarPressedStyle, - }); - }, - onScrollbarScrollingStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName, - styleType: STYLE_TYPE.PART_SCROLLBAR | STYLE_TYPE.STATE_SCROLLED, - oldStyleSheet: oldProps.scrollbarScrollingStyle, - }); - }, - onPressedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName, - styleType: STYLE_TYPE.STATE_PRESSED, - oldStyleSheet: oldProps.onPressedStyle, - }); - }, - onClick(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); - }, - onPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); - }, - onLongPressed(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); - }, - onLongPressRepeat(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); - }, - onPressLost(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESS_LOST); - }, - onReleased(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_RELEASED); - }, - onCancel(fn) { - handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CANCEL); - }, - onFocusedStyle(styleSheet) { - setStyle({ - comp, - styleSheet, - compName, - styleType: STYLE_TYPE.STATE_FOCUSED, - oldStyleSheet: oldProps.onFocusedStyle, - }); - }, - addToFocusGroup(v) { - if (v) comp.addToFocusGroup?.(); - }, - autoFocus() { - // handled in commitMount - }, - }; +export const commonSetters = { + style(comp, styleSheet, compName, oldProps) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.PART_MAIN, + oldStyleSheet: oldProps.style, + }); + }, + align(comp, { type, pos = [0, 0] }, newProps, oldProps) { + if ( + !type || + (type === oldProps.align?.type && + newProps.align?.pos?.[0] === oldProps.align?.pos?.[0] && + newProps.align?.pos?.[1] === oldProps.align?.pos?.[1]) + ) + return; + comp.align(type, pos); + }, + alignTo(comp, { type, pos = [0, 0], parent }, newProps, oldProps) { + if ( + !type || + (type === oldProps.alignTo?.type && + newProps.alignTo?.pos?.[0] === oldProps.alignTo?.pos?.[0] && + newProps.alignTo?.pos?.[1] === oldProps.alignTo?.pos?.[1] && + parent?.uid === oldProps.alignTo?.parent?.uid) + ) + return; + comp.alignTo(type, pos, parent); + }, + scrollbarStyle(comp, styleSheet, compName, oldProps) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.PART_SCROLLBAR, + oldStyleSheet: oldProps.scrollbarStyle, + }); + }, + onScrollbarPressedStyle(comp, styleSheet, compName, oldProps) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.PART_SCROLLBAR | STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onScrollbarPressedStyle, + }); + }, + onScrollbarScrollingStyle(comp, styleSheet, compName, oldProps) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.PART_SCROLLBAR | STYLE_TYPE.STATE_SCROLLED, + oldStyleSheet: oldProps.scrollbarScrollingStyle, + }); + }, + onPressedStyle(comp, styleSheet, compName, oldProps) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.STATE_PRESSED, + oldStyleSheet: oldProps.onPressedStyle, + }); + }, + onClick(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CLICKED); + }, + onPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESSED); + }, + onLongPressed(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED); + }, + onLongPressRepeat(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_LONG_PRESSED_REPEAT); + }, + onPressLost(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_PRESS_LOST); + }, + onReleased(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_RELEASED); + }, + onCancel(comp, fn) { + handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_CANCEL); + }, + onFocusedStyle(comp, styleSheet, compName, oldProps) { + setStyle({ + comp, + styleSheet, + compName, + styleType: STYLE_TYPE.STATE_FOCUSED, + oldStyleSheet: oldProps.onFocusedStyle, + }); + }, + addToFocusGroup(comp, v) { + if (v) comp.addToFocusGroup?.(); + }, + autoFocus() { + // handled in commitMount + }, }; + +export function setComponentProps( + comp: any, + compName: string, + newProps: any, + oldProps: any, + componentSetters: Record +) { + for (const key in newProps) { + const setter = componentSetters[key] || commonSetters[key]; + if (!setter) continue; + if (setter.length === 0) { + setter(); + } else if (setter.length === 2) { + setter(comp, newProps[key]); + } else if (setter.length === 3) { + setter(comp, newProps[key], oldProps); + } else if (setter.length === 4) { + setter(comp, newProps[key], compName, oldProps); + } else if (setter.length === 5) { + setter(comp, newProps[key], newProps, oldProps); + } else { + setter(); + } + } + + comp.dataset = {}; + for (const prop in newProps) { + if (prop.indexOf("data-") === 0) { + comp.dataset[prop.substring(5)] = newProps[prop]; + } + } +} + From 46fa7f9d119ffae372d2319459d02af118a68930 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Thu, 22 Jan 2026 15:04:49 +0800 Subject: [PATCH 36/62] chore(deps): update lvgl subproject to commit 74d0a81 This update reflects the latest changes in the lvgl dependency, ensuring compatibility and access to recent improvements. --- deps/lvgl | 2 +- src/render/native/core/animate/animate.cpp | 9 +++++---- src/render/native/core/basic/comp.cpp | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/deps/lvgl b/deps/lvgl index 4495f4286..74d0a816a 160000 --- a/deps/lvgl +++ b/deps/lvgl @@ -1 +1 @@ -Subproject commit 4495f428630cc1741bd8bfd977f080e8460e8e8d +Subproject commit 74d0a816a440eea53e030c4f1af842a94f7ce3d3 diff --git a/src/render/native/core/animate/animate.cpp b/src/render/native/core/animate/animate.cpp index 07b8828c1..a203737bd 100644 --- a/src/render/native/core/animate/animate.cpp +++ b/src/render/native/core/animate/animate.cpp @@ -100,6 +100,11 @@ static JSValue NativeAnimateStart(JSContext *ctx, JSValueConst this_val, int arg readycb_value = JS_GetPropertyStr(ctx, argv[0], "readyCbUid"); use_native_value = JS_GetPropertyStr(ctx, argv[0], "useNative"); + if (JS_IsNumber(uid_value)) { + JS_ToInt32(ctx, &uid, uid_value); + ref->uid = uid; + } + if (animate_map.find(uid) != animate_map.end()) { animate = animate_map.at(uid); } else { @@ -108,10 +113,6 @@ static JSValue NativeAnimateStart(JSContext *ctx, JSValueConst this_val, int arg } lv_anim_init(animate); - if (JS_IsNumber(uid_value)) { - JS_ToInt32(ctx, &uid, uid_value); - ref->uid = uid; - } if (JS_IsNumber(execcb_value)) { JS_ToInt32(ctx, &exec_uid, execcb_value); ref->exec_uid = exec_uid; diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index bf2a64041..c593c360c 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -138,9 +138,9 @@ void BasicComponent::setTransition (JSContext* ctx, JSValue obj, lv_style_t* sty bool BasicComponent::ensureStyle (int32_t type) { lv_style_t* style; - bool is_new; + bool is_new = false; if (this->style_map.find(type) != this->style_map.end()) { - + // style already exists } else { style = static_cast(style_pool.allocate()); style_map[type] = style; From 7e19d378cccc04ac1766b788ee0a5a0821f312d0 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Thu, 22 Jan 2026 17:37:05 +0800 Subject: [PATCH 37/62] refactor: style.cpp remove duplicate code --- src/render/native/core/basic/comp.cpp | 9 +- src/render/native/core/style/style.cpp | 672 +++++-------------------- src/render/native/core/style/style.hpp | 37 +- 3 files changed, 167 insertions(+), 551 deletions(-) diff --git a/src/render/native/core/basic/comp.cpp b/src/render/native/core/basic/comp.cpp index c593c360c..e8269cf41 100644 --- a/src/render/native/core/basic/comp.cpp +++ b/src/render/native/core/basic/comp.cpp @@ -1,6 +1,7 @@ #include "./comp.hpp" #include "native/core/utils/utils.hpp" +#include "native/core/style/style.hpp" std::unordered_map comp_map; @@ -171,9 +172,13 @@ void BasicComponent::setStyle(JSContext* ctx, JSValue& obj, std::vector 0) { - CompSetStyle* func = StyleManager::styles.at(key); + const StyleEntryWrapper& wrapper = StyleManager::styles.at(key); JSValue value = JS_GetPropertyStr(ctx, obj, key.c_str()); - func(this->instance, style, ctx, value); + if (wrapper.type == StyleEntryType::SIMPLE) { + ApplySimpleStyle(this->instance, style, ctx, value, wrapper.entry.simple); + } else { + wrapper.entry.complex(this->instance, style, ctx, value); + } JS_FreeValue(ctx, value); } } diff --git a/src/render/native/core/style/style.cpp b/src/render/native/core/style/style.cpp index faa3fa6e1..e362a9c58 100644 --- a/src/render/native/core/style/style.cpp +++ b/src/render/native/core/style/style.cpp @@ -11,159 +11,24 @@ static std::unordered_map transition_funcs = { { "step", &lv_anim_path_step }, }; -static void CompSetWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_width(style, static_cast(width)); -}; - -static void CompSetMaxWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_max_width(style, static_cast(width)); -}; - -static void CompSetMinWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_min_width(style, static_cast(width)); -}; - -static void CompSetMaxWidthPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_max_width(style, lv_pct(static_cast(width))); -}; - -static void CompSetMinWidthPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_min_width(style, lv_pct(static_cast(width))); -}; - -static void CompSetWidthPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_width(style, lv_pct(static_cast(width))); -}; - -static void CompSetHeight (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int height; - JS_ToInt32(ctx, &height, obj); - lv_style_set_height(style, static_cast(height)); -}; - -static void CompSetHeightPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int height; - JS_ToInt32(ctx, &height, obj); - lv_style_set_height(style, lv_pct(static_cast(height))); -}; - -static void CompSetMaxHeight (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int height; - JS_ToInt32(ctx, &height, obj); - lv_style_set_max_height(style, static_cast(height)); -}; - -static void CompSetMaxHeightPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int height; - JS_ToInt32(ctx, &height, obj); - lv_style_set_max_height(style, lv_pct(static_cast(height))); -}; - -static void CompSetMinHeight (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int height; - JS_ToInt32(ctx, &height, obj); - lv_style_set_min_height(style, static_cast(height)); -}; - -static void CompSetMinHeightPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int height; - JS_ToInt32(ctx, &height, obj); - lv_style_set_min_height(style, lv_pct(static_cast(height))); -}; - -static void CompSetX (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - lv_style_set_x(style, static_cast(x)); -}; - -static void CompSetXPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - lv_style_set_x(style, lv_pct(static_cast(x))); -}; - -static void CompSetY (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - lv_style_set_y(style, static_cast(y)); -}; - -static void CompSetYPch (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - lv_style_set_y(style, lv_pct(static_cast(y))); -}; - -static void CompSetBackgroundColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_bg_color(style, lv_color_hex(y)); -}; - -static void CompSetBackgroundOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_bg_opa(style, y); -}; - -static void CompSetBackgroundGradColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_bg_grad_color(style, lv_color_hex(y)); -}; - -static void CompSetBackgroundGradColorDir (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_bg_grad_dir(style, y); -}; - -static void CompSetArcWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int width; - JS_ToInt32(ctx, &width, obj); - lv_style_set_arc_width(style, static_cast(width)); -}; - -static void CompSetArcRounded (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - bool rounded = JS_ToBool(ctx, obj); - lv_style_set_arc_rounded(style, static_cast(rounded)); -}; - -static void CompSetArcColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int color; - JS_ToInt32(ctx, &color, obj); - lv_style_set_arc_color(style, lv_color_hex(color)); -}; - -static void CompSetArcOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int opacity; - JS_ToInt32(ctx, &opacity, obj); - lv_style_set_arc_opa(style, static_cast(opacity)); -}; - -static void CompSetBorderRadius (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { +void ApplySimpleStyle(lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj, const StylePropConfig& config) { int x; JS_ToInt32(ctx, &x, obj); - - lv_style_set_radius(style, x); -}; + + lv_style_value_t v; + switch (config.type) { + case StyleValueType::NUM: + v.num = x; + break; + case StyleValueType::COLOR: + v.color = lv_color_hex(x); + break; + case StyleValueType::PCT: + v.num = lv_pct(static_cast(x)); + break; + } + lv_style_set_prop(style, config.prop, v); +} static void CompSetDisplay (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { size_t len; @@ -207,7 +72,7 @@ static void CompSetFlexGrow (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, int x; JS_ToInt32(ctx, &x, obj); - lv_style_set_flex_grow(style, static_cast(x)); + lv_style_set_flex_grow(style, static_cast(x)); }; static void CompSetFlexFlow (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { @@ -238,89 +103,6 @@ static void CompSetAlignContent (lv_obj_t* comp, lv_style_t* style, JSContext* c lv_style_set_flex_track_place(style, static_cast(x)); }; -static void CompSetPaddingLeft (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_pad_left(style, x); -}; - -static void CompSetPaddingRight (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_pad_right(style, x); -}; - -static void CompSetPaddingBottom (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_pad_bottom(style, x); -}; - -static void CompSetPaddingTop (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_pad_top(style, x); -}; - -static void CompSetBorderWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_border_width(style, x); -}; - -static void CompSetBorderOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_border_opa(style, x); -}; - -static void CompSetBorderColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_border_color(style, lv_color_hex(x)); -}; - -static void CompSetBorderSide (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_border_side(style, x); -}; - -static void CompSetOutlineWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_outline_width(style, x); -}; - -static void CompSetOutlineOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_outline_opa(style, x); -}; - -static void CompSetOutlineColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_outline_color(style, lv_color_hex(x)); -}; - -static void CompSetOutlinePadding (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_outline_pad(style, x); -}; static void CompSetTextOverFLow (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { int x; @@ -329,34 +111,6 @@ static void CompSetTextOverFLow (lv_obj_t* comp, lv_style_t* style, JSContext* c lv_label_set_long_mode(comp, x); }; -static void CompSetLetterSpacing (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_text_letter_space(style, x); -}; - -static void CompSetLineSpacing (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_text_line_space(style, x); -}; - -static void CompSetTextAlign (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_text_align(style, x); -}; - -static void CompSetDecoration (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_text_decor(style, x); -}; - static void CompSetOverFlowScrolling (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { int x; JS_ToInt32(ctx, &x, obj); @@ -404,55 +158,6 @@ static void CompScrollEnableSnap (lv_obj_t* comp, lv_style_t* style, JSContext* } }; -static void CompSetOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_opa(style, x); -}; - -static void CompSetImgOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_img_opa(style, x); -}; - -static void CompRecolorOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_img_recolor_opa(style, x); -}; - -static void CompSetTranslateX (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_translate_x(style, x); -}; - -static void CompSetTranslateY (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_translate_y(style, x); -}; - -static void CompSetScale (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_transform_zoom(style, x); -}; - -static void CompSetRotate (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_transform_angle(style, x); -}; - static void CompSetImgScale (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { int x; JS_ToInt32(ctx, &x, obj); @@ -501,27 +206,6 @@ static void CompSetChartScaleY (lv_obj_t* comp, lv_style_t* style, JSContext* ct lv_chart_set_zoom_y(comp, x); }; -static void CompSetTransformWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_transform_width(style, x); -}; - -static void CompSetTransformHeight (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_transform_height(style, x); -}; - -static void CompSetStyleTransitionTime (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_anim_time(style, x); -}; - void CompSetTransition ( lv_style_t* style, lv_style_transition_dsc_t* trans, @@ -562,8 +246,8 @@ void CompSetAnimation ( dura_value = JS_GetPropertyStr(ctx, obj, "duration"); if (JS_IsNumber(dura_value)) { - lv_anim_set_time(animate, duration); JS_ToInt32(ctx, &duration, dura_value); + lv_anim_set_time(animate, duration); } JS_FreeValue(ctx, dura_value); @@ -587,97 +271,6 @@ void CompSetAnimation ( lv_anim_start(animate); }; -static void CompSetTextColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_text_color(style, lv_color_hex(y)); -}; - -static void CompSetRecolor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_img_recolor(style, lv_color_hex(y)); -}; - -static void CompSetRowSpacing (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_pad_row(style, y); -}; - -static void CompSetColumnSpacing (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_pad_column(style, y); -}; - -static void CompSetLineWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int y; - JS_ToInt32(ctx, &y, obj); - - lv_style_set_line_width(style, y); -}; - -static void CompSetLineColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_line_color(style, lv_color_hex(x)); -}; - -static void CompSetLineRounded (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_line_rounded(style, x); -}; - -static void CompSetShadowWidth (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_shadow_width(style, x); -}; - -static void CompSetShadowColor (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_shadow_color(style, lv_color_hex(x)); -}; - -static void CompSetShadowSpread (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_shadow_spread(style, x); -}; - -static void CompSetShadowOpacity (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_shadow_opa(style, x); -}; - -static void CompSetOffsetX (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_shadow_ofs_x(style, x); -}; - -static void CompSetOffsetY (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { - int x; - JS_ToInt32(ctx, &x, obj); - - lv_style_set_shadow_ofs_y(style, x); -}; - static void CompSetPosition (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj) { size_t len; const char* str = JS_ToCStringLen(ctx, &len, obj); @@ -801,128 +394,111 @@ static void CompsetGridAlign (lv_obj_t* comp, lv_style_t* style, JSContext* ctx, } }; -std::unordered_map StyleManager::styles { - /* size && position */ - {"width", &CompSetWidth}, - {"max-width", &CompSetMaxWidth}, - {"max-width_pct", &CompSetMaxWidthPch}, - {"min-width", &CompSetMinWidth}, - {"min-width_pct", &CompSetMinWidthPch}, - {"height", &CompSetHeight}, - {"max-height", &CompSetMaxHeight}, - {"max-height_pct", &CompSetMaxHeightPch}, - {"min-height", &CompSetMinHeight}, - {"min-height_pct", &CompSetMinHeightPch}, - {"left", &CompSetX}, - {"top", &CompSetY}, - {"width_pct", &CompSetWidthPch}, - {"height_pct", &CompSetHeightPch}, - {"left_pct", &CompSetXPch}, - {"top_pct", &CompSetYPch}, - - /* background */ - {"background-color", &CompSetBackgroundColor}, - {"background-opacity", &CompSetBackgroundOpacity}, - {"background-grad-color", &CompSetBackgroundGradColor}, - {"background-grad-color-dir", &CompSetBackgroundGradColorDir}, - - /* border-radius */ - {"border-radius", &CompSetBorderRadius}, - - /* arc */ - {"arc-width", &CompSetArcWidth}, - {"arc-rounded", &CompSetArcRounded}, - {"arc-color", &CompSetArcColor}, - {"arc-opacity", &CompSetArcOpacity}, - - /* layout */ - {"display", &CompSetDisplay}, - {"flex-align", &CompSetFlexAlign}, - {"flex-flow", &CompSetFlexFlow}, - {"flex-grow", &CompSetFlexGrow}, - {"justify-content", &CompSetJustifyContent}, - {"align-items", &CompSetAlignItems}, - {"align-content", &CompSetAlignContent}, - - /* padding */ - {"padding-left", &CompSetPaddingLeft}, - {"padding-right", &CompSetPaddingRight}, - {"padding-bottom", &CompSetPaddingBottom}, - {"padding-top", &CompSetPaddingTop}, - - /* border */ - {"border-width", &CompSetBorderWidth}, - {"border-opacity", &CompSetBorderOpacity}, - {"border-color", &CompSetBorderColor}, - {"border-side", &CompSetBorderSide}, - - /* outline */ - {"outline-width", &CompSetOutlineWidth}, - {"outline-opacity", &CompSetOutlineOpacity}, - {"outline-color", &CompSetOutlineColor}, - {"outline-padding", &CompSetOutlinePadding}, - - /* font */ - {"font-size", &CompSetFontSize}, - {"font-size-1", &CompSetFontSize1}, - {"text-overflow", &CompSetTextOverFLow}, - {"letter-spacing", &CompSetLetterSpacing}, - {"text-align", &CompSetTextAlign}, - {"text-decoration", &CompSetDecoration}, - {"line-spacing", &CompSetLineSpacing}, - - /* scroll */ - {"overflow-scrolling", &CompSetOverFlowScrolling}, - {"overflow", &CompSetOverflow}, - {"scroll-snap-x", &CompSetScrollSnapX}, - {"scroll-snap-y", &CompSetScrollSnapY}, - {"scroll-enable-snap", &CompScrollEnableSnap}, - - /* opacity */ - {"opacity", &CompSetOpacity}, - {"img-opacity", &CompSetImgOpacity}, - {"recolor-opacity", &CompRecolorOpacity}, - - /* transform */ - {"translateX", &CompSetTranslateX}, - {"translateY", &CompSetTranslateY}, - {"scale", &CompSetScale}, - {"rotate", &CompSetRotate}, - {"img-scale", &CompSetImgScale}, - {"img-rotate", &CompSetImgRotate}, - {"img-origin", &CompSetTransformOrigin}, - {"chart-scaleX", &CompSetChartScaleX}, - {"chart-scaleY", &CompSetChartScaleY}, - {"transform-width", &CompSetTransformWidth}, - {"transform-height", &CompSetTransformHeight}, - {"style-transition-time", &CompSetStyleTransitionTime}, - - /* color */ - {"text-color", &CompSetTextColor}, - {"recolor", &CompSetRecolor}, - - /* spacing */ - {"row-spacing", &CompSetRowSpacing}, - {"column-spacing", &CompSetColumnSpacing}, +std::unordered_map StyleManager::styles { + {"width", StyleEntryWrapper({LV_STYLE_WIDTH, StyleValueType::NUM})}, + {"max-width", StyleEntryWrapper({LV_STYLE_MAX_WIDTH, StyleValueType::NUM})}, + {"min-width", StyleEntryWrapper({LV_STYLE_MIN_WIDTH, StyleValueType::NUM})}, + {"height", StyleEntryWrapper({LV_STYLE_HEIGHT, StyleValueType::NUM})}, + {"max-height", StyleEntryWrapper({LV_STYLE_MAX_HEIGHT, StyleValueType::NUM})}, + {"min-height", StyleEntryWrapper({LV_STYLE_MIN_HEIGHT, StyleValueType::NUM})}, + {"left", StyleEntryWrapper({LV_STYLE_X, StyleValueType::NUM})}, + {"top", StyleEntryWrapper({LV_STYLE_Y, StyleValueType::NUM})}, + + {"width_pct", StyleEntryWrapper({LV_STYLE_WIDTH, StyleValueType::PCT})}, + {"height_pct", StyleEntryWrapper({LV_STYLE_HEIGHT, StyleValueType::PCT})}, + {"left_pct", StyleEntryWrapper({LV_STYLE_X, StyleValueType::PCT})}, + {"top_pct", StyleEntryWrapper({LV_STYLE_Y, StyleValueType::PCT})}, + {"max-width_pct", StyleEntryWrapper({LV_STYLE_MAX_WIDTH, StyleValueType::PCT})}, + {"min-width_pct", StyleEntryWrapper({LV_STYLE_MIN_WIDTH, StyleValueType::PCT})}, + {"max-height_pct", StyleEntryWrapper({LV_STYLE_MAX_HEIGHT, StyleValueType::PCT})}, + {"min-height_pct", StyleEntryWrapper({LV_STYLE_MIN_HEIGHT, StyleValueType::PCT})}, + + {"background-color", StyleEntryWrapper({LV_STYLE_BG_COLOR, StyleValueType::COLOR})}, + {"background-opacity", StyleEntryWrapper({LV_STYLE_BG_OPA, StyleValueType::NUM})}, + {"background-grad-color", StyleEntryWrapper({LV_STYLE_BG_GRAD_COLOR, StyleValueType::COLOR})}, + {"background-grad-color-dir", StyleEntryWrapper({LV_STYLE_BG_GRAD_DIR, StyleValueType::NUM})}, + + {"border-radius", StyleEntryWrapper({LV_STYLE_RADIUS, StyleValueType::NUM})}, + + {"arc-width", StyleEntryWrapper({LV_STYLE_ARC_WIDTH, StyleValueType::NUM})}, + {"arc-rounded", StyleEntryWrapper({LV_STYLE_ARC_ROUNDED, StyleValueType::NUM})}, + {"arc-color", StyleEntryWrapper({LV_STYLE_ARC_COLOR, StyleValueType::COLOR})}, + {"arc-opacity", StyleEntryWrapper({LV_STYLE_ARC_OPA, StyleValueType::NUM})}, + + {"display", StyleEntryWrapper(&CompSetDisplay)}, + {"flex-align", StyleEntryWrapper(&CompSetFlexAlign)}, + {"flex-flow", StyleEntryWrapper(&CompSetFlexFlow)}, + {"flex-grow", StyleEntryWrapper(&CompSetFlexGrow)}, + {"justify-content", StyleEntryWrapper(&CompSetJustifyContent)}, + {"align-items", StyleEntryWrapper(&CompSetAlignItems)}, + {"align-content", StyleEntryWrapper(&CompSetAlignContent)}, + + {"padding-left", StyleEntryWrapper({LV_STYLE_PAD_LEFT, StyleValueType::NUM})}, + {"padding-right", StyleEntryWrapper({LV_STYLE_PAD_RIGHT, StyleValueType::NUM})}, + {"padding-bottom", StyleEntryWrapper({LV_STYLE_PAD_BOTTOM, StyleValueType::NUM})}, + {"padding-top", StyleEntryWrapper({LV_STYLE_PAD_TOP, StyleValueType::NUM})}, + + {"border-width", StyleEntryWrapper({LV_STYLE_BORDER_WIDTH, StyleValueType::NUM})}, + {"border-opacity", StyleEntryWrapper({LV_STYLE_BORDER_OPA, StyleValueType::NUM})}, + {"border-color", StyleEntryWrapper({LV_STYLE_BORDER_COLOR, StyleValueType::COLOR})}, + {"border-side", StyleEntryWrapper({LV_STYLE_BORDER_SIDE, StyleValueType::NUM})}, + + {"outline-width", StyleEntryWrapper({LV_STYLE_OUTLINE_WIDTH, StyleValueType::NUM})}, + {"outline-opacity", StyleEntryWrapper({LV_STYLE_OUTLINE_OPA, StyleValueType::NUM})}, + {"outline-color", StyleEntryWrapper({LV_STYLE_OUTLINE_COLOR, StyleValueType::COLOR})}, + {"outline-padding", StyleEntryWrapper({LV_STYLE_OUTLINE_PAD, StyleValueType::NUM})}, + + {"font-size", StyleEntryWrapper(&CompSetFontSize)}, + {"font-size-1", StyleEntryWrapper(&CompSetFontSize1)}, + {"text-overflow", StyleEntryWrapper(&CompSetTextOverFLow)}, + {"letter-spacing", StyleEntryWrapper({LV_STYLE_TEXT_LETTER_SPACE, StyleValueType::NUM})}, + {"text-align", StyleEntryWrapper({LV_STYLE_TEXT_ALIGN, StyleValueType::NUM})}, + {"text-decoration", StyleEntryWrapper({LV_STYLE_TEXT_DECOR, StyleValueType::NUM})}, + {"line-spacing", StyleEntryWrapper({LV_STYLE_TEXT_LINE_SPACE, StyleValueType::NUM})}, + + {"overflow-scrolling", StyleEntryWrapper(&CompSetOverFlowScrolling)}, + {"overflow", StyleEntryWrapper(&CompSetOverflow)}, + {"scroll-snap-x", StyleEntryWrapper(&CompSetScrollSnapX)}, + {"scroll-snap-y", StyleEntryWrapper(&CompSetScrollSnapY)}, + {"scroll-enable-snap", StyleEntryWrapper(&CompScrollEnableSnap)}, + + {"opacity", StyleEntryWrapper({LV_STYLE_OPA, StyleValueType::NUM})}, + {"img-opacity", StyleEntryWrapper({LV_STYLE_IMG_OPA, StyleValueType::NUM})}, + {"recolor-opacity", StyleEntryWrapper({LV_STYLE_IMG_RECOLOR_OPA, StyleValueType::NUM})}, + + {"translateX", StyleEntryWrapper({LV_STYLE_TRANSLATE_X, StyleValueType::NUM})}, + {"translateY", StyleEntryWrapper({LV_STYLE_TRANSLATE_Y, StyleValueType::NUM})}, + {"scale", StyleEntryWrapper({LV_STYLE_TRANSFORM_ZOOM, StyleValueType::NUM})}, + {"rotate", StyleEntryWrapper({LV_STYLE_TRANSFORM_ANGLE, StyleValueType::NUM})}, + {"img-scale", StyleEntryWrapper(&CompSetImgScale)}, + {"img-rotate", StyleEntryWrapper(&CompSetImgRotate)}, + {"img-origin", StyleEntryWrapper(&CompSetTransformOrigin)}, + {"chart-scaleX", StyleEntryWrapper(&CompSetChartScaleX)}, + {"chart-scaleY", StyleEntryWrapper(&CompSetChartScaleY)}, + {"transform-width", StyleEntryWrapper({LV_STYLE_TRANSFORM_WIDTH, StyleValueType::NUM})}, + {"transform-height", StyleEntryWrapper({LV_STYLE_TRANSFORM_HEIGHT, StyleValueType::NUM})}, + {"style-transition-time", StyleEntryWrapper({LV_STYLE_ANIM_TIME, StyleValueType::NUM})}, + + {"text-color", StyleEntryWrapper({LV_STYLE_TEXT_COLOR, StyleValueType::COLOR})}, + {"recolor", StyleEntryWrapper({LV_STYLE_IMG_RECOLOR, StyleValueType::COLOR})}, + + {"row-spacing", StyleEntryWrapper({LV_STYLE_PAD_ROW, StyleValueType::NUM})}, + {"column-spacing", StyleEntryWrapper({LV_STYLE_PAD_COLUMN, StyleValueType::NUM})}, + + {"line-width", StyleEntryWrapper({LV_STYLE_LINE_WIDTH, StyleValueType::NUM})}, + {"line-color", StyleEntryWrapper({LV_STYLE_LINE_COLOR, StyleValueType::COLOR})}, + {"line-rounded", StyleEntryWrapper({LV_STYLE_LINE_ROUNDED, StyleValueType::NUM})}, + + {"shadow-width", StyleEntryWrapper({LV_STYLE_SHADOW_WIDTH, StyleValueType::NUM})}, + {"shadow-color", StyleEntryWrapper({LV_STYLE_SHADOW_COLOR, StyleValueType::COLOR})}, + {"shadow-spread", StyleEntryWrapper({LV_STYLE_SHADOW_SPREAD, StyleValueType::NUM})}, + {"shadow-opacity", StyleEntryWrapper({LV_STYLE_SHADOW_OPA, StyleValueType::NUM})}, + {"shadow-offset-x", StyleEntryWrapper({LV_STYLE_SHADOW_OFS_X, StyleValueType::NUM})}, + {"shadow-offset-y", StyleEntryWrapper({LV_STYLE_SHADOW_OFS_Y, StyleValueType::NUM})}, + + {"position", StyleEntryWrapper(&CompSetPosition)}, - /* line comp */ - {"line-width", &CompSetLineWidth}, - {"line-color", &CompSetLineColor}, - {"line-rounded", &CompSetLineRounded}, - - /* shadow */ - {"shadow-width", &CompSetShadowWidth}, - {"shadow-color", &CompSetShadowColor}, - {"shadow-spread", &CompSetShadowSpread}, - {"shadow-opacity", &CompSetShadowOpacity}, - {"shadow-offset-x", &CompSetOffsetX}, - {"shadow-offset-y", &CompSetOffsetY}, - - /* position */ - {"position", &CompSetPosition}, - - /* grid */ - {"grid-template", &CompGridColumnRow}, - {"grid-child", &CompSetGridChild}, - {"grid-align", &CompsetGridAlign}, + {"grid-template", StyleEntryWrapper(&CompGridColumnRow)}, + {"grid-child", StyleEntryWrapper(&CompSetGridChild)}, + {"grid-align", StyleEntryWrapper(&CompsetGridAlign)}, }; diff --git a/src/render/native/core/style/style.hpp b/src/render/native/core/style/style.hpp index ce0445dc1..7ef15282c 100644 --- a/src/render/native/core/style/style.hpp +++ b/src/render/native/core/style/style.hpp @@ -14,11 +14,46 @@ extern "C" { using CompSetStyle = void (lv_obj_t*, lv_style_t*, JSContext*, JSValue); +enum class StyleValueType : uint8_t { + NUM, + COLOR, + PCT, +}; + +struct StylePropConfig { + lv_style_prop_t prop; + StyleValueType type; +}; + +enum class StyleEntryType : uint8_t { + SIMPLE, + COMPLEX, +}; + +union StyleEntry { + StylePropConfig simple; + CompSetStyle* complex; + + StyleEntry() {} + StyleEntry(const StylePropConfig& s) : simple(s) {} + StyleEntry(CompSetStyle* c) : complex(c) {} +}; + +struct StyleEntryWrapper { + StyleEntryType type; + StyleEntry entry; + + StyleEntryWrapper(const StylePropConfig& config) : type(StyleEntryType::SIMPLE), entry(config) {} + StyleEntryWrapper(CompSetStyle* func) : type(StyleEntryType::COMPLEX), entry(func) {} +}; + class StyleManager { public: - static std::unordered_map styles; + static std::unordered_map styles; }; +void ApplySimpleStyle(lv_obj_t* comp, lv_style_t* style, JSContext* ctx, JSValue obj, const StylePropConfig& config); + void CompSetTransition ( lv_style_t* style, lv_style_transition_dsc_t* trans, From ef0daf4f7bdd60b000365a56710906149a771132 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 23 Jan 2026 15:36:43 +0800 Subject: [PATCH 38/62] refactor: rename style-transition-time to transition-time for consistency - Adjusted ProgressBar and Roller components to utilize reordered props for improved property management. - Modified MiscStyle type and its processing logic to reflect the new naming convention. --- src/render/native/core/style/style.cpp | 2 +- .../react/components/ProgressBar/comp.ts | 32 ++++++------------- src/render/react/components/Roller/comp.ts | 16 ++++------ src/render/react/components/common/index.ts | 9 +++++- src/render/react/core/style/pipe/misc.ts | 8 ++--- test/progressbar/2/index.jsx | 4 +-- test/progressbar/3/index.jsx | 2 +- 7 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/render/native/core/style/style.cpp b/src/render/native/core/style/style.cpp index e362a9c58..ec2563872 100644 --- a/src/render/native/core/style/style.cpp +++ b/src/render/native/core/style/style.cpp @@ -477,7 +477,7 @@ std::unordered_map StyleManager::styles { {"chart-scaleY", StyleEntryWrapper(&CompSetChartScaleY)}, {"transform-width", StyleEntryWrapper({LV_STYLE_TRANSFORM_WIDTH, StyleValueType::NUM})}, {"transform-height", StyleEntryWrapper({LV_STYLE_TRANSFORM_HEIGHT, StyleValueType::NUM})}, - {"style-transition-time", StyleEntryWrapper({LV_STYLE_ANIM_TIME, StyleValueType::NUM})}, + {"transition-time", StyleEntryWrapper({LV_STYLE_ANIM_TIME, StyleValueType::NUM})}, {"text-color", StyleEntryWrapper({LV_STYLE_TEXT_COLOR, StyleValueType::COLOR})}, {"recolor", StyleEntryWrapper({LV_STYLE_IMG_RECOLOR, StyleValueType::COLOR})}, diff --git a/src/render/react/components/ProgressBar/comp.ts b/src/render/react/components/ProgressBar/comp.ts index 360225ebf..9783f825a 100644 --- a/src/render/react/components/ProgressBar/comp.ts +++ b/src/render/react/components/ProgressBar/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { setComponentProps, CommonProps } from "../common/index"; +import { setComponentProps, CommonProps, reorderProps } from "../common/index"; import { STYLE_TYPE, setStyle, styleGetterProp } from "../config"; const bridge = globalThis[Symbol.for('lvgljs')]; @@ -8,7 +8,6 @@ const NativeProgressBar = bridge.NativeRender.NativeComponents.ProgressBar; export type ProgressBarProps = CommonProps & { value: number; range: number[]; - animationTime?: number; useAnimation?: boolean; indicatorStyle?: StyleProps; }; @@ -28,11 +27,18 @@ const progressBarSetters = { comp.setRange(arr[0], arr[1]); } }, + value(comp, value) { + comp.setValue(value, comp.useAnimation); + }, + useAnimation(comp, useAnimation: boolean) { + comp.useAnimation = useAnimation; + }, }; export class ProgressBarComp extends NativeProgressBar { uid: string; style: any; + useAnimation: boolean = false; constructor({ uid }) { super({ uid }); @@ -50,27 +56,7 @@ export class ProgressBarComp extends NativeProgressBar { }); } setProps(newProps: ProgressBarProps, oldProps: ProgressBarProps) { - const customSetters = { - ...progressBarSetters, - style(comp, styleSheet, compName, oldProps) { - if (newProps.animationTime) { - styleSheet["style-transition-time"] = newProps.animationTime; - } - setStyle({ - comp, - styleSheet, - compName: "ProgressBar", - styleType: STYLE_TYPE.PART_MAIN, - oldStyleSheet: oldProps.style, - }); - }, - value(comp, value, oldProps) { - if (value !== oldProps.value) { - comp.setValue(value, !!newProps.useAnimation); - } - }, - }; - setComponentProps(this, "ProgressBar", newProps, oldProps, customSetters); + setComponentProps(this, "ProgressBar", reorderProps(newProps, "useAnimation"), oldProps, progressBarSetters); } insertBefore(child, beforeChild) {} static tagName = "ProgressBar"; diff --git a/src/render/react/components/Roller/comp.ts b/src/render/react/components/Roller/comp.ts index 1134bc5fc..dfccf23d2 100644 --- a/src/render/react/components/Roller/comp.ts +++ b/src/render/react/components/Roller/comp.ts @@ -1,5 +1,5 @@ import { StyleProps } from "../../core/style"; -import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; +import { setComponentProps, CommonProps, OnChangeEvent, reorderProps } from "../common/index"; import { EVENTTYPE_MAP, STYLE_TYPE, @@ -33,7 +33,7 @@ const rollerSetters = { }, options(comp, options, oldProps, newProps) { if (options !== oldProps.options && Array.isArray(options)) { - comp.setOptions(options, options.length, !!newProps.infinity); + comp.setOptions(options, options.length, comp.infinity); } }, selectIndex(comp, selectIndex, oldProps) { @@ -49,11 +49,15 @@ const rollerSetters = { onChange(comp, fn) { handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); }, + infinity(comp, infinity: boolean) { + comp.infinity = infinity; + }, }; export class RollerComp extends NativeRoller { uid: string; style: any; + infinity: boolean = false; constructor({ uid }) { super({ uid }); @@ -71,13 +75,7 @@ export class RollerComp extends NativeRoller { }); } setProps(newProps: RollerProps, oldProps: RollerProps) { - const customSetters = { - ...rollerSetters, - options(comp, options, oldProps) { - rollerSetters.options(comp, options, oldProps, newProps); - }, - }; - setComponentProps(this, "Roller", newProps, oldProps, customSetters); + setComponentProps(this, "Roller", reorderProps(newProps, "infinity"), oldProps, rollerSetters); } insertBefore(child, beforeChild) {} static tagName = "Roller"; diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index 5994d1a0a..ba13e92c1 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -5,7 +5,6 @@ import { STYLE_TYPE, handleEvent, setStyle, - styleGetterProp, } from "../config"; import { StyleProps } from "../../core/style"; @@ -218,3 +217,11 @@ export function setComponentProps( } } +export function reorderProps(props: T, priorityKey: keyof T & string): T { + if (props && priorityKey in props) { + const { [priorityKey]: priorityValue, ...rest } = props; + return { [priorityKey]: priorityValue, ...rest } as T; + } + + return props; +} \ No newline at end of file diff --git a/src/render/react/core/style/pipe/misc.ts b/src/render/react/core/style/pipe/misc.ts index 646ad70e2..07f8b9fd1 100644 --- a/src/render/react/core/style/pipe/misc.ts +++ b/src/render/react/core/style/pipe/misc.ts @@ -2,7 +2,7 @@ import { ColorType } from "../color"; import { ProcessColor } from "../util"; export type MiscStyleType = { - "style-transition-time"?: number; + "transition-time"?: number; recolor?: ColorType; }; @@ -10,10 +10,10 @@ export function MiscStyle(style: MiscStyleType, result, compName) { if (style["recolor"] && compName === "Image") { ProcessColor("recolor", style["recolor"], result); } - if (style["style-transition-time"]) { - const value = style["style-transition-time"]; + if (style["transition-time"]) { + const value = style["transition-time"]; if (!isNaN(value)) { - result["style-transition-time"] = value; + result["transition-time"] = value; } } diff --git a/test/progressbar/2/index.jsx b/test/progressbar/2/index.jsx index d8d07a419..045303656 100644 --- a/test/progressbar/2/index.jsx +++ b/test/progressbar/2/index.jsx @@ -13,7 +13,6 @@ function App () { }} value={100} useAnimation={true} - animationTime={1000} indicatorStyle={style.indicator} /> @@ -31,7 +30,8 @@ const style = { 'border-color': 'blue', 'border-width': 2, 'padding': 6, - 'border-radius': 6 + 'border-radius': 6, + 'transition-time': 1000, }, indicator: { 'background-color': 'blue', diff --git a/test/progressbar/3/index.jsx b/test/progressbar/3/index.jsx index 69602b81d..939710c72 100644 --- a/test/progressbar/3/index.jsx +++ b/test/progressbar/3/index.jsx @@ -40,7 +40,6 @@ function App () { value={value} range={[-20, 40]} useAnimation={true} - animationTime={1000} indicatorStyle={style.indicator} /> @@ -60,6 +59,7 @@ const style = { bar: { 'width': 20, 'height': 200, + 'transition-time': 1000, } }; From c4a2f8f4ca6183c6ea763060d967ad60d0f67c8a Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 23 Jan 2026 16:19:00 +0800 Subject: [PATCH 39/62] refactor: simplify align logic in common component setters --- src/render/react/components/common/index.ts | 12 +++--- test/calendar/1/index.jsx | 48 ++++++++++++++------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index ba13e92c1..324e9efa9 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -89,22 +89,22 @@ export const commonSetters = { oldStyleSheet: oldProps.style, }); }, - align(comp, { type, pos = [0, 0] }, newProps, oldProps) { + align(comp, { type, pos = [0, 0] }, oldProps) { if ( !type || (type === oldProps.align?.type && - newProps.align?.pos?.[0] === oldProps.align?.pos?.[0] && - newProps.align?.pos?.[1] === oldProps.align?.pos?.[1]) + pos?.[0] === oldProps.align?.pos?.[0] && + pos?.[1] === oldProps.align?.pos?.[1]) ) return; comp.align(type, pos); }, - alignTo(comp, { type, pos = [0, 0], parent }, newProps, oldProps) { + alignTo(comp, { type, pos = [0, 0], parent }, oldProps) { if ( !type || (type === oldProps.alignTo?.type && - newProps.alignTo?.pos?.[0] === oldProps.alignTo?.pos?.[0] && - newProps.alignTo?.pos?.[1] === oldProps.alignTo?.pos?.[1] && + pos?.[0] === oldProps.alignTo?.pos?.[0] && + pos?.[1] === oldProps.alignTo?.pos?.[1] && parent?.uid === oldProps.alignTo?.parent?.uid) ) return; diff --git a/test/calendar/1/index.jsx b/test/calendar/1/index.jsx index f9731e427..62d5d3f2b 100644 --- a/test/calendar/1/index.jsx +++ b/test/calendar/1/index.jsx @@ -1,27 +1,43 @@ -import { Calendar, Render, Line, EAlignType, Button } from 'lvgljs-ui'; +import { Calendar, Render, Button, Text, EAlignType, View } from 'lvgljs-ui'; import React, { useState } from 'react'; +import { Dimensions } from 'lvgljs-ui'; -function App () { +const { width, height } = Dimensions.window +function App () { + const [pos, setPos] = useState([0, 0]) return ( - { console.log(e.value) }} - /> + + + { console.log(e.value) }} + /> + ) }; const style = { + window: { + width: width, + height: height, + }, calendar: { 'width': 285, 'height': 285, From 2ac6b2d8d01f6fc28c9047822a87e22ef866b556 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 23 Jan 2026 20:10:36 +0800 Subject: [PATCH 40/62] fix: ts warnings --- src/render/react/components/Calendar/comp.ts | 1 + src/render/react/components/Canvas/comp.ts | 4 +++- src/render/react/components/Checkbox/comp.ts | 2 +- src/render/react/components/Image/comp.ts | 1 + src/render/react/components/Image/config.ts | 2 +- src/render/react/components/Keyboard/comp.ts | 1 + src/render/react/components/Switch/comp.ts | 2 +- src/render/react/components/Textarea/config.ts | 2 +- src/render/react/components/Window/comp.ts | 1 + 9 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/render/react/components/Calendar/comp.ts b/src/render/react/components/Calendar/comp.ts index cd63c3c48..a63aa34d2 100644 --- a/src/render/react/components/Calendar/comp.ts +++ b/src/render/react/components/Calendar/comp.ts @@ -2,6 +2,7 @@ import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, + setStyle, styleGetterProp, } from "../config"; diff --git a/src/render/react/components/Canvas/comp.ts b/src/render/react/components/Canvas/comp.ts index 82d149bd4..47f0dee1b 100644 --- a/src/render/react/components/Canvas/comp.ts +++ b/src/render/react/components/Canvas/comp.ts @@ -2,6 +2,7 @@ import { setComponentProps, CommonProps, OnClickEvent } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, + setStyle, styleGetterProp, } from "../config"; import CanvasContext from "./context"; @@ -24,7 +25,8 @@ const canvasSetters = { export class CanvasComp extends NativeButton { uid: string; style: any; - + ctx: CanvasContext = null; + constructor({ uid }) { super({ uid }); this.uid = uid; diff --git a/src/render/react/components/Checkbox/comp.ts b/src/render/react/components/Checkbox/comp.ts index c462dcbb3..101295f80 100644 --- a/src/render/react/components/Checkbox/comp.ts +++ b/src/render/react/components/Checkbox/comp.ts @@ -92,7 +92,7 @@ export class CheckboxComp extends NativeView { setComponentProps(this, "Checkbox", newProps, oldProps, checkboxSetters); } insertBefore(child, beforeChild) { - this.insertChildBefore(child, beforeChild); + super.insertChildBefore(child, beforeChild); } appendInitialChild(child) { this.appendChild(child); diff --git a/src/render/react/components/Image/comp.ts b/src/render/react/components/Image/comp.ts index c1f45596b..27e20bed9 100644 --- a/src/render/react/components/Image/comp.ts +++ b/src/render/react/components/Image/comp.ts @@ -4,6 +4,7 @@ import { setComponentProps, CommonProps } from "../common/index"; import { EVENTTYPE_MAP, handleEvent, + setStyle, styleGetterProp, } from "../config"; import path from 'tjs:path'; diff --git a/src/render/react/components/Image/config.ts b/src/render/react/components/Image/config.ts index bca45d3ff..397db0289 100644 --- a/src/render/react/components/Image/config.ts +++ b/src/render/react/components/Image/config.ts @@ -9,7 +9,7 @@ export default class ImageConfig implements LvgljsComponentConfig Date: Sun, 25 Jan 2026 20:22:34 +0800 Subject: [PATCH 41/62] refactor: update setProps method to use UpdatePayload for Button, Text, and View components - Modified setProps in ButtonComp, TextComp, and ViewComp to accept UpdatePayload instead of newProps, enhancing property management. - Updated corresponding config files to align with the new setProps signature. - Introduced propDiffer utility to handle prop differences and streamline updates across components. --- src/render/react/components/Button/comp.ts | 5 +- src/render/react/components/Button/config.ts | 2 +- src/render/react/components/Text/comp.ts | 9 +- src/render/react/components/Text/config.ts | 4 +- src/render/react/components/View/comp.ts | 5 +- src/render/react/components/View/config.ts | 7 +- src/render/react/components/common/index.ts | 24 +++--- src/render/react/core/reconciler/index.js | 12 +-- .../react/core/reconciler/propDiffer.ts | 83 +++++++++++++++++++ 9 files changed, 118 insertions(+), 33 deletions(-) create mode 100644 src/render/react/core/reconciler/propDiffer.ts diff --git a/src/render/react/components/Button/comp.ts b/src/render/react/components/Button/comp.ts index 5ee90b033..37c520719 100644 --- a/src/render/react/components/Button/comp.ts +++ b/src/render/react/components/Button/comp.ts @@ -1,3 +1,4 @@ +import { UpdatePayload } from "../../core/reconciler/propDiffer"; import { StyleProps } from "../../core/style"; import { setComponentProps, CommonProps, OnClickEvent } from "../common/index"; import { @@ -74,8 +75,8 @@ export class ButtonComp extends NativeButton { }, }); } - setProps(newProps: ButtonProps, oldProps: ButtonProps) { - setComponentProps(this, "Button", newProps, oldProps, buttonSetters); + setProps(updatePayload: UpdatePayload, oldProps: ButtonProps) { + setComponentProps(this, "Button", updatePayload, oldProps, buttonSetters); } insertBefore(child, beforeChild) {} static tagName = "Button"; diff --git a/src/render/react/components/Button/config.ts b/src/render/react/components/Button/config.ts index 61433085f..cfe6b2de0 100644 --- a/src/render/react/components/Button/config.ts +++ b/src/render/react/components/Button/config.ts @@ -14,7 +14,7 @@ export default class ButtonConfig implements LvgljsComponentConfig, oldProps: TextProps) { + setComponentProps(this, "Text", updatePayload, oldProps, textSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Text/config.ts b/src/render/react/components/Text/config.ts index 43b7afc67..03ac2348b 100644 --- a/src/render/react/components/Text/config.ts +++ b/src/render/react/components/Text/config.ts @@ -8,12 +8,12 @@ export default class TextConfig implements LvgljsComponentConfig, oldProps: ViewProps) { + setComponentProps(this, "View", updatePayload, oldProps, viewSetters); } insertBefore(child, beforeChild) { super.insertChildBefore(child, beforeChild); diff --git a/src/render/react/components/View/config.ts b/src/render/react/components/View/config.ts index a8380b7ff..748974ab7 100644 --- a/src/render/react/components/View/config.ts +++ b/src/render/react/components/View/config.ts @@ -1,5 +1,6 @@ import { LvgljsComponentConfig } from "../config"; import { ViewComp, ViewProps } from "./comp"; +import { UpdatePayload } from "../../core/reconciler/propDiffer"; export default class ViewConfig implements LvgljsComponentConfig { tagName = "View"; @@ -8,12 +9,12 @@ export default class ViewConfig implements LvgljsComponentConfig, oldProps: ViewProps, newProps: ViewProps, finishedWork) { + instance.setProps(updatePayload, oldProps); } commitUnmount(instance) {} setProps(newProps: ViewProps, oldProps: ViewProps) {} diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index 324e9efa9..ffe2b566b 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -7,6 +7,7 @@ import { setStyle, } from "../config"; import { StyleProps } from "../../core/style"; +import { UpdatePayload } from "../../core/reconciler/propDiffer"; export type CommonProps = { style?: StyleProps; @@ -187,32 +188,33 @@ export const commonSetters = { export function setComponentProps( comp: any, compName: string, - newProps: any, - oldProps: any, + updatePayload: UpdatePayload, + oldProps: CommonProps, componentSetters: Record ) { - for (const key in newProps) { + if (!updatePayload) return; + + for (const key in updatePayload) { + const value = updatePayload[key]; const setter = componentSetters[key] || commonSetters[key]; if (!setter) continue; if (setter.length === 0) { setter(); } else if (setter.length === 2) { - setter(comp, newProps[key]); + setter(comp, value); } else if (setter.length === 3) { - setter(comp, newProps[key], oldProps); + setter(comp, value, oldProps); } else if (setter.length === 4) { - setter(comp, newProps[key], compName, oldProps); - } else if (setter.length === 5) { - setter(comp, newProps[key], newProps, oldProps); + setter(comp, value, compName, oldProps); } else { setter(); } } comp.dataset = {}; - for (const prop in newProps) { - if (prop.indexOf("data-") === 0) { - comp.dataset[prop.substring(5)] = newProps[prop]; + for (const key in updatePayload) { + if (key.indexOf("data-") === 0) { + comp.dataset[key.substring(5)] = updatePayload[key]; } } } diff --git a/src/render/react/core/reconciler/index.js b/src/render/react/core/reconciler/index.js index eba4c605c..073b2f682 100644 --- a/src/render/react/core/reconciler/index.js +++ b/src/render/react/core/reconciler/index.js @@ -2,6 +2,7 @@ import { getComponentByTagName } from "../../components/config"; import { unRegistEvent } from "../event"; import Reconciler from "react-reconciler"; import { DefaultEventPriority } from "react-reconciler/constants"; +import { diffProps } from "./propDiffer.ts"; let id = 1; @@ -123,7 +124,8 @@ const HostConfig = { return true; }, prepareUpdate(instance, type, oldProps, newProps, rootContainer, hostContext) { - return true; + const skipKeys = type === 'Text' ? [] : ['children']; + return diffProps(oldProps, newProps, skipKeys); }, // --- Mutation Methods --- @@ -166,13 +168,7 @@ const HostConfig = { finishedWork, ) { const { commitUpdate } = getComponentByTagName(type); - return commitUpdate( - instance, - updatePayload, - oldProps, - newProps, - finishedWork, - ); + return commitUpdate(instance, updatePayload, oldProps, newProps, finishedWork); }, // --- Visibility Methods (for Suspense) --- diff --git a/src/render/react/core/reconciler/propDiffer.ts b/src/render/react/core/reconciler/propDiffer.ts new file mode 100644 index 000000000..868080c81 --- /dev/null +++ b/src/render/react/core/reconciler/propDiffer.ts @@ -0,0 +1,83 @@ +export type UpdatePayload = Partial | null; + +export function diffProps>( + oldProps: Props, + newProps: Props, + skipKeys: string[] +): UpdatePayload { + const updatePayload: Partial = {}; + + for (const key in newProps) { + if (skipKeys.includes(key)) { + continue; + } + + const oldValue = oldProps[key]; + const newValue = newProps[key]; + + if (hasChanged(oldValue, newValue)) { + updatePayload[key as keyof Props] = newValue; + } + } + + return Object.keys(updatePayload).length > 0 ? updatePayload : null; +} + +function hasChanged(oldValue: any, newValue: any): boolean { + if (Object.is(oldValue, newValue) || (oldValue == null && newValue == null)) { + return false; + } + + if ((oldValue == null || newValue == null) || (typeof oldValue !== typeof newValue)) { + return true; + } + + if (typeof oldValue === 'function') { + return oldValue !== newValue; + } + + if (Array.isArray(oldValue) && Array.isArray(newValue)) { + return hasArrayChanged(oldValue, newValue); + } + + if (typeof oldValue === 'object') { + return hasObjectChanged(oldValue, newValue); + } + + return true; +} + +function hasArrayChanged(oldArray: any[], newArray: any[]): boolean { + if (oldArray.length !== newArray.length) { + return true; + } + + for (let i = 0; i < oldArray.length; i++) { + if (!Object.is(oldArray[i], newArray[i])) { + return true; + } + } + + return false; +} + +function hasObjectChanged(oldObj: Record, newObj: Record): boolean { + const oldKeys = Object.keys(oldObj); + const newKeys = Object.keys(newObj); + + if (oldKeys.length !== newKeys.length) { + return true; + } + + for (const key of oldKeys) { + if (!(key in newObj)) { + return true; + } + + if (!Object.is(oldObj[key], newObj[key])) { + return true; + } + } + + return false; +} \ No newline at end of file From dbf10bc6b363c598df1b925d3e41376e28a3c9e9 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Sun, 25 Jan 2026 22:32:58 +0800 Subject: [PATCH 42/62] refactor: update setProps method to use UpdatePayload across multiple components - Refactored setProps in various components including Arc, Calendar, Canvas, Chart, Checkbox, Dropdownlist, GIF, Image, Input, Keyboard, Line, Mask, ProgressBar, Roller, Slider, Switch, Tabs, Textarea, and Window to accept UpdatePayload instead of newProps. - Updated corresponding config files to align with the new setProps signature. - Enhanced property management and consistency across components by utilizing the propDiffer utility for handling prop differences. --- demo/hello_world/index.tsx | 7 +- src/render/react/components/Arc/comp.ts | 44 ++--- src/render/react/components/Arc/config.ts | 2 +- src/render/react/components/Calendar/comp.ts | 35 ++-- .../react/components/Calendar/config.ts | 2 +- src/render/react/components/Canvas/comp.ts | 5 +- src/render/react/components/Canvas/config.ts | 2 +- src/render/react/components/Chart/comp.ts | 160 +++++------------- src/render/react/components/Chart/config.ts | 2 +- src/render/react/components/Checkbox/comp.ts | 23 +-- .../react/components/Checkbox/config.ts | 2 +- .../react/components/Dropdownlist/comp.ts | 42 ++--- .../react/components/Dropdownlist/config.ts | 2 +- src/render/react/components/GIF/comp.ts | 9 +- src/render/react/components/GIF/config.ts | 2 +- src/render/react/components/Image/comp.ts | 9 +- src/render/react/components/Image/config.ts | 2 +- src/render/react/components/Input/comp.ts | 35 ++-- src/render/react/components/Input/config.ts | 2 +- src/render/react/components/Keyboard/comp.ts | 18 +- .../react/components/Keyboard/config.ts | 2 +- src/render/react/components/Line/comp.ts | 14 +- src/render/react/components/Line/config.ts | 2 +- src/render/react/components/Mask/comp.ts | 5 +- src/render/react/components/Mask/config.ts | 2 +- .../react/components/ProgressBar/comp.ts | 13 +- .../react/components/ProgressBar/config.ts | 2 +- src/render/react/components/Roller/comp.ts | 25 ++- src/render/react/components/Roller/config.ts | 2 +- src/render/react/components/Slider/comp.ts | 14 +- src/render/react/components/Slider/config.ts | 2 +- src/render/react/components/Switch/comp.ts | 14 +- src/render/react/components/Switch/config.ts | 2 +- src/render/react/components/Tabs/comp.ts | 9 +- src/render/react/components/Tabs/config.ts | 2 +- src/render/react/components/Textarea/comp.ts | 31 ++-- .../react/components/Textarea/config.ts | 2 +- src/render/react/components/Window/comp.ts | 11 +- src/render/react/components/Window/config.ts | 2 +- src/render/react/core/reconciler/index.js | 1 + .../react/core/reconciler/propDiffer.ts | 44 ++++- src/render/react/core/style/index.ts | 7 +- 42 files changed, 245 insertions(+), 368 deletions(-) diff --git a/demo/hello_world/index.tsx b/demo/hello_world/index.tsx index f937c2b71..ead28e644 100644 --- a/demo/hello_world/index.tsx +++ b/demo/hello_world/index.tsx @@ -1,11 +1,12 @@ import { Button, Render, Text, View } from "lvgljs-ui"; -import React from "react"; +import React, { useState } from "react"; function App() { + const [text, setText] = useState("text"); return ( - ); diff --git a/src/render/react/components/Arc/comp.ts b/src/render/react/components/Arc/comp.ts index e3a0d8d54..b7b9fad1b 100644 --- a/src/render/react/components/Arc/comp.ts +++ b/src/render/react/components/Arc/comp.ts @@ -1,4 +1,5 @@ import { StyleProps } from "../../core/style"; +import { UpdatePayload } from "../../core/reconciler/propDiffer"; import { setComponentProps, CommonProps, OnChangeEvent } from "../common/index"; import { EVENTTYPE_MAP, @@ -84,51 +85,32 @@ const arcSetters = { onChange(comp, fn) { handleEvent(comp, fn, EVENTTYPE_MAP.EVENT_VALUE_CHANGED); }, - range(comp, arr, oldProps) { - if (!Array.isArray(arr)) return; + range(comp, arr) { const [min, max] = arr; - if (min === oldProps.range?.[0] && max === oldProps.range?.[1]) return; - if (isNaN(min) || isNaN(max)) return; comp.setRange([min, max]); }, - value(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.value) return; + value(comp, val) { comp.setValue(val); }, - startAngle(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.startAngle) return; + startAngle(comp, val) { comp.setStartAngle(val); }, - endAngle(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.endAngle) return; + endAngle(comp, val) { comp.setEndAngle(val); }, - backgroundStartAngle(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.backgroundStartAngle) return; + backgroundStartAngle(comp, val) { comp.setBackgroundStartAngle(val); }, - backgroundEndAngle(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.backgroundEndAngle) return; + backgroundEndAngle(comp, val) { comp.setBackgroundEndAngle(val); }, - rotation(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.rotation) return; + rotation(comp, val) { comp.setRotation(val); }, - mode(comp, val, oldProps) { - if (val !== oldProps.mode && typeof modes[val] !== "undefined") { - comp.setMode(modes[val]); - } + mode(comp, val) { + comp.setMode(modes[val]); }, - changeRate(comp, val, oldProps) { - if (isNaN(val)) return; - if (val == oldProps.changeRate) return; + changeRate(comp, val) { comp.setChangeRate(val); }, }; @@ -152,8 +134,8 @@ export class ArcComp extends NativeArc { }, }); } - setProps(newProps: ArcProps, oldProps: ArcProps) { - setComponentProps(this, "Arc", newProps, oldProps, arcSetters); + setProps(updatePayload: UpdatePayload, oldProps: ArcProps) { + setComponentProps(this, "Arc", updatePayload, oldProps, arcSetters); } insertBefore(child, beforeChild) {} static tagName = "Arc"; diff --git a/src/render/react/components/Arc/config.ts b/src/render/react/components/Arc/config.ts index 1922ba74e..742921426 100644 --- a/src/render/react/components/Arc/config.ts +++ b/src/render/react/components/Arc/config.ts @@ -15,7 +15,7 @@ export default class ArcConfig implements LvgljsComponentConfig { - const date = new Date(item); - return [date.getFullYear(), date.getMonth() + 1, date.getDate()]; - }); - comp.setHighlightDates(dates, dates.length); - } + highLightDates(comp, dates) { + dates = dates.map((item) => { + const date = new Date(item); + return [date.getFullYear(), date.getMonth() + 1, date.getDate()]; + }); + comp.setHighlightDates(dates, dates.length); }, }; @@ -62,8 +57,8 @@ export class CalendarComp extends NativeCalendar { }, }); } - setProps(newProps: CalendarProps, oldProps: CalendarProps) { - setComponentProps(this, "Calendar", newProps, oldProps, calendarSetters); + setProps(updatePayload: UpdatePayload, oldProps: CalendarProps) { + setComponentProps(this, "Calendar", updatePayload, oldProps, calendarSetters); } insertBefore(child, beforeChild) {} static tagName = "Calendar"; diff --git a/src/render/react/components/Calendar/config.ts b/src/render/react/components/Calendar/config.ts index 64663ddfa..1db32428f 100644 --- a/src/render/react/components/Calendar/config.ts +++ b/src/render/react/components/Calendar/config.ts @@ -14,7 +14,7 @@ export default class CalendarConfig implements LvgljsComponentConfig, oldProps: CanvasProps) { + setComponentProps(this, "Canvas", updatePayload, oldProps, canvasSetters); } insertBefore(child, beforeChild) {} static tagName = "Canvas"; diff --git a/src/render/react/components/Canvas/config.ts b/src/render/react/components/Canvas/config.ts index e66d0897d..c99446b15 100644 --- a/src/render/react/components/Canvas/config.ts +++ b/src/render/react/components/Canvas/config.ts @@ -14,7 +14,7 @@ export default class CanvasConfig implements LvgljsComponentConfig { const arr = []; item.data.forEach((item1) => { @@ -106,22 +100,11 @@ const chartSetters = { comp.setScatterData(data); } }, - leftAxisOption(comp, options, oldProps) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - if (options != oldProps?.leftAxisOption) { - comp.setLeftAxisOption(options); - } + leftAxisOption(comp, options) { + comp.setLeftAxisOption(options); }, - leftAxisData(comp, data, oldProps) { - if (data !== oldProps?.leftAxisData) { + leftAxisData(comp, data) { + if (data) { data = data.map((item) => ({ ...item, color: item.color === void 0 ? -1 : colorTransform(item.color), @@ -129,22 +112,11 @@ const chartSetters = { comp.setLeftAxisData(data); } }, - bottomAxisOption(comp, options, oldProps) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - if (options != oldProps?.bottomAxisOption) { - comp.setBottomAxisOption(options); - } + bottomAxisOption(comp, options) { + comp.setBottomAxisOption(options); }, - bottomAxisData(comp, data, oldProps) { - if (data !== oldProps?.bottomAxisData) { + bottomAxisData(comp, data) { + if (data) { data = data.map((item) => ({ ...item, color: item.color === void 0 ? -1 : colorTransform(item.color), @@ -152,22 +124,11 @@ const chartSetters = { comp.setBottomAxisData(data); } }, - rightAxisOption(comp, options, oldProps) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - if (options != oldProps?.rightAxisOption) { - comp.setRightAxisOption(options); - } + rightAxisOption(comp, options) { + comp.setRightAxisOption(options); }, - rightAxisData(comp, data, oldProps) { - if (data !== oldProps?.rightAxisData) { + rightAxisData(comp, data) { + if (data) { data = data.map((item) => ({ ...item, color: item.color === void 0 ? -1 : colorTransform(item.color), @@ -175,22 +136,11 @@ const chartSetters = { comp.setRightAxisData(data); } }, - topAxisOption(comp, options, oldProps) { - if ( - options.majorLen == void 0 || - options.minorLen == void 0 || - options.majorNum == void 0 || - options.minorNum == void 0 || - !options.drawSize - ) { - return; - } - if (options != oldProps?.topAxisOption) { - comp.setTopAxisOption(options); - } + topAxisOption(comp, options) { + comp.setTopAxisOption(options); }, - topAxisData(comp, data, oldProps) { - if (data !== oldProps?.topAxisData) { + topAxisData(comp, data) { + if (data) { data = data.map((item) => ({ ...item, color: item.color === void 0 ? -1 : colorTransform(item.color), @@ -198,57 +148,29 @@ const chartSetters = { comp.setTopAxisData(data); } }, - leftAxisLabels(comp, arr, oldProps) { - if (arr !== oldProps?.leftAxisLabels) { - comp.setLeftAxisLabels(arr); - } + leftAxisLabels(comp, arr) { + comp.setLeftAxisLabels(arr); }, - rightAxisLabels(comp, arr, oldProps) { - if (arr !== oldProps?.rightAxisLabels) { - comp.setRightAxisLabels(arr); - } + rightAxisLabels(comp, arr) { + comp.setRightAxisLabels(arr); }, - topAxisLabels(comp, arr, oldProps) { - if (arr !== oldProps?.topAxisLabels) { - comp.setTopAxisLabels(arr); - } + topAxisLabels(comp, arr) { + comp.setTopAxisLabels(arr); }, - bottomAxisLabels(comp, arr, oldProps) { - if (arr !== oldProps?.bottomAxisLabels) { - comp.setBottomAxisLabels(arr); - } + bottomAxisLabels(comp, arr) { + comp.setBottomAxisLabels(arr); }, - leftAxisRange(comp, arr, oldProps) { - if ( - arr?.[0] !== oldProps?.leftAxisRange?.[0] || - arr?.[1] !== oldProps?.leftAxisRange?.[1] - ) { - comp.setLeftAxisRange(arr); - } + leftAxisRange(comp, arr) { + comp.setLeftAxisRange(arr); }, - rightAxisRange(comp, arr, oldProps) { - if ( - arr?.[0] !== oldProps?.rightAxisRange?.[0] || - arr?.[1] !== oldProps?.rightAxisRange?.[1] - ) { - comp.setRightAxisRange(arr); - } + rightAxisRange(comp, arr) { + comp.setRightAxisRange(arr); }, - topAxisRange(comp, arr, oldProps) { - if ( - arr?.[0] !== oldProps?.topAxisRange?.[0] || - arr?.[1] !== oldProps?.topAxisRange?.[1] - ) { - comp.setTopAxisRange(arr); - } + topAxisRange(comp, arr) { + comp.setTopAxisRange(arr); }, - bottomAxisRange(comp, arr, oldProps) { - if ( - arr?.[0] !== oldProps?.bottomAxisRange?.[0] || - arr?.[1] !== oldProps?.bottomAxisRange?.[1] - ) { - comp.setBottomAxisRange(arr); - } + bottomAxisRange(comp, arr) { + comp.setBottomAxisRange(arr); }, }; @@ -271,8 +193,8 @@ export class ChartComp extends NativeChart { }, }); } - setProps(newProps: ChartProps, oldProps: ChartProps) { - setComponentProps(this, "Chart", newProps, oldProps, chartSetters); + setProps(updatePayload: UpdatePayload, oldProps: ChartProps) { + setComponentProps(this, "Chart", updatePayload, oldProps, chartSetters); } insertBefore(child, beforeChild) {} static tagName = "Chart"; diff --git a/src/render/react/components/Chart/config.ts b/src/render/react/components/Chart/config.ts index d2f769931..e6b2c8312 100644 --- a/src/render/react/components/Chart/config.ts +++ b/src/render/react/components/Chart/config.ts @@ -14,7 +14,7 @@ export default class ChartConfig implements LvgljsComponentConfig, oldProps: CheckboxProps) { + setComponentProps(this, "Checkbox", updatePayload, oldProps, checkboxSetters); } insertBefore(child, beforeChild) { super.insertChildBefore(child, beforeChild); diff --git a/src/render/react/components/Checkbox/config.ts b/src/render/react/components/Checkbox/config.ts index b78838430..ab8aacb97 100644 --- a/src/render/react/components/Checkbox/config.ts +++ b/src/render/react/components/Checkbox/config.ts @@ -13,7 +13,7 @@ export default class CheckboxConfig implements LvgljsComponentConfig, oldProps: DropdownListProps) { + setComponentProps(this, "Dropdownlist", updatePayload, oldProps, dropdownlistSetters); } insertBefore(child, beforeChild) {} static tagName = "Dropdownlist"; diff --git a/src/render/react/components/Dropdownlist/config.ts b/src/render/react/components/Dropdownlist/config.ts index 99cb3b146..34782005a 100644 --- a/src/render/react/components/Dropdownlist/config.ts +++ b/src/render/react/components/Dropdownlist/config.ts @@ -14,7 +14,7 @@ export default class DropdownlistConfig implements LvgljsComponentConfig, oldProps: GIFProps) { + setComponentProps(this, "GIF", updatePayload, oldProps, gifSetters); } insertBefore(child, beforeChild) {} static tagName = "GIF"; diff --git a/src/render/react/components/GIF/config.ts b/src/render/react/components/GIF/config.ts index 5f2c76084..7508673ec 100644 --- a/src/render/react/components/GIF/config.ts +++ b/src/render/react/components/GIF/config.ts @@ -14,7 +14,7 @@ export default class GIFConfig implements LvgljsComponentConfig, oldProps: ImageProps) { + setComponentProps(this, "Image", updatePayload, oldProps, imageSetters); } insertBefore(child, beforeChild) {} static tagName = "Image"; diff --git a/src/render/react/components/Image/config.ts b/src/render/react/components/Image/config.ts index 397db0289..0e3075239 100644 --- a/src/render/react/components/Image/config.ts +++ b/src/render/react/components/Image/config.ts @@ -14,7 +14,7 @@ export default class ImageConfig implements LvgljsComponentConfig, oldProps: InputProps) { + setComponentProps(this, "Input", updatePayload, oldProps, inputSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Input/config.ts b/src/render/react/components/Input/config.ts index 5cc441867..da5ca480c 100644 --- a/src/render/react/components/Input/config.ts +++ b/src/render/react/components/Input/config.ts @@ -13,7 +13,7 @@ export default class InputConfig implements LvgljsComponentConfig, oldProps: KeyboardProps) { + setComponentProps(this, "Keyboard", updatePayload, oldProps, keyboardSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Keyboard/config.ts b/src/render/react/components/Keyboard/config.ts index 72c92f1fd..370ebefb0 100644 --- a/src/render/react/components/Keyboard/config.ts +++ b/src/render/react/components/Keyboard/config.ts @@ -13,7 +13,7 @@ export default class KeyboardConfig implements LvgljsComponentConfig, oldProps: LineProps) { + setComponentProps(this, "Line", updatePayload, oldProps, lineSetters); } insertBefore(child, beforeChild) {} static tagName = "Line"; diff --git a/src/render/react/components/Line/config.ts b/src/render/react/components/Line/config.ts index e0f44aa10..c0aef7935 100644 --- a/src/render/react/components/Line/config.ts +++ b/src/render/react/components/Line/config.ts @@ -14,7 +14,7 @@ export default class LineConfig implements LvgljsComponentConfig, oldProps: MaskProps) { + setComponentProps(this, "Mask", updatePayload, oldProps, maskSetters); } insertBefore(child, beforeChild) {} static tagName = "Mask"; diff --git a/src/render/react/components/Mask/config.ts b/src/render/react/components/Mask/config.ts index 63032b041..0e0eabc9e 100644 --- a/src/render/react/components/Mask/config.ts +++ b/src/render/react/components/Mask/config.ts @@ -14,7 +14,7 @@ export default class MaskConfig implements LvgljsComponentConfig(newProps, "useAnimation"), oldProps, progressBarSetters); + setProps(updatePayload: UpdatePayload, oldProps: ProgressBarProps) { + setComponentProps(this, "ProgressBar", updatePayload, oldProps, progressBarSetters); } insertBefore(child, beforeChild) {} static tagName = "ProgressBar"; diff --git a/src/render/react/components/ProgressBar/config.ts b/src/render/react/components/ProgressBar/config.ts index 08b1aeb1e..7e9fc6ee3 100644 --- a/src/render/react/components/ProgressBar/config.ts +++ b/src/render/react/components/ProgressBar/config.ts @@ -14,7 +14,7 @@ export default class ProgressBarConfig implements LvgljsComponentConfig(newProps, "infinity"), oldProps, rollerSetters); + setProps(updatePayload: UpdatePayload, oldProps: RollerProps) { + setComponentProps(this, "Roller", updatePayload, oldProps, rollerSetters); } insertBefore(child, beforeChild) {} static tagName = "Roller"; diff --git a/src/render/react/components/Roller/config.ts b/src/render/react/components/Roller/config.ts index 9da946668..c033b4fa1 100644 --- a/src/render/react/components/Roller/config.ts +++ b/src/render/react/components/Roller/config.ts @@ -14,7 +14,7 @@ export default class RollerConfig implements LvgljsComponentConfig, oldProps: SliderProps) { + setComponentProps(this, "Slider", updatePayload, oldProps, sliderSetters); } insertBefore(child, beforeChild) {} static tagName = "Slider"; diff --git a/src/render/react/components/Slider/config.ts b/src/render/react/components/Slider/config.ts index 30956694e..f58080ba6 100644 --- a/src/render/react/components/Slider/config.ts +++ b/src/render/react/components/Slider/config.ts @@ -14,7 +14,7 @@ export default class SliderConfig implements LvgljsComponentConfig, oldProps: SwitchProps) { + setComponentProps(this, "Switch", updatePayload, oldProps, switchSetters); } insertBefore(child, beforeChild) { super.insertChildBefore(child, beforeChild); diff --git a/src/render/react/components/Switch/config.ts b/src/render/react/components/Switch/config.ts index 0bb5f012a..24a8d97cb 100644 --- a/src/render/react/components/Switch/config.ts +++ b/src/render/react/components/Switch/config.ts @@ -13,7 +13,7 @@ export default class SwitchConfig implements LvgljsComponentConfig, oldProps: TabsProps) { + if (updatePayload?.tabs) { + this.tabs = updatePayload.tabs; + } + setComponentProps(this, "Tabs", updatePayload, oldProps, tabsSetters); } insertBefore(child, beforeChild) {} static tagName = "Tabs"; diff --git a/src/render/react/components/Tabs/config.ts b/src/render/react/components/Tabs/config.ts index bdc388137..d75b9628d 100644 --- a/src/render/react/components/Tabs/config.ts +++ b/src/render/react/components/Tabs/config.ts @@ -14,7 +14,7 @@ export default class TabsConfig implements LvgljsComponentConfig, oldProps: TextAreaProps) { + setComponentProps(this, "Textarea", updatePayload, oldProps, textareaSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) {} diff --git a/src/render/react/components/Textarea/config.ts b/src/render/react/components/Textarea/config.ts index 984eb8e28..81f920311 100644 --- a/src/render/react/components/Textarea/config.ts +++ b/src/render/react/components/Textarea/config.ts @@ -13,7 +13,7 @@ export default class TextareaConfig implements LvgljsComponentConfig, oldProps: WindowProps) { + setComponentProps(this, "Window", updatePayload, oldProps, windowSetters); } insertBefore(child, beforeChild) {} appendInitialChild(child) { diff --git a/src/render/react/components/Window/config.ts b/src/render/react/components/Window/config.ts index d90782ad2..b95865d8c 100644 --- a/src/render/react/components/Window/config.ts +++ b/src/render/react/components/Window/config.ts @@ -13,7 +13,7 @@ export default class WindowConfig implements LvgljsComponentConfig>( return Object.keys(updatePayload).length > 0 ? updatePayload : null; } -function hasChanged(oldValue: any, newValue: any): boolean { +function commonPreCheckChanged(oldValue: any, newValue: any): boolean | null { if (Object.is(oldValue, newValue) || (oldValue == null && newValue == null)) { return false; } - if ((oldValue == null || newValue == null) || (typeof oldValue !== typeof newValue)) { + if ((oldValue == null && newValue !== null) || (oldValue !== null && newValue == null)) { return true; } - if (typeof oldValue === 'function') { - return oldValue !== newValue; + if (typeof oldValue === 'function' && typeof newValue === 'function') { + return false; } + if (typeof oldValue !== typeof newValue) { + return true; + } + + return null; +} + +function hasChanged(oldValue: any, newValue: any): boolean { + const preCheck = commonPreCheckChanged(oldValue, newValue); + if (typeof preCheck === 'boolean') return preCheck; + if (Array.isArray(oldValue) && Array.isArray(newValue)) { return hasArrayChanged(oldValue, newValue); } - if (typeof oldValue === 'object') { + if (typeof oldValue === 'object' && typeof newValue === 'object') { return hasObjectChanged(oldValue, newValue); } - return true; + return oldValue !== newValue; +} + +function hasItemChanged(oldValue: any, newValue: any): boolean { + const preCheck = commonPreCheckChanged(oldValue, newValue); + if (typeof preCheck === 'boolean') return preCheck; + + if (typeof oldValue === 'object' && typeof newValue === 'object') { + if (Array.isArray(oldValue) && Array.isArray(newValue)) { + return hasArrayChanged(oldValue, newValue); + } else if (!Array.isArray(oldValue) && !Array.isArray(newValue)) { + return hasObjectChanged(oldValue, newValue); + } else { + return true; + } + } + + return oldValue !== newValue; } function hasArrayChanged(oldArray: any[], newArray: any[]): boolean { @@ -53,7 +81,7 @@ function hasArrayChanged(oldArray: any[], newArray: any[]): boolean { } for (let i = 0; i < oldArray.length; i++) { - if (!Object.is(oldArray[i], newArray[i])) { + if (hasItemChanged(oldArray[i], newArray[i])) { return true; } } @@ -74,7 +102,7 @@ function hasObjectChanged(oldObj: Record, newObj: Record item !== oldStyleSheet[i]); - - if (!maybeChange) return; styleSheet = Object.assign({}, defaultStyle, ...styleSheet); const result = StyleSheet.transform(styleSheet, compName); From 127a9ad5cf38deac9999ed3237940c059d091641 Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Sun, 25 Jan 2026 22:35:18 +0800 Subject: [PATCH 43/62] refactor: update setProps method to use type assertions for component props --- src/render/react/components/Keyboard/comp.ts | 1 - src/render/react/components/ProgressBar/config.ts | 2 +- src/render/react/components/Roller/config.ts | 2 +- src/render/react/components/Slider/config.ts | 2 +- src/render/react/components/Window/config.ts | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/render/react/components/Keyboard/comp.ts b/src/render/react/components/Keyboard/comp.ts index c9c8451f5..cf3e3f5ab 100644 --- a/src/render/react/components/Keyboard/comp.ts +++ b/src/render/react/components/Keyboard/comp.ts @@ -1,6 +1,5 @@ import { UpdatePayload } from "../../core/reconciler/propDiffer"; import { setComponentProps, CommonProps } from "../common/index"; -import { UpdatePayload } from "../../core/reconciler/propDiffer"; import { EVENTTYPE_MAP, handleEvent, diff --git a/src/render/react/components/ProgressBar/config.ts b/src/render/react/components/ProgressBar/config.ts index 7e9fc6ee3..0bc6df41b 100644 --- a/src/render/react/components/ProgressBar/config.ts +++ b/src/render/react/components/ProgressBar/config.ts @@ -9,7 +9,7 @@ export default class ProgressBarConfig implements LvgljsComponentConfig Date: Mon, 26 Jan 2026 17:19:41 +0800 Subject: [PATCH 44/62] feat: add gateway demo --- demo/gateway/assets/home1.png | Bin 0 -> 725 bytes demo/gateway/assets/home2.png | Bin 0 -> 252 bytes demo/gateway/assets/home3.png | Bin 0 -> 639 bytes demo/gateway/assets/home4.png | Bin 0 -> 631 bytes demo/gateway/components/ConfirmDialog.tsx | 99 +++++++++++++++ demo/gateway/components/Header.tsx | 30 +++++ demo/gateway/components/ListItem.tsx | 90 +++++++++++++ demo/gateway/i18n/en.json | 49 +++++++ demo/gateway/i18n/zh.json | 49 +++++++ demo/gateway/index.tsx | 48 +++++++ demo/gateway/pages/ClearLogsPage.tsx | 51 ++++++++ demo/gateway/pages/CountdownSettingsPage.tsx | 94 ++++++++++++++ demo/gateway/pages/DeviceInfoPage.tsx | 99 +++++++++++++++ demo/gateway/pages/DeviceStatusPage.tsx | 99 +++++++++++++++ demo/gateway/pages/ExportLogsPage.tsx | 67 ++++++++++ demo/gateway/pages/HomePage.tsx | 127 +++++++++++++++++++ demo/gateway/pages/LanguageSettingsPage.tsx | 104 +++++++++++++++ demo/gateway/pages/LogDetailPage.tsx | 99 +++++++++++++++ demo/gateway/pages/LogListPage.tsx | 68 ++++++++++ demo/gateway/pages/SettingsPage.tsx | 68 ++++++++++ tsconfig.json | 20 ++- 21 files changed, 1258 insertions(+), 3 deletions(-) create mode 100644 demo/gateway/assets/home1.png create mode 100644 demo/gateway/assets/home2.png create mode 100644 demo/gateway/assets/home3.png create mode 100644 demo/gateway/assets/home4.png create mode 100644 demo/gateway/components/ConfirmDialog.tsx create mode 100644 demo/gateway/components/Header.tsx create mode 100644 demo/gateway/components/ListItem.tsx create mode 100644 demo/gateway/i18n/en.json create mode 100644 demo/gateway/i18n/zh.json create mode 100644 demo/gateway/index.tsx create mode 100644 demo/gateway/pages/ClearLogsPage.tsx create mode 100644 demo/gateway/pages/CountdownSettingsPage.tsx create mode 100644 demo/gateway/pages/DeviceInfoPage.tsx create mode 100644 demo/gateway/pages/DeviceStatusPage.tsx create mode 100644 demo/gateway/pages/ExportLogsPage.tsx create mode 100644 demo/gateway/pages/HomePage.tsx create mode 100644 demo/gateway/pages/LanguageSettingsPage.tsx create mode 100644 demo/gateway/pages/LogDetailPage.tsx create mode 100644 demo/gateway/pages/LogListPage.tsx create mode 100644 demo/gateway/pages/SettingsPage.tsx diff --git a/demo/gateway/assets/home1.png b/demo/gateway/assets/home1.png new file mode 100644 index 0000000000000000000000000000000000000000..a890081298b3c2932e099933ae77b9805789afb1 GIT binary patch literal 725 zcmV;`0xJE9P)ff}lMU1fnhnxS&~6ZQf~FJ1Bcv19nIP^2R3~sc!SxPQnxc?vK2p>l zfIr|6z+gx{pG3Yp87LGAg+ifFC@dHexzaeu|8W{OSUM`A5{?=fd4>E`;HZ(2F$AB3 z;~kbtcRM@bVZWsD(2HA}u%6E^BgGoF!F}$Tv+7%GG<5Nszb?{gGF?DzJi3#u=q`5i|GYF^Io&O z3mqJj;Rf>&YfyHS%5axmhxu`>S>A*UWCd^Z&lS?JP3F5s3;!I}NOxCz6?}oAQNi~T zkCP*Xfqs52@g~JMAO{kE_BuJ?kic#F?WO92$yNf28y?m zS>{ec!ZUG6&dW3m=&CBE9{v?Lt_6Yawl+T0F18>UqX9s9-H!FZb8^2 z^=?Y>5c=(Y07p%X{e;|z?_{t?M^Kg}t|gSOwJZ6J$5!HKkON6;-8k`&Lf^c##Jemb z*jl~@$4|slY21mw1@{_1G~U8*YN=hyHgq6cE!l-VVtxddhcqhsR^|m&pU1R#>^QPT z=tDmfXPr9>fx-&nCmbcPM_2mZ6udC<6rf40p| z4)H>)#Y_LI#*0mTP_Z?pK#spmGgsy$j)U~Lr(b60l literal 0 HcmV?d00001 diff --git a/demo/gateway/assets/home2.png b/demo/gateway/assets/home2.png new file mode 100644 index 0000000000000000000000000000000000000000..004a6900e6caafb4a4840197c930a234fa65b28f GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND9BhG z&Y9{A$|Yw+m<>d}vSyc`kX&bf?zw`>JJEB#)*71` z#2joLPAYIsc>F=pLG&d@*o%)-_Du?2$0Eo&<9_h|mL)MKr#;h(oO|o*v#_0J9G>M} u#y5*|7B1Nw14`Z3~Ts2FPw{bwnF?hQAxvXt&HvlJSoj{pDIst4T8>Dv{UNHo6K#IP8-@6i$ zGxsq+?w$pxNC+`STcTxRxH3>ga|2iC>{YyfYUDcqj4Me(tx`T0*H1y99DsdcVKPnIg^i4juuw@q-3Y4RLplvi`l=Y|3QA4&Y zMSH_-$ms=xzYs)aoZ36=C*YhhUx9NKASa6rNiI@+V)fhO`%w&2#9g5+lE2HKdwjU~ z9x5=AvO2xR0lF_62okG<5+(pk;sE&=bb&By;KRhA&pEV;OE9gbFrOjPQiW;o%M7vB zL(fntO7Si}w`g;;*9Jej?rwSe6c}2WM`%&kYaf95yim{#gF_$vyG(6eT%d2L-*|)*>2idm)i{bzkWkY6Ys$W56JOzv508wI`!!OiV*~Wek&WX;N zxYwSNSyIg{GNH+85cGS(5 z4y(znr%q+ap+E9g9H4$c$5M`$KX6VOhOYycZv&$T0=ir6OpiQDFro&s`k z{IGq#*uccZ#Kd1FLjZ_q&X=6EWX+WX7gj5jW!VQ(Mwnn#tOM&zX2d-^R*95QMqVvV z^wEeqFgB`3T#Vc@Rw6e1(46GZ3dI{@q0BTCo|AYMLK4wTM?*4VS~Ih~QTnZd`gk55d?LQ&1@2&UZ>fGW@!xH=>6N42Aq<13uHEwXV&X!4M%mYJT;2>MQIW za^x#a`lrwp>gLd0DMw65ljG?Oyfo!`Fcyu`wD{h5RdnYbz!yq^#y^sCzta< zi@@j%xh{gE@LLVFeFZv0HPWP;k2mQxq<)lQFMa9?O+n#^^w{ePO@_8e4<|!4(i(P0 z-TV<~4T%L2a-~m&HC!RN)!Wc;mREI^G@QLnd#z3%xUv=GuFnu!$XB~A)9s)0Jr>YmDXj|4f^?;x2a{9H&|uM6bF#KgqE;tO>x7$u?l Rz<2-v002ovPDHLkV1m8}5vKqE literal 0 HcmV?d00001 diff --git a/demo/gateway/components/ConfirmDialog.tsx b/demo/gateway/components/ConfirmDialog.tsx new file mode 100644 index 000000000..54eace51f --- /dev/null +++ b/demo/gateway/components/ConfirmDialog.tsx @@ -0,0 +1,99 @@ +import React from "react"; +import { Button, Text, View, Dimensions } from "lvgljs-ui"; + +const { width, height } = Dimensions.window; + +interface ConfirmDialogProps { + title: string; + onConfirm: () => void; + onCancel: () => void; + confirmText?: string; + cancelText?: string; +} + +export function ConfirmDialog({ + title, + onConfirm, + onCancel, + confirmText = "确认", + cancelText = "取消", +}: ConfirmDialogProps) { + return ( + + + {title} + + + + + + + ); +} + +const style: Record = { + overlay: { + position: "absolute", + width, + height, + "background-color": "rgba(0, 0, 0, 0.7)", + display: "flex", + "align-items": "center", + "justify-content": "center", + zIndex: 1000, + }, + dialog: { + width: width - 80, + "background-color": "black", + "border-radius": 12, + padding: 24, + display: "flex", + "flex-direction": "column", + "align-items": "center", + }, + title: { + "text-color": "white", + "font-size": 16, + "text-align": "center", + "margin-bottom": 24, + }, + buttons: { + display: "flex", + "flex-direction": "row", + "justify-content": "space-between", + width: "100%", + gap: 16, + }, + button: { + flex: 1, + height: 44, + "border-radius": 8, + "background-color": "0x404040", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + buttonText: { + "text-color": "white", + "font-size": 18, + }, + buttonFocused: { + "border-width": 3, + "border-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/components/Header.tsx b/demo/gateway/components/Header.tsx new file mode 100644 index 000000000..7f8a73a18 --- /dev/null +++ b/demo/gateway/components/Header.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { Text, View, useT } from "lvgljs-ui"; + +interface HeaderProps { + title: string; +} + +export function Header({ title }: HeaderProps) { + return ( + + {title} + + ); +} + +const style: Record = { + header: { + width: "100%", + height: 52, + display: "flex", + "flex-direction": "row", + "align-items": "center", + "background-color": "0x202020", + padding: "0 16px", + }, + headerTitle: { + "text-color": "white", + "font-size": 16, + }, +}; diff --git a/demo/gateway/components/ListItem.tsx b/demo/gateway/components/ListItem.tsx new file mode 100644 index 000000000..248884131 --- /dev/null +++ b/demo/gateway/components/ListItem.tsx @@ -0,0 +1,90 @@ +import React from "react"; +import { Text, View } from "lvgljs-ui"; + +interface ListItemProps { + title: string; + badge?: string; + badgeColor?: string; + showArrow?: boolean; + onClick?: () => void; + autoFocus?: boolean; +} + +export function ListItem({ + title, + badge, + badgeColor = "0xFF0000", + showArrow = true, + onClick, + autoFocus = false, +}: ListItemProps) { + return ( + + + {title} + {badge && ( + + {badge} + + )} + + {showArrow && ( + + )} + + ); +} + +const style: Record = { + listItem: { + width: "100%", + height: 60, + "border-radius": 10, + "background-color": "0x2a2a2a", + margin: "0 0 8px 0", + padding: "0 16px", + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "space-between", + "scroll-on-focus": 1, + }, + content: { + display: "flex", + "flex-direction": "row", + "align-items": "center", + "flex": 1, + }, + title: { + "text-color": "white", + "font-size": 16, + }, + badge: { + "border-radius": 12, + padding: "2px 8px", + margin: "0 0 0 12px", + display: "flex", + "align-items": "center", + "justify-content": "center", + "min-width": 24, + height: 20, + }, + badgeText: { + "text-color": "white", + "font-size": 12, + }, + arrow: { + "text-color": "white", + "font-size": 18, + margin: "0 0 0 12px", + }, + focused: { + "background-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/i18n/en.json b/demo/gateway/i18n/en.json new file mode 100644 index 000000000..5b7535799 --- /dev/null +++ b/demo/gateway/i18n/en.json @@ -0,0 +1,49 @@ +{ + "home": { + "title": "Smart Gateway" + }, + "header": { + "eventLog": "Event Log", + "deviceInfo": "Device Info", + "deviceStatus": "Device Status", + "settings": "Setting" + }, + "logs": { + "title": "Event Log", + "alerts": "Alerts", + "notification": "Notification", + "detail": "Log Detail" + }, + "deviceInfo": { + "title": "Device Info" + }, + "deviceStatus": { + "title": "Device Status" + }, + "settings": { + "title": "Setting", + "language": "Language", + "exportLogs": "Export Logs To Micro SD", + "clearLogs": "Clear Logs", + "countdown": "Countdown" + }, + "language": { + "title": "Language", + "zh": "简体中文", + "en": "English", + "ja": "日本語" + }, + "countdown": { + "title": "Countdown", + "time": "{remain}s" + }, + "exportLogs": { + "title": "Export Logs To Micro SD" + }, + "clearLogs": { + "title": "Clear Logs", + "confirm": "Confirm To Clear The Logs?", + "cancel": "Cancel", + "confirmBtn": "Confirm" + } +} diff --git a/demo/gateway/i18n/zh.json b/demo/gateway/i18n/zh.json new file mode 100644 index 000000000..d030fd918 --- /dev/null +++ b/demo/gateway/i18n/zh.json @@ -0,0 +1,49 @@ +{ + "home": { + "title": "智慧网关" + }, + "header": { + "eventLog": "Event Log", + "deviceInfo": "Device Info", + "deviceStatus": "Device Status", + "settings": "Setting" + }, + "logs": { + "title": "Event Log", + "alerts": "Alerts", + "notification": "Notification", + "detail": "日志详情" + }, + "deviceInfo": { + "title": "Device Info" + }, + "deviceStatus": { + "title": "Device Status" + }, + "settings": { + "title": "Setting", + "language": "Language", + "exportLogs": "Export Logs To Micro SD", + "clearLogs": "Clear Logs", + "countdown": "Countdown" + }, + "language": { + "title": "Language", + "zh": "简体中文", + "en": "English", + "ja": "日本語" + }, + "countdown": { + "title": "Countdown", + "time": "剩余{remain}秒" + }, + "exportLogs": { + "title": "Export Logs To Micro SD" + }, + "clearLogs": { + "title": "Clear Logs", + "confirm": "Confirm To Clear The Logs?", + "cancel": "取消", + "confirmBtn": "确认" + } +} diff --git a/demo/gateway/index.tsx b/demo/gateway/index.tsx new file mode 100644 index 000000000..10815f325 --- /dev/null +++ b/demo/gateway/index.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { MemoryRouter, Route, Routes } from "react-router"; +import { I18nProvider, Render } from "lvgljs-ui"; +import { HomePage } from "./pages/HomePage"; +import { LogListPage } from "./pages/LogListPage"; +import { LogDetailPage } from "./pages/LogDetailPage"; +import { DeviceInfoPage } from "./pages/DeviceInfoPage"; +import { DeviceStatusPage } from "./pages/DeviceStatusPage"; +import { SettingsPage } from "./pages/SettingsPage"; +import { LanguageSettingsPage } from "./pages/LanguageSettingsPage"; +import { CountdownSettingsPage } from "./pages/CountdownSettingsPage"; +import { ExportLogsPage } from "./pages/ExportLogsPage"; +import { ClearLogsPage } from "./pages/ClearLogsPage"; + +declare const require: any; +const messages = (locale: string) => { + if (locale === "zh") return require("./i18n/zh.json"); + return require("./i18n/en.json"); +}; + +function App() { + return ( + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + ); +} + +function Root() { + return ( + + + + ); +} + +Render.render(); diff --git a/demo/gateway/pages/ClearLogsPage.tsx b/demo/gateway/pages/ClearLogsPage.tsx new file mode 100644 index 000000000..bb0ffee0f --- /dev/null +++ b/demo/gateway/pages/ClearLogsPage.tsx @@ -0,0 +1,51 @@ +import React, { useState } from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; +import { ConfirmDialog } from "../components/ConfirmDialog"; + +const { width, height } = Dimensions.window; + +export function ClearLogsPage() { + const t = useT(); + const navigate = useNavigate(); + const [showDialog, setShowDialog] = useState(true); + + const handleConfirm = () => { + // 执行清除日志操作 + setShowDialog(false); + navigate(-1); + }; + + const handleCancel = () => { + setShowDialog(false); + navigate(-1); + }; + + return ( + +
+ {showDialog && ( + + )} + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, +}; diff --git a/demo/gateway/pages/CountdownSettingsPage.tsx b/demo/gateway/pages/CountdownSettingsPage.tsx new file mode 100644 index 000000000..78991309e --- /dev/null +++ b/demo/gateway/pages/CountdownSettingsPage.tsx @@ -0,0 +1,94 @@ +import React, { useEffect, useState } from "react"; +import { useNavigate } from "react-router"; +import { Arc, Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; + +const { width, height } = Dimensions.window; + +export function CountdownSettingsPage() { + const t = useT(); + const navigate = useNavigate(); + const total = 60; + const [remain, setRemain] = useState(total); + + useEffect(() => { + setRemain(total); + const timer = setInterval(() => { + setRemain((r) => (r <= 0 ? 0 : r - 1)); + }, 1000); + return () => clearInterval(timer); + }, []); + + const elapsed = total - remain; + const angle = Math.floor((elapsed / total) * 360); + + return ( + navigate(-1)}> +
+ + + { + // keep non-interactive for this demo + }} + /> + {t("countdown.time", { remain })} + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + centerContent: { + width, + height: height - 52, + display: "flex", + "flex-direction": "column", + "justify-content": "center", + "align-items": "center", + }, + arc: { + width: 220, + height: 220, + "arc-width": 18, + "arc-color": "red", + "arc-rounded": true, + "background-color": "black", + }, + arcIndicator: { + "arc-width": 18, + "arc-color": "0x4267FF", + "arc-rounded": true, + }, + arcKnobHidden: { + width: 1, + height: 1, + opacity: 0, + }, + bigText: { + "text-color": "white", + "font-size": 26, + "padding-top": 20, + }, +}; diff --git a/demo/gateway/pages/DeviceInfoPage.tsx b/demo/gateway/pages/DeviceInfoPage.tsx new file mode 100644 index 000000000..ef509319a --- /dev/null +++ b/demo/gateway/pages/DeviceInfoPage.tsx @@ -0,0 +1,99 @@ +import React, { useMemo } from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; + +const { width, height } = Dimensions.window; + +export function DeviceInfoPage() { + const t = useT(); + const navigate = useNavigate(); + + const infoItems = useMemo( + () => [ + { label: "Device Name", value: "AX100M" }, + { label: "Firmware Version", value: "v1.2.3" }, + { label: "MAC Address", value: "00:11:22:33:44:55" }, + { label: "IP Address", value: "192.168.1.100" }, + { label: "Serial Number", value: "SN123456789" }, + ], + [] + ); + + return ( + navigate(-1)}> +
+ + + + {infoItems.map((item, index) => ( + + {item.label} + {item.value} + + ))} + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, + infoItem: { + width: "100%", + height: 60, + "border-radius": 10, + "background-color": "0x2a2a2a", + margin: "0 0 8px 0", + padding: "0 16px", + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "space-between", + "scroll-on-focus": 1, + }, + label: { + "text-color": "0xb0b0b0", + "font-size": 14, + }, + value: { + "text-color": "white", + "font-size": 14, + }, + focused: { + "background-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/pages/DeviceStatusPage.tsx b/demo/gateway/pages/DeviceStatusPage.tsx new file mode 100644 index 000000000..949197acb --- /dev/null +++ b/demo/gateway/pages/DeviceStatusPage.tsx @@ -0,0 +1,99 @@ +import React, { useMemo } from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; + +const { width, height } = Dimensions.window; + +export function DeviceStatusPage() { + const t = useT(); + const navigate = useNavigate(); + + const statusItems = useMemo( + () => [ + { label: "CPU Usage", value: "45%" }, + { label: "Memory Usage", value: "62%" }, + { label: "Temperature", value: "45°C" }, + { label: "Uptime", value: "15 days" }, + { label: "Network Status", value: "Connected" }, + ], + [] + ); + + return ( + navigate(-1)}> +
+ + + + {statusItems.map((item, index) => ( + + {item.label} + {item.value} + + ))} + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, + statusItem: { + width: "100%", + height: 60, + "border-radius": 10, + "background-color": "0x2a2a2a", + margin: "0 0 8px 0", + padding: "0 16px", + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "space-between", + "scroll-on-focus": 1, + }, + label: { + "text-color": "0xb0b0b0", + "font-size": 14, + }, + value: { + "text-color": "white", + "font-size": 14, + }, + focused: { + "background-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/pages/ExportLogsPage.tsx b/demo/gateway/pages/ExportLogsPage.tsx new file mode 100644 index 000000000..a5aacc268 --- /dev/null +++ b/demo/gateway/pages/ExportLogsPage.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; + +const { width, height } = Dimensions.window; + +export function ExportLogsPage() { + const t = useT(); + const navigate = useNavigate(); + + return ( + navigate(-1)}> +
+ + + + + {t("exportLogs.title")} + + + Exporting logs to Micro SD card... + + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + "justify-content": "center", + "align-items": "center", + }, + messageBox: { + width: width - 48, + padding: 24, + "background-color": "0x101010", + "border-radius": 12, + display: "flex", + "flex-direction": "column", + "align-items": "center", + }, + messageText: { + "text-color": "white", + "font-size": 18, + "margin-bottom": 12, + }, + hintText: { + "text-color": "0xb0b0b0", + "font-size": 14, + }, +}; diff --git a/demo/gateway/pages/HomePage.tsx b/demo/gateway/pages/HomePage.tsx new file mode 100644 index 000000000..9dc38a38a --- /dev/null +++ b/demo/gateway/pages/HomePage.tsx @@ -0,0 +1,127 @@ +import React from "react"; +import { Button, Dimensions, Text, useT, View } from "lvgljs-ui"; +import { useNavigate } from "react-router"; + +const { width, height } = Dimensions.window; + +export function HomePage() { + const t = useT(); + const navigate = useNavigate(); + const btnW = Math.floor((width - 24 * 2 - 12) / 2); + const btnH = 120; + + return ( + + + {t("home.title")} + + + + + + + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + header: { + width, + height: 80, + padding: "24px 24px 0 24px", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + title: { + "text-color": "white", + "font-size": 24, + }, + grid: { + width, + height: height - 80, + padding: "24px", + display: "flex", + "flex-direction": "row", + "flex-wrap": "wrap", + "justify-content": "space-between", + "align-content": "flex-start", + }, + button: { + "background-color": "0x1d1d1d", + "border-radius": 16, + margin: "0 0 12px 0", + display: "flex", + "align-items": "center", + "justify-content": "center", + }, + buttonContent: { + display: "flex", + "flex-direction": "column", + "align-items": "center", + "justify-content": "center", + gap: 8, + }, + icon: { + "font-size": 32, + }, + buttonText: { + "text-color": "white", + "font-size": 16, + }, + focused: { + "background-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/pages/LanguageSettingsPage.tsx b/demo/gateway/pages/LanguageSettingsPage.tsx new file mode 100644 index 000000000..32a9f4850 --- /dev/null +++ b/demo/gateway/pages/LanguageSettingsPage.tsx @@ -0,0 +1,104 @@ +import React, { useState } from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; + +const { width, height } = Dimensions.window; + +export function LanguageSettingsPage() { + const t = useT(); + const navigate = useNavigate(); + const [selectedLang, setSelectedLang] = useState("en"); + + const languages = [ + { id: "zh", label: t("language.zh") }, + { id: "en", label: t("language.en") }, + { id: "ja", label: t("language.ja") }, + ]; + + return ( + navigate(-1)}> +
+ + + + {languages.map((lang, index) => ( + setSelectedLang(lang.id)} + > + {lang.label} + {selectedLang === lang.id && ( + + )} + + ))} + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, + langItem: { + width: "100%", + height: 60, + "border-radius": 10, + "background-color": "0x2a2a2a", + margin: "0 0 8px 0", + padding: "0 16px", + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "space-between", + "scroll-on-focus": 1, + }, + langItemSelected: { + "background-color": "0x4267FF", + }, + langText: { + "text-color": "white", + "font-size": 16, + }, + checkmark: { + "text-color": "white", + "font-size": 18, + }, + focused: { + "background-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx new file mode 100644 index 000000000..8f452c1f7 --- /dev/null +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -0,0 +1,99 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { useNavigate, useParams } from "react-router"; +import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; + +const { width, height } = Dimensions.window; + +export function LogDetailPage() { + const t = useT(); + const navigate = useNavigate(); + const params = useParams<{ id: string }>(); + const [logId, setLogId] = useState("unknown"); + + // 使用 useEffect 监听路由参数变化 + useEffect(() => { + if (params.id) { + setLogId(params.id); + } + }, [params.id]); + + // 模拟日志详情数据 + const logDetails = useMemo(() => { + return Array.from({ length: 20 }).map((_, i) => ({ + id: i + 1, + content: `Log entry ${i + 1} for ${logId}`, + })); + }, [logId]); + + return ( + navigate(-1)}> +
+ + + + {logDetails.map((log, index) => ( + + {log.content} + + ))} + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, + logItem: { + width: "100%", + "min-height": 60, + "border-radius": 10, + "background-color": "0x2a2a2a", + margin: "0 0 8px 0", + padding: "12px 16px", + display: "flex", + "align-items": "flex-start", + "justify-content": "flex-start", + "scroll-on-focus": 1, + }, + logText: { + "text-color": "white", + "font-size": 14, + }, + focused: { + "background-color": "0x4267FF", + }, +}; diff --git a/demo/gateway/pages/LogListPage.tsx b/demo/gateway/pages/LogListPage.tsx new file mode 100644 index 000000000..9d9832d03 --- /dev/null +++ b/demo/gateway/pages/LogListPage.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; +import { ListItem } from "../components/ListItem"; + +const { width, height } = Dimensions.window; + +export function LogListPage() { + const t = useT(); + const navigate = useNavigate(); + + const logItems = [ + { id: "alerts", title: t("logs.alerts"), badge: "999+", badgeColor: "0xFF0000" }, + { id: "notification", title: t("logs.notification"), badge: "5", badgeColor: "0x4267FF" }, + ]; + + return ( + navigate(-1)}> +
+ + + + {logItems.map((item, index) => ( + navigate(`/logs/${item.id}`)} + /> + ))} + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, +}; diff --git a/demo/gateway/pages/SettingsPage.tsx b/demo/gateway/pages/SettingsPage.tsx new file mode 100644 index 000000000..6af654e98 --- /dev/null +++ b/demo/gateway/pages/SettingsPage.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import { useNavigate } from "react-router"; +import { Dimensions, useT, View } from "lvgljs-ui"; +import { Header } from "../components/Header"; +import { ListItem } from "../components/ListItem"; + +const { width, height } = Dimensions.window; + +export function SettingsPage() { + const t = useT(); + const navigate = useNavigate(); + + const settingsItems = [ + { id: "language", title: t("settings.language"), path: "/settings/language" }, + { id: "exportLogs", title: t("settings.exportLogs"), path: "/settings/export-logs" }, + { id: "clearLogs", title: t("settings.clearLogs"), path: "/settings/clear-logs" }, + { id: "countdown", title: t("settings.countdown"), path: "/settings/countdown" }, + ]; + + return ( + navigate(-1)}> +
+ + + + {settingsItems.map((item, index) => ( + navigate(item.path)} + /> + ))} + + + + ); +} + +const style: Record = { + pageRoot: { + width, + height, + padding: 0, + "background-color": "black", + display: "flex", + "flex-direction": "column", + overflow: "hidden", + }, + content: { + width, + height: height - 52, + padding: 12, + display: "flex", + "flex-direction": "column", + }, + scrollBox: { + width: width - 24, + height: height - 52 - 24, + padding: 8, + "background-color": "0x101010", + "border-radius": 10, + overflow: 0, + "overflow-scrolling": 1, + display: "flex", + "flex-direction": "column", + }, +}; diff --git a/tsconfig.json b/tsconfig.json index 12aeaeb09..3019e2710 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,25 @@ { "compilerOptions": { "module": "NodeNext", + "jsx": "react", + "target": "ES2020", + "lib": ["ES2020"], + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "skipLibCheck": true, + "strict": false, "typeRoots": [ "node_modules/@txikijs/types", "node_modules/@types" - ] + ], + "paths": { + "lvgljs-ui": ["./src/render/react"] + } }, - "include": ["src/**/*"], - "exclude": ["**/*.spec.ts"] + "include": [ + "src/**/*", + "demo/**/*", + "test/**/*" + ], + "exclude": ["**/*.spec.ts", "node_modules", "build", "deps"] } \ No newline at end of file From f5e93d59755b2a154e61353a3995b17e3f3d3f93 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 26 Jan 2026 19:09:24 +0800 Subject: [PATCH 45/62] feat: enhance gateway demo with new icons and header updates - Updated language handling in index.tsx to correctly load JSON files based on locale. - Added new navigation icons for device info, device status, event log, and settings. - Modified Header component to accept a backIcon prop for improved navigation. - Adjusted styles for focused states and various components to ensure consistent UI experience. - Updated multiple pages to utilize new icons and enhance header functionality. --- .../{home4.png => nav_icon/device_info.png} | Bin .../{home2.png => nav_icon/device_status.png} | Bin .../{home3.png => nav_icon/event_log.png} | Bin .../{home1.png => nav_icon/settings.png} | Bin demo/gateway/components/ConfirmDialog.tsx | 2 +- demo/gateway/components/Header.tsx | 10 +- demo/gateway/components/ListItem.tsx | 2 +- demo/gateway/index.tsx | 4 +- demo/gateway/pages/ClearLogsPage.tsx | 2 +- demo/gateway/pages/CountdownSettingsPage.tsx | 2 +- demo/gateway/pages/DeviceInfoPage.tsx | 4 +- demo/gateway/pages/DeviceStatusPage.tsx | 22 ++-- demo/gateway/pages/HomePage.tsx | 100 ++++++++---------- demo/gateway/pages/LanguageSettingsPage.tsx | 6 +- demo/gateway/pages/LogDetailPage.tsx | 2 +- demo/gateway/pages/LogListPage.tsx | 2 +- demo/gateway/pages/SettingsPage.tsx | 2 +- src/render/react/package.json | 1 + 18 files changed, 78 insertions(+), 83 deletions(-) rename demo/gateway/assets/{home4.png => nav_icon/device_info.png} (100%) rename demo/gateway/assets/{home2.png => nav_icon/device_status.png} (100%) rename demo/gateway/assets/{home3.png => nav_icon/event_log.png} (100%) rename demo/gateway/assets/{home1.png => nav_icon/settings.png} (100%) diff --git a/demo/gateway/assets/home4.png b/demo/gateway/assets/nav_icon/device_info.png similarity index 100% rename from demo/gateway/assets/home4.png rename to demo/gateway/assets/nav_icon/device_info.png diff --git a/demo/gateway/assets/home2.png b/demo/gateway/assets/nav_icon/device_status.png similarity index 100% rename from demo/gateway/assets/home2.png rename to demo/gateway/assets/nav_icon/device_status.png diff --git a/demo/gateway/assets/home3.png b/demo/gateway/assets/nav_icon/event_log.png similarity index 100% rename from demo/gateway/assets/home3.png rename to demo/gateway/assets/nav_icon/event_log.png diff --git a/demo/gateway/assets/home1.png b/demo/gateway/assets/nav_icon/settings.png similarity index 100% rename from demo/gateway/assets/home1.png rename to demo/gateway/assets/nav_icon/settings.png diff --git a/demo/gateway/components/ConfirmDialog.tsx b/demo/gateway/components/ConfirmDialog.tsx index 54eace51f..250a4f92b 100644 --- a/demo/gateway/components/ConfirmDialog.tsx +++ b/demo/gateway/components/ConfirmDialog.tsx @@ -94,6 +94,6 @@ const style: Record = { }, buttonFocused: { "border-width": 3, - "border-color": "0x4267FF", + "border-color": "#4660FF", }, }; diff --git a/demo/gateway/components/Header.tsx b/demo/gateway/components/Header.tsx index 7f8a73a18..c298e0a91 100644 --- a/demo/gateway/components/Header.tsx +++ b/demo/gateway/components/Header.tsx @@ -1,13 +1,15 @@ import React from "react"; -import { Text, View, useT } from "lvgljs-ui"; +import { Image, Text, View, useT } from "lvgljs-ui"; interface HeaderProps { title: string; + backIcon?: string; } -export function Header({ title }: HeaderProps) { +export function Header({ title, backIcon }: HeaderProps) { return ( + {backIcon && } {title} ); @@ -23,6 +25,10 @@ const style: Record = { "background-color": "0x202020", padding: "0 16px", }, + headerIcon: { + width: 'auto', + height: 'auto', + }, headerTitle: { "text-color": "white", "font-size": 16, diff --git a/demo/gateway/components/ListItem.tsx b/demo/gateway/components/ListItem.tsx index 248884131..0ea3afa44 100644 --- a/demo/gateway/components/ListItem.tsx +++ b/demo/gateway/components/ListItem.tsx @@ -85,6 +85,6 @@ const style: Record = { margin: "0 0 0 12px", }, focused: { - "background-color": "0x4267FF", + "background-color": "#4660FF", }, }; diff --git a/demo/gateway/index.tsx b/demo/gateway/index.tsx index 10815f325..91480d2cc 100644 --- a/demo/gateway/index.tsx +++ b/demo/gateway/index.tsx @@ -14,8 +14,8 @@ import { ClearLogsPage } from "./pages/ClearLogsPage"; declare const require: any; const messages = (locale: string) => { - if (locale === "zh") return require("./i18n/zh.json"); - return require("./i18n/en.json"); + if (locale === "en") return require("./i18n/en.json"); + return require("./i18n/zh.json"); }; function App() { diff --git a/demo/gateway/pages/ClearLogsPage.tsx b/demo/gateway/pages/ClearLogsPage.tsx index bb0ffee0f..e874dca89 100644 --- a/demo/gateway/pages/ClearLogsPage.tsx +++ b/demo/gateway/pages/ClearLogsPage.tsx @@ -24,7 +24,7 @@ export function ClearLogsPage() { return ( -
+
{showDialog && ( = { }, arcIndicator: { "arc-width": 18, - "arc-color": "0x4267FF", + "arc-color": "#4660FF", "arc-rounded": true, }, arcKnobHidden: { diff --git a/demo/gateway/pages/DeviceInfoPage.tsx b/demo/gateway/pages/DeviceInfoPage.tsx index ef509319a..c5719a566 100644 --- a/demo/gateway/pages/DeviceInfoPage.tsx +++ b/demo/gateway/pages/DeviceInfoPage.tsx @@ -22,7 +22,7 @@ export function DeviceInfoPage() { return ( navigate(-1)}> -
+
@@ -94,6 +94,6 @@ const style: Record = { "font-size": 14, }, focused: { - "background-color": "0x4267FF", + "background-color": "#4660FF", }, }; diff --git a/demo/gateway/pages/DeviceStatusPage.tsx b/demo/gateway/pages/DeviceStatusPage.tsx index 949197acb..d48c3a876 100644 --- a/demo/gateway/pages/DeviceStatusPage.tsx +++ b/demo/gateway/pages/DeviceStatusPage.tsx @@ -22,7 +22,7 @@ export function DeviceStatusPage() { return ( navigate(-1)}> -
+
@@ -34,8 +34,8 @@ export function DeviceStatusPage() { onFocusedStyle={style.focused} style={style.statusItem} > - {item.label} {item.value} + {item.label} ))} @@ -74,26 +74,28 @@ const style: Record = { }, statusItem: { width: "100%", - height: 60, + height: 160, "border-radius": 10, "background-color": "0x2a2a2a", margin: "0 0 8px 0", - padding: "0 16px", + padding: "16px", display: "flex", - "flex-direction": "row", - "align-items": "center", - "justify-content": "space-between", + "flex-direction": "column", + "align-items": "flex-start", + "justify-content": "flex-start", "scroll-on-focus": 1, }, label: { - "text-color": "0xb0b0b0", + "text-color": "white", "font-size": 14, + "margin-bottom": 8, }, value: { "text-color": "white", - "font-size": 14, + "font-size": 24, + "font-weight": "bold", }, focused: { - "background-color": "0x4267FF", + "background-color": "#4660FF", }, }; diff --git a/demo/gateway/pages/HomePage.tsx b/demo/gateway/pages/HomePage.tsx index 9dc38a38a..889fd66c4 100644 --- a/demo/gateway/pages/HomePage.tsx +++ b/demo/gateway/pages/HomePage.tsx @@ -1,67 +1,48 @@ import React from "react"; -import { Button, Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Button, Dimensions, Image, Text, useT, View } from "lvgljs-ui"; import { useNavigate } from "react-router"; const { width, height } = Dimensions.window; +const colWidth = (width - 24 * 2 - 12) / 2; +const rowHeight = (height - 80 - 24 * 2 - 12) / 2; + export function HomePage() { const t = useT(); const navigate = useNavigate(); - const btnW = Math.floor((width - 24 * 2 - 12) / 2); - const btnH = 120; + + const buttons = [ + { path: "/logs", icon: "./demo/gateway/assets/nav_icon/event_log.png", text: t("header.eventLog"), col: 0, row: 0 }, + { path: "/device-info", icon: "./demo/gateway/assets/nav_icon/device_info.png", text: t("header.deviceInfo"), col: 1, row: 0 }, + { path: "/device-status", icon: "./demo/gateway/assets/nav_icon/device_status.png", text: t("header.deviceStatus"), col: 0, row: 1 }, + { path: "/settings", icon: "./demo/gateway/assets/nav_icon/settings.png", text: t("header.settings"), col: 1, row: 1 }, + ]; return ( - - {t("home.title")} - - - - - + ))} ); @@ -93,19 +74,20 @@ const style: Record = { width, height: height - 80, padding: "24px", - display: "flex", - "flex-direction": "row", - "flex-wrap": "wrap", - "justify-content": "space-between", - "align-content": "flex-start", + display: "grid", + "grid-template-columns": `${colWidth} ${colWidth}`, + "grid-template-rows": `${rowHeight} ${rowHeight}`, + gap: 12, }, button: { "background-color": "0x1d1d1d", "border-radius": 16, - margin: "0 0 12px 0", display: "flex", "align-items": "center", "justify-content": "center", + "grid-child": true, + "align-self": "stretch", + "justify-self": "stretch" }, buttonContent: { display: "flex", @@ -122,6 +104,10 @@ const style: Record = { "font-size": 16, }, focused: { - "background-color": "0x4267FF", + "background-color": "#4660FF", + }, + image: { + width: 'auto', + height: 'auto', }, }; diff --git a/demo/gateway/pages/LanguageSettingsPage.tsx b/demo/gateway/pages/LanguageSettingsPage.tsx index 32a9f4850..6d663b709 100644 --- a/demo/gateway/pages/LanguageSettingsPage.tsx +++ b/demo/gateway/pages/LanguageSettingsPage.tsx @@ -18,7 +18,7 @@ export function LanguageSettingsPage() { return ( navigate(-1)}> -
+
@@ -88,7 +88,7 @@ const style: Record = { "scroll-on-focus": 1, }, langItemSelected: { - "background-color": "0x4267FF", + "background-color": "#4660FF", }, langText: { "text-color": "white", @@ -99,6 +99,6 @@ const style: Record = { "font-size": 18, }, focused: { - "background-color": "0x4267FF", + "background-color": "#4660FF", }, }; diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx index 8f452c1f7..e674d7a16 100644 --- a/demo/gateway/pages/LogDetailPage.tsx +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -94,6 +94,6 @@ const style: Record = { "font-size": 14, }, focused: { - "background-color": "0x4267FF", + "background-color": "#4660FF", }, }; diff --git a/demo/gateway/pages/LogListPage.tsx b/demo/gateway/pages/LogListPage.tsx index 9d9832d03..be85c3c20 100644 --- a/demo/gateway/pages/LogListPage.tsx +++ b/demo/gateway/pages/LogListPage.tsx @@ -17,7 +17,7 @@ export function LogListPage() { return ( navigate(-1)}> -
+
diff --git a/demo/gateway/pages/SettingsPage.tsx b/demo/gateway/pages/SettingsPage.tsx index 6af654e98..04a002258 100644 --- a/demo/gateway/pages/SettingsPage.tsx +++ b/demo/gateway/pages/SettingsPage.tsx @@ -19,7 +19,7 @@ export function SettingsPage() { return ( navigate(-1)}> -
+
diff --git a/src/render/react/package.json b/src/render/react/package.json index bfc2c5cfb..2c067eb36 100644 --- a/src/render/react/package.json +++ b/src/render/react/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "description": "lvgljs react frame", "main": "index.js", + "types": "index.ts", "scripts": { "build": "esbuild index.ts --outfile=index.js", "test": "echo \"Error: no test specified\" && exit 1" From cbcbc355bc563d57976b3a63d269e65746c866d9 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 26 Jan 2026 19:27:19 +0800 Subject: [PATCH 46/62] refactor: streamline layout in DeviceStatusPage component --- demo/gateway/pages/DeviceStatusPage.tsx | 40 ++++++++++--------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/demo/gateway/pages/DeviceStatusPage.tsx b/demo/gateway/pages/DeviceStatusPage.tsx index d48c3a876..88aa6465c 100644 --- a/demo/gateway/pages/DeviceStatusPage.tsx +++ b/demo/gateway/pages/DeviceStatusPage.tsx @@ -24,21 +24,19 @@ export function DeviceStatusPage() { navigate(-1)}>
- - - {statusItems.map((item, index) => ( - - {item.value} - {item.label} - - ))} - + + {statusItems.map((item, index) => ( + + {item.value} + {item.label} + + ))} ); @@ -54,19 +52,11 @@ const style: Record = { "flex-direction": "column", overflow: "hidden", }, - content: { - width, - height: height - 52, - padding: 12, - display: "flex", - "flex-direction": "column", - }, scrollBox: { - width: width - 24, - height: height - 52 - 24, + width: width, + height: height - 24, padding: 8, "background-color": "0x101010", - "border-radius": 10, overflow: 0, "overflow-scrolling": 1, display: "flex", From c0af941fcb02e184823d0a3eeff24e949dd737ec Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 26 Jan 2026 20:01:37 +0800 Subject: [PATCH 47/62] feat: enhance device information display in gateway demo --- demo/gateway/pages/DeviceInfoPage.tsx | 136 +++++++++++++++++--------- 1 file changed, 92 insertions(+), 44 deletions(-) diff --git a/demo/gateway/pages/DeviceInfoPage.tsx b/demo/gateway/pages/DeviceInfoPage.tsx index c5719a566..501762b3a 100644 --- a/demo/gateway/pages/DeviceInfoPage.tsx +++ b/demo/gateway/pages/DeviceInfoPage.tsx @@ -5,40 +5,75 @@ import { Header } from "../components/Header"; const { width, height } = Dimensions.window; +interface DeviceInfoSectionProps { + title: string; + content: Array; + autoFocus?: boolean; +} + +function DeviceInfoSection({ title, content, autoFocus = false }: DeviceInfoSectionProps) { + return ( + + {title} + + {content.map((item) => ( + {item} + ))} + + + ); +} + export function DeviceInfoPage() { const t = useT(); const navigate = useNavigate(); - const infoItems = useMemo( - () => [ - { label: "Device Name", value: "AX100M" }, - { label: "Firmware Version", value: "v1.2.3" }, - { label: "MAC Address", value: "00:11:22:33:44:55" }, - { label: "IP Address", value: "192.168.1.100" }, - { label: "Serial Number", value: "SN123456789" }, - ], - [] - ); - + const eth1Items = useMemo( + () => [{ + title: "ETH1", + content: [ + "IP:192.168.1.100", + "MAC:00:11:22:33:44:55", + "Netmask:255.255.255.0", + "Gateway:192.168.1.1", + ] + }, + { + title: "ETH2", + content: [ + "IP:192.168.2.100", + "MAC:00:11:22:33:44:56", + "Netmask:255.255.255.0", + "Gateway:192.168.2.1", + ] + }, + { + title: "Version", + content: [ + "Firmware Version:1.0.0", + "Studio Version:1.0.0", + ] + } + ], []); + return ( navigate(-1)}>
- - - {infoItems.map((item, index) => ( - - {item.label} - {item.value} - - ))} - + + {eth1Items.map((item, index) => ( + + ))} ); @@ -54,46 +89,59 @@ const style: Record = { "flex-direction": "column", overflow: "hidden", }, - content: { - width, - height: height - 52, - padding: 12, - display: "flex", - "flex-direction": "column", - }, scrollBox: { - width: width - 24, - height: height - 52 - 24, - padding: 8, + width: width, + height: height - 80, + padding: "16px", "background-color": "0x101010", - "border-radius": 10, overflow: 0, "overflow-scrolling": 1, display: "flex", "flex-direction": "column", }, - infoItem: { + ethSection: { + height: 'auto', width: "100%", - height: 60, - "border-radius": 10, "background-color": "0x2a2a2a", + display: "flex", + "flex-direction": "column", + }, + ethTitle: { + "text-color": "white", + "font-size": 24, + "font-weight": "bold", + }, + ethSectionFocused: { + "background-color": "#4660FF", + }, + ethContent: { + width: "100%", + height: 'auto', + "background-opacity": 0, + display: "flex", + "flex-direction": "column", + }, + infoItem: { + width: "100%", + height: 50, + "border-radius": 8, + "background-color": "0x1a1a1a", margin: "0 0 8px 0", padding: "0 16px", display: "flex", "flex-direction": "row", "align-items": "center", "justify-content": "space-between", - "scroll-on-focus": 1, }, label: { "text-color": "0xb0b0b0", "font-size": 14, + "flex": 1, }, value: { "text-color": "white", "font-size": 14, - }, - focused: { - "background-color": "#4660FF", + "font-weight": "normal", + "text-align": "right", }, }; From 49d0f837a3a64e93a9a1679e2ff4d8eaa034e0cc Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 26 Jan 2026 20:49:16 +0800 Subject: [PATCH 48/62] feat: add Japanese language support and enhance localization in gateway demo - Updated index.tsx to load Japanese language JSON file based on locale. - Modified ListItem component to use translation function for titles. - Enhanced various pages to support localization and improved UI consistency. - Updated language settings to reflect direct language labels instead of translation keys. --- demo/gateway/components/ListItem.tsx | 10 ++-- demo/gateway/i18n/en.json | 5 +- demo/gateway/i18n/ja.json | 47 ++++++++++++++++++ demo/gateway/i18n/zh.json | 51 +++++++++----------- demo/gateway/index.tsx | 1 + demo/gateway/pages/CountdownSettingsPage.tsx | 3 +- demo/gateway/pages/ExportLogsPage.tsx | 2 +- demo/gateway/pages/LanguageSettingsPage.tsx | 21 ++++---- demo/gateway/pages/SettingsPage.tsx | 8 +-- 9 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 demo/gateway/i18n/ja.json diff --git a/demo/gateway/components/ListItem.tsx b/demo/gateway/components/ListItem.tsx index 0ea3afa44..7bf7d3393 100644 --- a/demo/gateway/components/ListItem.tsx +++ b/demo/gateway/components/ListItem.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Text, View } from "lvgljs-ui"; +import { Image, Text, useT, View } from "lvgljs-ui"; interface ListItemProps { title: string; @@ -18,6 +18,7 @@ export function ListItem({ onClick, autoFocus = false, }: ListItemProps) { + const t = useT(); return ( - {title} + {t(title)} {badge && ( {badge} @@ -35,7 +36,7 @@ export function ListItem({ )} {showArrow && ( - + )} ); @@ -57,6 +58,9 @@ const style: Record = { }, content: { display: "flex", + width: 'auto', + height: 'auto', + "background-opacity": 0, "flex-direction": "row", "align-items": "center", "flex": 1, diff --git a/demo/gateway/i18n/en.json b/demo/gateway/i18n/en.json index 5b7535799..2ed701169 100644 --- a/demo/gateway/i18n/en.json +++ b/demo/gateway/i18n/en.json @@ -28,10 +28,7 @@ "countdown": "Countdown" }, "language": { - "title": "Language", - "zh": "简体中文", - "en": "English", - "ja": "日本語" + "title": "Language" }, "countdown": { "title": "Countdown", diff --git a/demo/gateway/i18n/ja.json b/demo/gateway/i18n/ja.json new file mode 100644 index 000000000..ff9660413 --- /dev/null +++ b/demo/gateway/i18n/ja.json @@ -0,0 +1,47 @@ +{ + "home": { + "title": "Smart Gateway [ja]" + }, + "header": { + "eventLog": "Event Log [ja]", + "deviceInfo": "Device Info [ja]", + "deviceStatus": "Device Status [ja]", + "settings": "Setting [ja]" + }, + "logs": { + "title": "Event Log [ja]", + "alerts": "Alerts [ja]", + "notification": "Notification [ja]", + "detail": "Log Detail [ja]" + }, + "deviceInfo": { + "title": "Device Info [ja]" + }, + "deviceStatus": { + "title": "Device Status [ja]" + }, + "settings": { + "title": "Setting [ja]", + "language": "Language [ja]", + "exportLogs": "Export Logs To Micro SD [ja]", + "clearLogs": "Clear Logs [ja]", + "countdown": "Countdown [ja]" + }, + "language": { + "title": "Language [ja]" + }, + "countdown": { + "title": "Countdown [ja]", + "time": "{remain}s [ja]" + }, + "exportLogs": { + "title": "Export Logs To Micro SD [ja]" + }, + "clearLogs": { + "title": "Clear Logs [ja]", + "confirm": "Confirm To Clear The Logs? [ja]", + "cancel": "Cancel [ja]", + "confirmBtn": "Confirm [ja]" + } + } + \ No newline at end of file diff --git a/demo/gateway/i18n/zh.json b/demo/gateway/i18n/zh.json index d030fd918..38599ffba 100644 --- a/demo/gateway/i18n/zh.json +++ b/demo/gateway/i18n/zh.json @@ -1,49 +1,46 @@ { "home": { - "title": "智慧网关" + "title": "Smart Gateway [zh]" }, "header": { - "eventLog": "Event Log", - "deviceInfo": "Device Info", - "deviceStatus": "Device Status", - "settings": "Setting" + "eventLog": "Event Log [zh]", + "deviceInfo": "Device Info [zh]", + "deviceStatus": "Device Status [zh]", + "settings": "Setting [zh]" }, "logs": { - "title": "Event Log", - "alerts": "Alerts", - "notification": "Notification", - "detail": "日志详情" + "title": "Event Log [zh]", + "alerts": "Alerts [zh]", + "notification": "Notification [zh]", + "detail": "Log Detail [zh]" }, "deviceInfo": { - "title": "Device Info" + "title": "Device Info [zh]" }, "deviceStatus": { - "title": "Device Status" + "title": "Device Status [zh]" }, "settings": { - "title": "Setting", - "language": "Language", - "exportLogs": "Export Logs To Micro SD", - "clearLogs": "Clear Logs", - "countdown": "Countdown" + "title": "Setting [zh]", + "language": "Language [zh]", + "exportLogs": "Export Logs To Micro SD [zh]", + "clearLogs": "Clear Logs [zh]", + "countdown": "Countdown [zh]" }, "language": { - "title": "Language", - "zh": "简体中文", - "en": "English", - "ja": "日本語" + "title": "Language [zh]" }, "countdown": { - "title": "Countdown", - "time": "剩余{remain}秒" + "title": "Countdown [zh]", + "time": "{remain}s [zh]" }, "exportLogs": { - "title": "Export Logs To Micro SD" + "title": "Export Logs To Micro SD [zh]" }, "clearLogs": { - "title": "Clear Logs", - "confirm": "Confirm To Clear The Logs?", - "cancel": "取消", - "confirmBtn": "确认" + "title": "Clear Logs [zh]", + "confirm": "Confirm To Clear The Logs? [zh]", + "cancel": "Cancel [zh]", + "confirmBtn": "Confirm [zh]" } } diff --git a/demo/gateway/index.tsx b/demo/gateway/index.tsx index 91480d2cc..62686a6f0 100644 --- a/demo/gateway/index.tsx +++ b/demo/gateway/index.tsx @@ -15,6 +15,7 @@ import { ClearLogsPage } from "./pages/ClearLogsPage"; declare const require: any; const messages = (locale: string) => { if (locale === "en") return require("./i18n/en.json"); + if (locale === "ja") return require("./i18n/ja.json"); return require("./i18n/zh.json"); }; diff --git a/demo/gateway/pages/CountdownSettingsPage.tsx b/demo/gateway/pages/CountdownSettingsPage.tsx index 2cb50711a..bd38f111d 100644 --- a/demo/gateway/pages/CountdownSettingsPage.tsx +++ b/demo/gateway/pages/CountdownSettingsPage.tsx @@ -26,7 +26,7 @@ export function CountdownSettingsPage() { navigate(-1)}>
- + = { width, height: height - 52, display: "flex", + "background-opacity": 0, "flex-direction": "column", "justify-content": "center", "align-items": "center", diff --git a/demo/gateway/pages/ExportLogsPage.tsx b/demo/gateway/pages/ExportLogsPage.tsx index a5aacc268..2cafbda04 100644 --- a/demo/gateway/pages/ExportLogsPage.tsx +++ b/demo/gateway/pages/ExportLogsPage.tsx @@ -13,7 +13,7 @@ export function ExportLogsPage() { navigate(-1)}>
- + {t("exportLogs.title")} diff --git a/demo/gateway/pages/LanguageSettingsPage.tsx b/demo/gateway/pages/LanguageSettingsPage.tsx index 6d663b709..ddf605114 100644 --- a/demo/gateway/pages/LanguageSettingsPage.tsx +++ b/demo/gateway/pages/LanguageSettingsPage.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useNavigate } from "react-router"; -import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Dimensions, Image, Text, useI18n, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -8,12 +8,12 @@ const { width, height } = Dimensions.window; export function LanguageSettingsPage() { const t = useT(); const navigate = useNavigate(); - const [selectedLang, setSelectedLang] = useState("en"); + const { locale, setLocale } = useI18n(); const languages = [ - { id: "zh", label: t("language.zh") }, - { id: "en", label: t("language.en") }, - { id: "ja", label: t("language.ja") }, + { id: "zh", label: "简体中文" }, + { id: "en", label: "English" }, + { id: "ja", label: "日本語" }, ]; return ( @@ -28,15 +28,12 @@ export function LanguageSettingsPage() { autoFocus={index === 0} addToFocusGroup onFocusedStyle={style.focused} - style={[ - style.langItem, - selectedLang === lang.id && style.langItemSelected, - ]} - onClick={() => setSelectedLang(lang.id)} + style={style.langItem} + onClick={() => setLocale(lang.id)} > {lang.label} - {selectedLang === lang.id && ( - + {locale === lang.id && ( + )} ))} diff --git a/demo/gateway/pages/SettingsPage.tsx b/demo/gateway/pages/SettingsPage.tsx index 04a002258..961c14ebc 100644 --- a/demo/gateway/pages/SettingsPage.tsx +++ b/demo/gateway/pages/SettingsPage.tsx @@ -11,10 +11,10 @@ export function SettingsPage() { const navigate = useNavigate(); const settingsItems = [ - { id: "language", title: t("settings.language"), path: "/settings/language" }, - { id: "exportLogs", title: t("settings.exportLogs"), path: "/settings/export-logs" }, - { id: "clearLogs", title: t("settings.clearLogs"), path: "/settings/clear-logs" }, - { id: "countdown", title: t("settings.countdown"), path: "/settings/countdown" }, + { id: "language", title: "settings.language", path: "/settings/language" }, + { id: "exportLogs", title: "settings.exportLogs", path: "/settings/export-logs" }, + { id: "clearLogs", title: "settings.clearLogs", path: "/settings/clear-logs" }, + { id: "countdown", title: "settings.countdown", path: "/settings/countdown" }, ]; return ( From 5f7d864eb5a5006c87d6b6f0a8d6de1b38e809b5 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 27 Jan 2026 11:35:59 +0800 Subject: [PATCH 49/62] fix: correct countdown angle calculation and update styles in CountdownSettingsPage --- demo/gateway/pages/CountdownSettingsPage.tsx | 12 +++++------ src/render/react/components/common/index.ts | 21 ++------------------ 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/demo/gateway/pages/CountdownSettingsPage.tsx b/demo/gateway/pages/CountdownSettingsPage.tsx index bd38f111d..35ca35e39 100644 --- a/demo/gateway/pages/CountdownSettingsPage.tsx +++ b/demo/gateway/pages/CountdownSettingsPage.tsx @@ -20,7 +20,7 @@ export function CountdownSettingsPage() { }, []); const elapsed = total - remain; - const angle = Math.floor((elapsed / total) * 360); + const angle = Math.floor((1 - elapsed / total) * 360); return ( navigate(-1)}> @@ -34,9 +34,9 @@ export function CountdownSettingsPage() { range={[0, total]} value={elapsed} rotation={270} - backgroundStartAngle={0} - backgroundEndAngle={360} - startAngle={0} + backgroundStartAngle={360} + backgroundEndAngle={0} + startAngle={360} endAngle={angle} mode="normal" changeRate={360} @@ -73,13 +73,13 @@ const style: Record = { width: 220, height: 220, "arc-width": 18, - "arc-color": "red", + "arc-color": "black", "arc-rounded": true, "background-color": "black", }, arcIndicator: { "arc-width": 18, - "arc-color": "#4660FF", + "arc-color": "white", "arc-rounded": true, }, arcKnobHidden: { diff --git a/src/render/react/components/common/index.ts b/src/render/react/components/common/index.ts index ffe2b566b..c8c658226 100644 --- a/src/render/react/components/common/index.ts +++ b/src/render/react/components/common/index.ts @@ -90,25 +90,10 @@ export const commonSetters = { oldStyleSheet: oldProps.style, }); }, - align(comp, { type, pos = [0, 0] }, oldProps) { - if ( - !type || - (type === oldProps.align?.type && - pos?.[0] === oldProps.align?.pos?.[0] && - pos?.[1] === oldProps.align?.pos?.[1]) - ) - return; + align(comp, { type, pos = [0, 0] }) { comp.align(type, pos); }, - alignTo(comp, { type, pos = [0, 0], parent }, oldProps) { - if ( - !type || - (type === oldProps.alignTo?.type && - pos?.[0] === oldProps.alignTo?.pos?.[0] && - pos?.[1] === oldProps.alignTo?.pos?.[1] && - parent?.uid === oldProps.alignTo?.parent?.uid) - ) - return; + alignTo(comp, { type, pos = [0, 0], parent }) { comp.alignTo(type, pos, parent); }, scrollbarStyle(comp, styleSheet, compName, oldProps) { @@ -206,8 +191,6 @@ export function setComponentProps( setter(comp, value, oldProps); } else if (setter.length === 4) { setter(comp, value, compName, oldProps); - } else { - setter(); } } From b30d5ebaa8cd3affea9ef68daf114bf2634c0f71 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 27 Jan 2026 14:55:15 +0800 Subject: [PATCH 50/62] refactor: remove background-opacity property and update color styles across multiple components - Removed "background-opacity" property from ListItem, CountdownSettingsPage, and DeviceInfoPage components for consistency. - Updated "arc-color" in CountdownSettingsPage to a darker shade for improved visibility. - Adjusted "background-color" in HomePage to a semi-transparent white for better UI aesthetics. - Enhanced color handling in color.ts to support 4-digit and 8-digit hex formats, including opacity extraction. --- demo/gateway/components/ListItem.tsx | 1 - demo/gateway/pages/CountdownSettingsPage.tsx | 3 +- demo/gateway/pages/DeviceInfoPage.tsx | 1 - demo/gateway/pages/HomePage.tsx | 3 +- doc/style/color.md | 9 ++++- src/render/native/components/view/view.cpp | 28 +++++++-------- src/render/native/components/view/view.hpp | 2 +- src/render/react/core/style/color.ts | 37 ++++++++++++++++++++ src/render/react/core/style/util.ts | 15 +++++--- 9 files changed, 74 insertions(+), 25 deletions(-) diff --git a/demo/gateway/components/ListItem.tsx b/demo/gateway/components/ListItem.tsx index 7bf7d3393..7afc071c0 100644 --- a/demo/gateway/components/ListItem.tsx +++ b/demo/gateway/components/ListItem.tsx @@ -60,7 +60,6 @@ const style: Record = { display: "flex", width: 'auto', height: 'auto', - "background-opacity": 0, "flex-direction": "row", "align-items": "center", "flex": 1, diff --git a/demo/gateway/pages/CountdownSettingsPage.tsx b/demo/gateway/pages/CountdownSettingsPage.tsx index 35ca35e39..e04ced6b3 100644 --- a/demo/gateway/pages/CountdownSettingsPage.tsx +++ b/demo/gateway/pages/CountdownSettingsPage.tsx @@ -64,7 +64,6 @@ const style: Record = { width, height: height - 52, display: "flex", - "background-opacity": 0, "flex-direction": "column", "justify-content": "center", "align-items": "center", @@ -73,7 +72,7 @@ const style: Record = { width: 220, height: 220, "arc-width": 18, - "arc-color": "black", + "arc-color": "#2E2E2E", "arc-rounded": true, "background-color": "black", }, diff --git a/demo/gateway/pages/DeviceInfoPage.tsx b/demo/gateway/pages/DeviceInfoPage.tsx index 501762b3a..f0da977d2 100644 --- a/demo/gateway/pages/DeviceInfoPage.tsx +++ b/demo/gateway/pages/DeviceInfoPage.tsx @@ -117,7 +117,6 @@ const style: Record = { ethContent: { width: "100%", height: 'auto', - "background-opacity": 0, display: "flex", "flex-direction": "column", }, diff --git a/demo/gateway/pages/HomePage.tsx b/demo/gateway/pages/HomePage.tsx index 889fd66c4..2b667a854 100644 --- a/demo/gateway/pages/HomePage.tsx +++ b/demo/gateway/pages/HomePage.tsx @@ -80,7 +80,7 @@ const style: Record = { gap: 12, }, button: { - "background-color": "0x1d1d1d", + "background-color": "#FFFFFF33", "border-radius": 16, display: "flex", "align-items": "center", @@ -105,6 +105,7 @@ const style: Record = { }, focused: { "background-color": "#4660FF", + "border-radius": 16, }, image: { width: 'auto', diff --git a/doc/style/color.md b/doc/style/color.md index 14e92d724..b0ed94e92 100644 --- a/doc/style/color.md +++ b/doc/style/color.md @@ -18,9 +18,16 @@ const style = { A notation for describing the hexadecimal color syntax of an sRGB color using its primary color components (red, green, blue) written as hexadecimal numbers ### Usage +Supports 3-digit, 4-digit, 6-digit, and 8-digit hexadecimal color formats: +- 3-digit: `#fff` (equivalent to `#ffffff`) +- 4-digit: `#fff3` (equivalent to `#ffffff33`, includes alpha channel) +- 6-digit: `#ff0099` (standard RGB color) +- 8-digit: `#ff009933` (RGB + Alpha channel, automatically sets corresponding opacity property) + ```js const style = { - "background-color": "#ff0099", + "background-color": "#ff0099", // Standard color, will set background-opacity to 255 + "background-color": "#FFFFFF33", // With opacity, automatically sets background-opacity } ``` diff --git a/src/render/native/components/view/view.cpp b/src/render/native/components/view/view.cpp index 52934c5c4..bfef9f5e6 100644 --- a/src/render/native/components/view/view.cpp +++ b/src/render/native/components/view/view.cpp @@ -8,20 +8,20 @@ View::View(std::string uid, lv_obj_t* parent): BasicComponent(uid) { lv_obj_add_flag(this->instance, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_set_user_data(this->instance, this); - // this->initStyle(LV_PART_MAIN); + this->initStyle(LV_PART_MAIN); }; -// void View::initCompStyle (int32_t type) { -// this->ensureStyle(type); -// lv_style_t* style = this->style_map.at(type); +void View::initCompStyle (int32_t type) { + lv_style_t* style = this->style_map.at(type); -// lv_style_set_pad_left(style, 0); -// lv_style_set_pad_right(style, 0); -// lv_style_set_pad_bottom(style, 0); -// lv_style_set_pad_top(style, 0); -// lv_style_set_radius(style, 0); -// lv_style_set_outline_width(style, 0); -// lv_style_set_outline_pad(style, 0); -// lv_style_set_border_width(style, 0); -// lv_style_set_border_side(style, LV_BORDER_SIDE_FULL); -// }; + lv_style_set_pad_left(style, 0); + lv_style_set_pad_right(style, 0); + lv_style_set_pad_bottom(style, 0); + lv_style_set_pad_top(style, 0); + lv_style_set_radius(style, 0); + lv_style_set_outline_width(style, 0); + lv_style_set_outline_pad(style, 0); + lv_style_set_border_width(style, 0); + lv_style_set_border_side(style, LV_BORDER_SIDE_FULL); + lv_style_set_bg_opa(style, LV_OPA_TRANSP); +}; diff --git a/src/render/native/components/view/view.hpp b/src/render/native/components/view/view.hpp index 735ff4f43..ae826a7b4 100644 --- a/src/render/native/components/view/view.hpp +++ b/src/render/native/components/view/view.hpp @@ -8,5 +8,5 @@ class View final : public BasicComponent { public: View(std::string uid, lv_obj_t* parent = nullptr); - // void initCompStyle (int32_t type); + void initCompStyle (int32_t type); }; diff --git a/src/render/react/core/style/color.ts b/src/render/react/core/style/color.ts index 77ba09b53..db006c28f 100644 --- a/src/render/react/core/style/color.ts +++ b/src/render/react/core/style/color.ts @@ -30,6 +30,8 @@ export const colorTransform = (data) => { return builtinColor[data]; } data = data.replace(/(^\s*)|(\s*$)/g, ""); + const reg8 = /^#([0-9a-fA-f]{8})$/; + const reg4 = /^#([0-9a-fA-f]{4})$/; const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; if (/^(rgb|RGB)/.test(data)) { const aColor = data.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(","); @@ -45,6 +47,17 @@ export const colorTransform = (data) => { num = ""; } return num; + } else if (reg8.test(data)) { + // 8-digit hex: #RRGGBBAA, return RGB part + return Number(`0x${data.substring(1, 7)}`); + } else if (reg4.test(data)) { + // 4-digit hex: #RGBA, return RGB part + const aNum = data.replace(/#/, "").split(""); + let num = "0x"; + for (let i = 0; i < 3; i += 1) { + num += aNum[i] + aNum[i]; + } + return Number(num); } else if (reg.test(data)) { const aNum = data.replace(/#/, "").split(""); if (aNum.length === 6) { @@ -59,3 +72,27 @@ export const colorTransform = (data) => { } return ""; }; + +/** + * Extract opacity value (0-1 range) from color string + * Supports 8-digit hex format: #RRGGBBAA or #RGBA + */ +export const extractOpacity = (data) => { + if (builtinColor[data]) { + return 255; // Built-in colors don't have opacity information + } + data = data.replace(/(^\s*)|(\s*$)/g, ""); + const reg8 = /^#([0-9a-fA-f]{8})$/; + const reg4 = /^#([0-9a-fA-f]{4})$/; + + if (reg8.test(data)) { + // 8-digit hex: #RRGGBBAA, extract last two digits AA + const alphaHex = data.substring(7, 9); + return parseInt(alphaHex, 16) / 255; + } else if (reg4.test(data)) { + // 4-digit hex: #RGBA, extract last digit A and duplicate + const alphaHex = data.substring(4, 5); + return parseInt(alphaHex + alphaHex, 16) / 255; + } + return 255; +}; diff --git a/src/render/react/core/style/util.ts b/src/render/react/core/style/util.ts index c36926178..b39387282 100644 --- a/src/render/react/core/style/util.ts +++ b/src/render/react/core/style/util.ts @@ -1,4 +1,4 @@ -import { colorTransform } from "./color"; +import { colorTransform, extractOpacity } from "./color"; export function NormalizePx(value) { if (value == void 0) return null; @@ -66,9 +66,16 @@ export function ProcessEnum(obj) { } export function ProcessColor(key, value, result) { - value = colorTransform(value); - if (!isNaN(value)) { - result[key] = value; + const colorValue = colorTransform(value); + if (!isNaN(colorValue)) { + result[key] = colorValue; + + // Detect 8-digit hex color (with alpha channel), automatically set corresponding opacity + const opacity = extractOpacity(value); + if (opacity !== undefined) { + const opacityKey = key.replace("color", "opacity"); + result[opacityKey] = NormalizeOpacity(opacity); + } } } From 65dd47671b55418ea82afe7cf5570fcc04422b59 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 27 Jan 2026 15:13:00 +0800 Subject: [PATCH 51/62] refactor: adjust layout and styling in HomePage component --- demo/gateway/pages/HomePage.tsx | 81 +++++++++++---------------------- 1 file changed, 27 insertions(+), 54 deletions(-) diff --git a/demo/gateway/pages/HomePage.tsx b/demo/gateway/pages/HomePage.tsx index 2b667a854..0407bcfd6 100644 --- a/demo/gateway/pages/HomePage.tsx +++ b/demo/gateway/pages/HomePage.tsx @@ -4,8 +4,8 @@ import { useNavigate } from "react-router"; const { width, height } = Dimensions.window; -const colWidth = (width - 24 * 2 - 12) / 2; -const rowHeight = (height - 80 - 24 * 2 - 12) / 2; +const colWidth = (width - 12 * 2 - 12) / 2; +const rowHeight = (height - 12 * 2 - 12) / 2; export function HomePage() { const t = useT(); @@ -19,65 +19,41 @@ export function HomePage() { ]; return ( - - - - {buttons.map((btn, index) => ( - navigate(btn.path)} - > - {/* */} - - {btn.text} - {/* */} - - ))} - + + {buttons.map((btn, index) => ( + navigate(btn.path)} + > + {/* */} + + {btn.text} + {/* */} + + ))} ); } const style: Record = { - pageRoot: { - width, - height, - padding: 0, - "background-color": "black", - display: "flex", - "flex-direction": "column", - overflow: "hidden", - }, - header: { - width, - height: 80, - padding: "24px 24px 0 24px", - display: "flex", - "align-items": "center", - "justify-content": "center", - }, - title: { - "text-color": "white", - "font-size": 24, - }, grid: { width, - height: height - 80, - padding: "24px", + height, + padding: "12px", display: "grid", + "background-color": "black", "grid-template-columns": `${colWidth} ${colWidth}`, "grid-template-rows": `${rowHeight} ${rowHeight}`, - gap: 12, }, button: { "background-color": "#FFFFFF33", @@ -96,9 +72,6 @@ const style: Record = { "justify-content": "center", gap: 8, }, - icon: { - "font-size": 32, - }, buttonText: { "text-color": "white", "font-size": 16, From 60da91492c7e03ae4d943b9521ca17f0fd41cd2b Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 27 Jan 2026 16:00:06 +0800 Subject: [PATCH 52/62] refactor: replace Record with CreateStyle for consistent styling across components - Updated ConfirmDialog, Header, ListItem, and various pages to use CreateStyle for defining styles. - Improved code consistency and readability by standardizing the style definition approach. --- demo/gateway/components/ConfirmDialog.tsx | 6 +++--- demo/gateway/components/Header.tsx | 6 +++--- demo/gateway/components/ListItem.tsx | 6 +++--- demo/gateway/pages/ClearLogsPage.tsx | 6 +++--- demo/gateway/pages/CountdownSettingsPage.tsx | 6 +++--- demo/gateway/pages/DeviceInfoPage.tsx | 6 +++--- demo/gateway/pages/DeviceStatusPage.tsx | 6 +++--- demo/gateway/pages/ExportLogsPage.tsx | 6 +++--- demo/gateway/pages/HomePage.tsx | 6 +++--- demo/gateway/pages/LanguageSettingsPage.tsx | 6 +++--- demo/gateway/pages/LogDetailPage.tsx | 6 +++--- demo/gateway/pages/LogListPage.tsx | 6 +++--- demo/gateway/pages/SettingsPage.tsx | 6 +++--- demo/navigation/index.tsx | 5 +++-- src/render/react/core/style/util.ts | 2 ++ src/render/react/index.ts | 1 + 16 files changed, 45 insertions(+), 41 deletions(-) diff --git a/demo/gateway/components/ConfirmDialog.tsx b/demo/gateway/components/ConfirmDialog.tsx index 250a4f92b..37efad545 100644 --- a/demo/gateway/components/ConfirmDialog.tsx +++ b/demo/gateway/components/ConfirmDialog.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Button, Text, View, Dimensions } from "lvgljs-ui"; +import { Button, Text, View, Dimensions, CreateStyle } from "lvgljs-ui"; const { width, height } = Dimensions.window; @@ -46,7 +46,7 @@ export function ConfirmDialog({ ); } -const style: Record = { +const style = CreateStyle({ overlay: { position: "absolute", width, @@ -96,4 +96,4 @@ const style: Record = { "border-width": 3, "border-color": "#4660FF", }, -}; +}); diff --git a/demo/gateway/components/Header.tsx b/demo/gateway/components/Header.tsx index c298e0a91..5ed64fef8 100644 --- a/demo/gateway/components/Header.tsx +++ b/demo/gateway/components/Header.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Image, Text, View, useT } from "lvgljs-ui"; +import { CreateStyle, Image, Text, View } from "lvgljs-ui"; interface HeaderProps { title: string; @@ -15,7 +15,7 @@ export function Header({ title, backIcon }: HeaderProps) { ); } -const style: Record = { +const style = CreateStyle({ header: { width: "100%", height: 52, @@ -33,4 +33,4 @@ const style: Record = { "text-color": "white", "font-size": 16, }, -}; +}); diff --git a/demo/gateway/components/ListItem.tsx b/demo/gateway/components/ListItem.tsx index 7afc071c0..d5fe507ae 100644 --- a/demo/gateway/components/ListItem.tsx +++ b/demo/gateway/components/ListItem.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Image, Text, useT, View } from "lvgljs-ui"; +import { CreateStyle, Image, Text, useT, View } from "lvgljs-ui"; interface ListItemProps { title: string; @@ -42,7 +42,7 @@ export function ListItem({ ); } -const style: Record = { +const style = CreateStyle({ listItem: { width: "100%", height: 60, @@ -90,4 +90,4 @@ const style: Record = { focused: { "background-color": "#4660FF", }, -}; +}); diff --git a/demo/gateway/pages/ClearLogsPage.tsx b/demo/gateway/pages/ClearLogsPage.tsx index e874dca89..a3fc99bbe 100644 --- a/demo/gateway/pages/ClearLogsPage.tsx +++ b/demo/gateway/pages/ClearLogsPage.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useNavigate } from "react-router"; -import { Dimensions, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; import { ConfirmDialog } from "../components/ConfirmDialog"; @@ -38,7 +38,7 @@ export function ClearLogsPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -48,4 +48,4 @@ const style: Record = { "flex-direction": "column", overflow: "hidden", }, -}; +}); diff --git a/demo/gateway/pages/CountdownSettingsPage.tsx b/demo/gateway/pages/CountdownSettingsPage.tsx index e04ced6b3..d38dc70ec 100644 --- a/demo/gateway/pages/CountdownSettingsPage.tsx +++ b/demo/gateway/pages/CountdownSettingsPage.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router"; -import { Arc, Dimensions, Text, useT, View } from "lvgljs-ui"; +import { Arc, CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -50,7 +50,7 @@ export function CountdownSettingsPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -91,4 +91,4 @@ const style: Record = { "font-size": 26, "padding-top": 20, }, -}; +}); diff --git a/demo/gateway/pages/DeviceInfoPage.tsx b/demo/gateway/pages/DeviceInfoPage.tsx index f0da977d2..e001ccc1e 100644 --- a/demo/gateway/pages/DeviceInfoPage.tsx +++ b/demo/gateway/pages/DeviceInfoPage.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { useNavigate } from "react-router"; -import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -79,7 +79,7 @@ export function DeviceInfoPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -143,4 +143,4 @@ const style: Record = { "font-weight": "normal", "text-align": "right", }, -}; +}); diff --git a/demo/gateway/pages/DeviceStatusPage.tsx b/demo/gateway/pages/DeviceStatusPage.tsx index 88aa6465c..5b5b483ef 100644 --- a/demo/gateway/pages/DeviceStatusPage.tsx +++ b/demo/gateway/pages/DeviceStatusPage.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { useNavigate } from "react-router"; -import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -42,7 +42,7 @@ export function DeviceStatusPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -88,4 +88,4 @@ const style: Record = { focused: { "background-color": "#4660FF", }, -}; +}); diff --git a/demo/gateway/pages/ExportLogsPage.tsx b/demo/gateway/pages/ExportLogsPage.tsx index 2cafbda04..7b4957ea3 100644 --- a/demo/gateway/pages/ExportLogsPage.tsx +++ b/demo/gateway/pages/ExportLogsPage.tsx @@ -1,6 +1,6 @@ import React from "react"; import { useNavigate } from "react-router"; -import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -27,7 +27,7 @@ export function ExportLogsPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -64,4 +64,4 @@ const style: Record = { "text-color": "0xb0b0b0", "font-size": 14, }, -}; +}); diff --git a/demo/gateway/pages/HomePage.tsx b/demo/gateway/pages/HomePage.tsx index 0407bcfd6..ab94972eb 100644 --- a/demo/gateway/pages/HomePage.tsx +++ b/demo/gateway/pages/HomePage.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Button, Dimensions, Image, Text, useT, View } from "lvgljs-ui"; +import { Dimensions, CreateStyle, Image, Text, useT, View } from "lvgljs-ui"; import { useNavigate } from "react-router"; const { width, height } = Dimensions.window; @@ -45,7 +45,7 @@ export function HomePage() { ); } -const style: Record = { +const style = CreateStyle({ grid: { width, height, @@ -84,4 +84,4 @@ const style: Record = { width: 'auto', height: 'auto', }, -}; +}); diff --git a/demo/gateway/pages/LanguageSettingsPage.tsx b/demo/gateway/pages/LanguageSettingsPage.tsx index ddf605114..5c65e8b12 100644 --- a/demo/gateway/pages/LanguageSettingsPage.tsx +++ b/demo/gateway/pages/LanguageSettingsPage.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useNavigate } from "react-router"; -import { Dimensions, Image, Text, useI18n, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, Image, Text, useI18n, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -43,7 +43,7 @@ export function LanguageSettingsPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -98,4 +98,4 @@ const style: Record = { focused: { "background-color": "#4660FF", }, -}; +}); diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx index e674d7a16..240db30e8 100644 --- a/demo/gateway/pages/LogDetailPage.tsx +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState } from "react"; import { useNavigate, useParams } from "react-router"; -import { Dimensions, Text, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; @@ -49,7 +49,7 @@ export function LogDetailPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -96,4 +96,4 @@ const style: Record = { focused: { "background-color": "#4660FF", }, -}; +}); diff --git a/demo/gateway/pages/LogListPage.tsx b/demo/gateway/pages/LogListPage.tsx index be85c3c20..1a7f2c3af 100644 --- a/demo/gateway/pages/LogListPage.tsx +++ b/demo/gateway/pages/LogListPage.tsx @@ -1,6 +1,6 @@ import React from "react"; import { useNavigate } from "react-router"; -import { Dimensions, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; import { ListItem } from "../components/ListItem"; @@ -37,7 +37,7 @@ export function LogListPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -65,4 +65,4 @@ const style: Record = { display: "flex", "flex-direction": "column", }, -}; +}); diff --git a/demo/gateway/pages/SettingsPage.tsx b/demo/gateway/pages/SettingsPage.tsx index 961c14ebc..5ac4245f1 100644 --- a/demo/gateway/pages/SettingsPage.tsx +++ b/demo/gateway/pages/SettingsPage.tsx @@ -1,6 +1,6 @@ import React from "react"; import { useNavigate } from "react-router"; -import { Dimensions, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; import { ListItem } from "../components/ListItem"; @@ -37,7 +37,7 @@ export function SettingsPage() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -65,4 +65,4 @@ const style: Record = { display: "flex", "flex-direction": "column", }, -}; +}); diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index 34756ce5f..dd8a81ce9 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -4,6 +4,7 @@ import { Arc, Button, Checkbox, + CreateStyle, Dimensions, I18nProvider, Render, @@ -368,7 +369,7 @@ function Root() { ); } -const style: Record = { +const style = CreateStyle({ pageRoot: { width, height, @@ -651,7 +652,7 @@ const style: Record = { "justify-content": "center", }, homeBtnText: { "text-color": "white", "font-size": 16 }, -}; +}); Render.render(); diff --git a/src/render/react/core/style/util.ts b/src/render/react/core/style/util.ts index b39387282..113653d95 100644 --- a/src/render/react/core/style/util.ts +++ b/src/render/react/core/style/util.ts @@ -115,3 +115,5 @@ export function ProcessDeg(key, value, result) { export function ProcessBoolean(key, value, result) { result[key] = !!value; } + +export const CreateStyle = >(styles: T): { [K in keyof T]: any } => styles; \ No newline at end of file diff --git a/src/render/react/index.ts b/src/render/react/index.ts index e56535967..4f10fafe9 100644 --- a/src/render/react/index.ts +++ b/src/render/react/index.ts @@ -76,5 +76,6 @@ export { EAnimateEasingFunc, Animate } from "./core/animate"; export { Dimensions } from "./core/dimensions"; export { BUILT_IN_SYMBOL } from "./core/style/symbol"; export { Theme } from "./core/theme"; +export { CreateStyle } from "./core/style/util"; export const Render = Renderer; From 10ece335c35de0c461135aae37fba38743fcaae5 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 27 Jan 2026 16:18:38 +0800 Subject: [PATCH 53/62] refactor: simplify color list animation logic in App component --- demo/widgets/index.jsx | 62 ++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/demo/widgets/index.jsx b/demo/widgets/index.jsx index 76a483888..e858eedf4 100644 --- a/demo/widgets/index.jsx +++ b/demo/widgets/index.jsx @@ -1,5 +1,5 @@ import { View, Render, Animate, Dimensions, EAlignType, Button, Tabs, Theme } from 'lvgljs-ui'; -import React, { useState, useRef } from 'react'; +import React, { useState, useRef, useEffect, useCallback } from 'react'; import Profile from './components/profile' import Analytics from './components/analytics'; import Shop from './components/shop' @@ -34,6 +34,28 @@ function App () { const wrapperRef = useRef() const colorListRef = useRef() + const execAnimate = useCallback((expand) => { + Animate.timing({ + duration: 200, + startValue: expand ? 0 : 256, + endValue: expand ? 256 : 0, + execCallback: (value) => { + colorListRef.current.setStyle({ + width: Math.floor((value / 256) * (width - 60) + 60), + }) + colorListItemsRef.current.forEach(item => { + item.setStyle({ + opacity: (value / 256).toFixed(2), + }) + }) + } + }).start() + }, [colorListRef, colorListItemsRef]) + + useEffect(() => { + execAnimate(colorListExpand) + }, [colorListExpand, execAnimate]) + return ( { - setColorListExpand(!colorListExpand) - const width = wrapperRef.current.style.width - 20 - if (!colorListExpand) { - const animate = Animate.timing({ - duration: 200, - startValue: 0, - endValue: 256, - execCallback: (value) => { - colorListRef.current.setStyle({ - width: Math.floor((value / 256) * (width - 60) + 60), - }) - colorListItemsRef.current.forEach(item => { - item.setStyle({ - opacity: (value / 256).toFixed(2), - }) - }) - } - }) - animate.start() - } else { - const animate = Animate.timing({ - duration: 200, - startValue: 256, - endValue: 0, - execCallback: (value) => { - colorListRef.current.setStyle({ - width: Math.floor((value / 256) * (width - 60) + 60), - }) - colorListItemsRef.current.forEach(item => { - item.setStyle({ - opacity: (value / 256).toFixed(2), - }) - }) - } - }) - animate.start() - } + setColorListExpand((prev) => !prev) }} /> From 23fd241308d8b75d228b9b6aefafa5d46f4a13bc Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Tue, 27 Jan 2026 16:42:46 +0800 Subject: [PATCH 54/62] refactor: update padding and border-radius styles across multiple components --- demo/gateway/components/ListItem.tsx | 5 +++-- demo/gateway/pages/DeviceInfoPage.tsx | 13 ++++++------- demo/gateway/pages/DeviceStatusPage.tsx | 8 +++++--- demo/gateway/pages/LanguageSettingsPage.tsx | 4 +++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/demo/gateway/components/ListItem.tsx b/demo/gateway/components/ListItem.tsx index d5fe507ae..1385ee408 100644 --- a/demo/gateway/components/ListItem.tsx +++ b/demo/gateway/components/ListItem.tsx @@ -46,10 +46,9 @@ const style = CreateStyle({ listItem: { width: "100%", height: 60, - "border-radius": 10, "background-color": "0x2a2a2a", margin: "0 0 8px 0", - padding: "0 16px", + padding: "0 12px", display: "flex", "flex-direction": "row", "align-items": "center", @@ -88,6 +87,8 @@ const style = CreateStyle({ margin: "0 0 0 12px", }, focused: { + padding: "0 12px", + "border-radius": 12, "background-color": "#4660FF", }, }); diff --git a/demo/gateway/pages/DeviceInfoPage.tsx b/demo/gateway/pages/DeviceInfoPage.tsx index e001ccc1e..3e5737a99 100644 --- a/demo/gateway/pages/DeviceInfoPage.tsx +++ b/demo/gateway/pages/DeviceInfoPage.tsx @@ -105,6 +105,7 @@ const style = CreateStyle({ "background-color": "0x2a2a2a", display: "flex", "flex-direction": "column", + "padding": "12px", }, ethTitle: { "text-color": "white", @@ -113,6 +114,8 @@ const style = CreateStyle({ }, ethSectionFocused: { "background-color": "#4660FF", + "border-radius": 12, + "padding": "12px", }, ethContent: { width: "100%", @@ -132,14 +135,10 @@ const style = CreateStyle({ "align-items": "center", "justify-content": "space-between", }, - label: { - "text-color": "0xb0b0b0", - "font-size": 14, - "flex": 1, - }, value: { - "text-color": "white", - "font-size": 14, + "text-color": "#FFFFFF", + "opacity": 0.8, + "font-size": 16, "font-weight": "normal", "text-align": "right", }, diff --git a/demo/gateway/pages/DeviceStatusPage.tsx b/demo/gateway/pages/DeviceStatusPage.tsx index 5b5b483ef..b7100c5b5 100644 --- a/demo/gateway/pages/DeviceStatusPage.tsx +++ b/demo/gateway/pages/DeviceStatusPage.tsx @@ -55,7 +55,7 @@ const style = CreateStyle({ scrollBox: { width: width, height: height - 24, - padding: 8, + padding: 12, "background-color": "0x101010", overflow: 0, "overflow-scrolling": 1, @@ -65,10 +65,9 @@ const style = CreateStyle({ statusItem: { width: "100%", height: 160, - "border-radius": 10, "background-color": "0x2a2a2a", margin: "0 0 8px 0", - padding: "16px", + padding: "12px", display: "flex", "flex-direction": "column", "align-items": "flex-start", @@ -77,6 +76,7 @@ const style = CreateStyle({ }, label: { "text-color": "white", + "opacity": 0.8, "font-size": 14, "margin-bottom": 8, }, @@ -86,6 +86,8 @@ const style = CreateStyle({ "font-weight": "bold", }, focused: { + padding: 12, + "border-radius": 12, "background-color": "#4660FF", }, }); diff --git a/demo/gateway/pages/LanguageSettingsPage.tsx b/demo/gateway/pages/LanguageSettingsPage.tsx index 5c65e8b12..a8cbc15a2 100644 --- a/demo/gateway/pages/LanguageSettingsPage.tsx +++ b/demo/gateway/pages/LanguageSettingsPage.tsx @@ -77,7 +77,7 @@ const style = CreateStyle({ "border-radius": 10, "background-color": "0x2a2a2a", margin: "0 0 8px 0", - padding: "0 16px", + padding: "0 12px", display: "flex", "flex-direction": "row", "align-items": "center", @@ -96,6 +96,8 @@ const style = CreateStyle({ "font-size": 18, }, focused: { + padding: "0 12px", + "border-radius": 12, "background-color": "#4660FF", }, }); From 7e3f47781c0c52be9102c257c325fb68aac80a82 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 28 Jan 2026 17:13:04 +0800 Subject: [PATCH 55/62] refactor: enhance Header component with navigation functionality and style updates --- demo/gateway/components/Header.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/demo/gateway/components/Header.tsx b/demo/gateway/components/Header.tsx index 5ed64fef8..4644a85e0 100644 --- a/demo/gateway/components/Header.tsx +++ b/demo/gateway/components/Header.tsx @@ -1,5 +1,6 @@ import React from "react"; import { CreateStyle, Image, Text, View } from "lvgljs-ui"; +import { useNavigate } from "react-router"; interface HeaderProps { title: string; @@ -7,8 +8,10 @@ interface HeaderProps { } export function Header({ title, backIcon }: HeaderProps) { + const navigate = useNavigate(); return ( + navigate(-1)} /> {backIcon && } {title} @@ -28,6 +31,8 @@ const style = CreateStyle({ headerIcon: { width: 'auto', height: 'auto', + "text-color": "white", + "font-size": 18, }, headerTitle: { "text-color": "white", From 76f75ac4f73106b0eb0eb4c36b418ceccec17cb4 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 30 Jan 2026 15:38:47 +0800 Subject: [PATCH 56/62] fix: reorder the select items --- demo/gateway/pages/HomePage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/gateway/pages/HomePage.tsx b/demo/gateway/pages/HomePage.tsx index ab94972eb..d44c90fff 100644 --- a/demo/gateway/pages/HomePage.tsx +++ b/demo/gateway/pages/HomePage.tsx @@ -13,8 +13,8 @@ export function HomePage() { const buttons = [ { path: "/logs", icon: "./demo/gateway/assets/nav_icon/event_log.png", text: t("header.eventLog"), col: 0, row: 0 }, - { path: "/device-info", icon: "./demo/gateway/assets/nav_icon/device_info.png", text: t("header.deviceInfo"), col: 1, row: 0 }, - { path: "/device-status", icon: "./demo/gateway/assets/nav_icon/device_status.png", text: t("header.deviceStatus"), col: 0, row: 1 }, + { path: "/device-info", icon: "./demo/gateway/assets/nav_icon/device_info.png", text: t("header.deviceInfo"), col: 0, row: 1 }, + { path: "/device-status", icon: "./demo/gateway/assets/nav_icon/device_status.png", text: t("header.deviceStatus"), col: 1, row: 0 }, { path: "/settings", icon: "./demo/gateway/assets/nav_icon/settings.png", text: t("header.settings"), col: 1, row: 1 }, ]; @@ -33,7 +33,7 @@ export function HomePage() { ]} addToFocusGroup onFocusedStyle={style.focused} - onClick={() => navigate(btn.path)} + onClick={() => navigate(btn.path, { state: { from: "home", to: btn.path } })} > {/* */} From b2ca22c07d90967299761ea46724f86965b6a0f1 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 30 Jan 2026 18:29:47 +0800 Subject: [PATCH 57/62] feat: add pagination navigation to LogDetailPage and update localization strings - Implemented previous and next page navigation in LogDetailPage. - Added corresponding localization strings for English, Japanese, and Chinese. - Enhanced the user interface with new navigation items for improved usability. --- demo/gateway/i18n/en.json | 4 +- demo/gateway/i18n/ja.json | 4 +- demo/gateway/i18n/zh.json | 4 +- demo/gateway/pages/LogDetailPage.tsx | 114 +++++++++++++++++++++++---- 4 files changed, 108 insertions(+), 18 deletions(-) diff --git a/demo/gateway/i18n/en.json b/demo/gateway/i18n/en.json index 2ed701169..c62dc17ae 100644 --- a/demo/gateway/i18n/en.json +++ b/demo/gateway/i18n/en.json @@ -12,7 +12,9 @@ "title": "Event Log", "alerts": "Alerts", "notification": "Notification", - "detail": "Log Detail" + "detail": "Log Detail", + "prevPage": "Previous Page", + "nextPage": "Next Page" }, "deviceInfo": { "title": "Device Info" diff --git a/demo/gateway/i18n/ja.json b/demo/gateway/i18n/ja.json index ff9660413..3b047c09e 100644 --- a/demo/gateway/i18n/ja.json +++ b/demo/gateway/i18n/ja.json @@ -12,7 +12,9 @@ "title": "Event Log [ja]", "alerts": "Alerts [ja]", "notification": "Notification [ja]", - "detail": "Log Detail [ja]" + "detail": "Log Detail [ja]", + "prevPage": "前のページ", + "nextPage": "次のページ" }, "deviceInfo": { "title": "Device Info [ja]" diff --git a/demo/gateway/i18n/zh.json b/demo/gateway/i18n/zh.json index 38599ffba..f729d4fac 100644 --- a/demo/gateway/i18n/zh.json +++ b/demo/gateway/i18n/zh.json @@ -12,7 +12,9 @@ "title": "Event Log [zh]", "alerts": "Alerts [zh]", "notification": "Notification [zh]", - "detail": "Log Detail [zh]" + "detail": "Log Detail [zh]", + "prevPage": "上一页", + "nextPage": "下一页" }, "deviceInfo": { "title": "Device Info [zh]" diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx index 240db30e8..fc6e692a3 100644 --- a/demo/gateway/pages/LogDetailPage.tsx +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -1,48 +1,110 @@ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useEffect, useMemo, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router"; import { CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; +const PAGE_SIZE = 5; +const ITEM_EACH_PAGE = 20; +const TOTAL_ITEMS = ITEM_EACH_PAGE * PAGE_SIZE; + +function NavItem({ text, onClick }: { text: string, onClick: () => void }) { + return ( + + {text} + + ); +} + export function LogDetailPage() { const t = useT(); const navigate = useNavigate(); const params = useParams<{ id: string }>(); const [logId, setLogId] = useState("unknown"); + const [currentPage, setCurrentPage] = useState(1); + const [direction, setDirection] = useState<"prev" | "next">("next"); + const focusItemRef = useRef(null); - // 使用 useEffect 监听路由参数变化 useEffect(() => { if (params.id) { setLogId(params.id); } }, [params.id]); - // 模拟日志详情数据 - const logDetails = useMemo(() => { - return Array.from({ length: 20 }).map((_, i) => ({ + const allLogDetails = useMemo(() => { + return Array.from({ length: TOTAL_ITEMS }).map((_, i) => ({ id: i + 1, content: `Log entry ${i + 1} for ${logId}`, })); }, [logId]); + const isFirstPage = currentPage <= 1; + const isLastPage = currentPage >= PAGE_SIZE; + + const currentPageData = useMemo(() => { + const start = (currentPage - 1) * ITEM_EACH_PAGE; + return allLogDetails.slice(start, start + ITEM_EACH_PAGE); + }, [allLogDetails, currentPage]); + + useEffect(() => { + const id = setTimeout(() => { + focusItemRef.current?.focus?.(); + }, 0); + return () => clearTimeout(id); + }, [currentPage, direction]); + + const goPrevPage = () => { + if (!isFirstPage) { + setDirection("prev"); + setCurrentPage((p) => p - 1); + } + }; + + const goNextPage = () => { + if (!isLastPage) { + setDirection("next"); + setCurrentPage((p) => p + 1); + } + }; + return ( navigate(-1)}>
- {logDetails.map((log, index) => ( - - {log.content} - + {!isFirstPage && ( + + )} + + {Array.from({ length: ITEM_EACH_PAGE }).map((_, index) => ( + { + if (direction === "next" && index === 0) { + focusItemRef.current = el; + } else if (direction === "prev" && index === ITEM_EACH_PAGE - 1) { + focusItemRef.current = el; + } + }} + autoFocus={index === 0 && isFirstPage} + addToFocusGroup + onFocusedStyle={style.focused} + style={style.logItem} + > + {currentPageData[index]?.content ?? ""} + ))} + + {!isLastPage && ( + + )} @@ -77,6 +139,25 @@ const style = CreateStyle({ display: "flex", "flex-direction": "column", }, + navItem: { + width: "100%", + "min-height": 48, + "border-radius": 10, + "background-color": "0x333333", + margin: "0 0 8px 0", + padding: "12px 16px", + display: "flex", + "align-items": "center", + "justify-content": "center", + "scroll-on-focus": 1, + }, + navText: { + "text-color": "white", + "font-size": 14, + }, + navFocused: { + "background-color": "#4660FF", + }, logItem: { width: "100%", "min-height": 60, @@ -94,6 +175,9 @@ const style = CreateStyle({ "font-size": 14, }, focused: { + "border-radius": 10, + margin: "0 0 8px 0", + padding: "12px 16px", "background-color": "#4660FF", }, }); From 40390eeddb8cc1d4cee18450b2a485195ec5aa2e Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 30 Jan 2026 19:48:27 +0800 Subject: [PATCH 58/62] feat: integrate focus group functionality and enhance LogDetailPage pagination - Added focus group support to LogDetailPage for improved navigation. - Updated pagination logic to use constants for better readability. - Included focus group initialization in the render bootstrap process. - Refactored LogDetailPage to remove deprecated navigation components and streamline the UI. --- CMakeLists.txt | 1 + demo/gateway/pages/LogDetailPage.tsx | 114 ++++++------------ .../native/bootstrap/render_bootstrap.cpp | 3 + .../native/core/focus_group/focus_group.cpp | 78 ++++++++++++ .../native/core/focus_group/focus_group.hpp | 9 ++ src/render/react/core/focus-group/index.ts | 73 +++++++++++ src/render/react/index.ts | 2 + 7 files changed, 202 insertions(+), 78 deletions(-) create mode 100644 src/render/native/core/focus_group/focus_group.cpp create mode 100644 src/render/native/core/focus_group/focus_group.hpp create mode 100644 src/render/react/core/focus-group/index.ts diff --git a/CMakeLists.txt b/CMakeLists.txt index 4caffcbda..34399ebc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(LVGLJS_SOURCES src/render/native/core/img/img.cpp src/render/native/core/utils/utils.hpp src/render/native/core/animate/animate.cpp + src/render/native/core/focus_group/focus_group.cpp src/render/native/components/arc/arc.cpp src/render/native/components/arc/arc_wrap.cpp src/render/native/components/mask/mask.cpp diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx index fc6e692a3..30c873a70 100644 --- a/demo/gateway/pages/LogDetailPage.tsx +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -1,26 +1,13 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router"; -import { CreateStyle, Dimensions, Text, useT, View } from "lvgljs-ui"; +import { CreateStyle, Dimensions, Text, useFocusGroupEdge, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; -const PAGE_SIZE = 5; -const ITEM_EACH_PAGE = 20; -const TOTAL_ITEMS = ITEM_EACH_PAGE * PAGE_SIZE; - -function NavItem({ text, onClick }: { text: string, onClick: () => void }) { - return ( - - {text} - - ); -} +const TOTAL_PAGES = 5; +const ITEMS_PER_PAGE = 20; +const TOTAL_ITEMS = ITEMS_PER_PAGE * TOTAL_PAGES; export function LogDetailPage() { const t = useT(); @@ -45,13 +32,25 @@ export function LogDetailPage() { }, [logId]); const isFirstPage = currentPage <= 1; - const isLastPage = currentPage >= PAGE_SIZE; + const isLastPage = currentPage >= TOTAL_PAGES; const currentPageData = useMemo(() => { - const start = (currentPage - 1) * ITEM_EACH_PAGE; - return allLogDetails.slice(start, start + ITEM_EACH_PAGE); + const start = (currentPage - 1) * ITEMS_PER_PAGE; + return allLogDetails.slice(start, start + ITEMS_PER_PAGE); }, [allLogDetails, currentPage]); + useFocusGroupEdge({ + onEdge: (edgeDirection) => { + if (edgeDirection === "next" && !isLastPage) { + setDirection("next"); + setCurrentPage((p) => p + 1); + } else if (edgeDirection === "prev" && !isFirstPage) { + setDirection("prev"); + setCurrentPage((p) => p - 1); + } + } + }); + useEffect(() => { const id = setTimeout(() => { focusItemRef.current?.focus?.(); @@ -59,52 +58,30 @@ export function LogDetailPage() { return () => clearTimeout(id); }, [currentPage, direction]); - const goPrevPage = () => { - if (!isFirstPage) { - setDirection("prev"); - setCurrentPage((p) => p - 1); - } - }; - - const goNextPage = () => { - if (!isLastPage) { - setDirection("next"); - setCurrentPage((p) => p + 1); - } - }; - return ( navigate(-1)}>
- {!isFirstPage && ( - - )} - - {Array.from({ length: ITEM_EACH_PAGE }).map((_, index) => ( - { - if (direction === "next" && index === 0) { - focusItemRef.current = el; - } else if (direction === "prev" && index === ITEM_EACH_PAGE - 1) { - focusItemRef.current = el; - } - }} - autoFocus={index === 0 && isFirstPage} - addToFocusGroup - onFocusedStyle={style.focused} - style={style.logItem} - > - {currentPageData[index]?.content ?? ""} - + {Array.from({ length: ITEMS_PER_PAGE }).map((_, index) => ( + { + if (direction === "next" && index === 0) { + focusItemRef.current = el; + } else if (direction === "prev" && index === ITEMS_PER_PAGE - 1) { + focusItemRef.current = el; + } + }} + autoFocus={index === 0 && isFirstPage} + addToFocusGroup + onFocusedStyle={style.focused} + style={style.logItem} + > + {currentPageData[index]?.content ?? ""} + ))} - - {!isLastPage && ( - - )} @@ -139,25 +116,6 @@ const style = CreateStyle({ display: "flex", "flex-direction": "column", }, - navItem: { - width: "100%", - "min-height": 48, - "border-radius": 10, - "background-color": "0x333333", - margin: "0 0 8px 0", - padding: "12px 16px", - display: "flex", - "align-items": "center", - "justify-content": "center", - "scroll-on-focus": 1, - }, - navText: { - "text-color": "white", - "font-size": 14, - }, - navFocused: { - "background-color": "#4660FF", - }, logItem: { width: "100%", "min-height": 60, diff --git a/src/render/native/bootstrap/render_bootstrap.cpp b/src/render/native/bootstrap/render_bootstrap.cpp index 03222493f..52a96cde5 100644 --- a/src/render/native/bootstrap/render_bootstrap.cpp +++ b/src/render/native/bootstrap/render_bootstrap.cpp @@ -5,6 +5,7 @@ #include "native/core/dimensions/dimensions.hpp" #include "native/core/refresh/refresh.hpp" #include "native/core/theme/theme.hpp" +#include "native/core/focus_group/focus_group.hpp" #define NATIVE_RENDER_OBJ "NativeRender" @@ -24,6 +25,8 @@ void NativeRenderInit (JSContext* ctx, JSValue ns) { NativeThemeInit(ctx, obj); + NativeFocusGroupInit(ctx, obj); + lv_init(); lv_png_init(); }; diff --git a/src/render/native/core/focus_group/focus_group.cpp b/src/render/native/core/focus_group/focus_group.cpp new file mode 100644 index 000000000..7c759b70d --- /dev/null +++ b/src/render/native/core/focus_group/focus_group.cpp @@ -0,0 +1,78 @@ +#include "focus_group.hpp" +#include "engine.hpp" + +static JSValue js_edge_callback = JS_UNDEFINED; +static JSContext* stored_ctx = nullptr; + +static void focus_group_edge_cb(lv_group_t* group, bool is_next) { + if (stored_ctx == nullptr || JS_IsUndefined(js_edge_callback)) { + return; + } + + JSValue argv[1]; + argv[0] = JS_NewBool(stored_ctx, is_next); + + JSValue ret = JS_Call(stored_ctx, js_edge_callback, JS_NULL, 1, argv); + if (JS_IsException(ret)) { + TJSRuntime* qrt = GetRuntime(); + tjs_dump_error(qrt->ctx); + } + + JS_FreeValue(stored_ctx, ret); + JS_FreeValue(stored_ctx, argv[0]); +} + +static JSValue NativeSetFocusGroupEdgeCallback(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) { + if (argc < 1) { + return JS_UNDEFINED; + } + + if (!JS_IsUndefined(js_edge_callback)) { + JS_FreeValue(stored_ctx, js_edge_callback); + } + + stored_ctx = ctx; + + if (JS_IsNull(argv[0]) || JS_IsUndefined(argv[0])) { + js_edge_callback = JS_UNDEFINED; + lv_group_t* def_group = lv_group_get_default(); + if (def_group) { + lv_group_set_edge_cb(def_group, NULL); + } + return JS_UNDEFINED; + } + + js_edge_callback = JS_DupValue(ctx, argv[0]); + + lv_group_t* def_group = lv_group_get_default(); + if (def_group) { + lv_group_set_edge_cb(def_group, focus_group_edge_cb); + } + + return JS_UNDEFINED; +} + +static JSValue NativeSetFocusGroupWrap(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) { + if (argc < 1) { + return JS_UNDEFINED; + } + + bool wrap = JS_ToBool(ctx, argv[0]); + lv_group_t* def_group = lv_group_get_default(); + if (def_group) { + lv_group_set_wrap(def_group, wrap); + } + + return JS_UNDEFINED; +} + +static const JSCFunctionListEntry focus_group_funcs[] = { + TJS_CFUNC_DEF("setEdgeCallback", 1, NativeSetFocusGroupEdgeCallback), + TJS_CFUNC_DEF("setWrap", 1, NativeSetFocusGroupWrap), +}; + +void NativeFocusGroupInit(JSContext* ctx, JSValue& ns) { + JSValue obj = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, obj, focus_group_funcs, sizeof(focus_group_funcs) / sizeof(focus_group_funcs[0])); + JS_SetPropertyStr(ctx, ns, "FocusGroup", obj); +} diff --git a/src/render/native/core/focus_group/focus_group.hpp b/src/render/native/core/focus_group/focus_group.hpp new file mode 100644 index 000000000..38478cddd --- /dev/null +++ b/src/render/native/core/focus_group/focus_group.hpp @@ -0,0 +1,9 @@ +#pragma once + +extern "C" { + #include "lvgl.h" + #include "private.h" + #include "utils.h" +}; + +void NativeFocusGroupInit(JSContext* ctx, JSValue& ns); diff --git a/src/render/react/core/focus-group/index.ts b/src/render/react/core/focus-group/index.ts new file mode 100644 index 000000000..3c8c813b6 --- /dev/null +++ b/src/render/react/core/focus-group/index.ts @@ -0,0 +1,73 @@ +import { useEffect, useRef } from 'react'; + +const bridge = globalThis[Symbol.for('lvgljs')] as any; +const FocusGroup = bridge?.NativeRender?.FocusGroup; + +export type EdgeDirection = 'next' | 'prev'; + +export interface UseFocusGroupEdgeOptions { + /** + * 当焦点到达边缘时的回调 + * @param direction 'next' 表示到达底部/右侧边缘,'prev' 表示到达顶部/左侧边缘 + */ + onEdge: (direction: EdgeDirection) => void; + + /** + * 是否启用循环(到达边缘后是否回到另一端) + * 默认 false,这样才能触发 edge 回调 + */ + wrap?: boolean; +} + +/** + * 监听焦点组边缘事件 + * + * @example + * ```tsx + * useFocusGroupEdge({ + * onEdge: (direction) => { + * if (direction === 'next' && !isLastPage) { + * setCurrentPage(p => p + 1); + * } else if (direction === 'prev' && !isFirstPage) { + * setCurrentPage(p => p - 1); + * } + * } + * }); + * ``` + */ +export function useFocusGroupEdge(options: UseFocusGroupEdgeOptions) { + const { onEdge, wrap = false } = options; + const callbackRef = useRef(onEdge); + + useEffect(() => { + callbackRef.current = onEdge; + }, [onEdge]); + + useEffect(() => { + if (!FocusGroup) { + console.warn('FocusGroup API not available'); + return; + } + + FocusGroup.setWrap(wrap); + + const handler = (isNext: boolean) => { + const direction: EdgeDirection = isNext ? 'next' : 'prev'; + callbackRef.current(direction); + }; + + FocusGroup.setEdgeCallback(handler); + + return () => { + FocusGroup.setEdgeCallback(null); + }; + }, [wrap]); +} + +export function setFocusGroupWrap(wrap: boolean) { + if (!FocusGroup) { + console.warn('FocusGroup API not available'); + return; + } + FocusGroup.setWrap(wrap); +} diff --git a/src/render/react/index.ts b/src/render/react/index.ts index 4f10fafe9..f67a5b388 100644 --- a/src/render/react/index.ts +++ b/src/render/react/index.ts @@ -77,5 +77,7 @@ export { Dimensions } from "./core/dimensions"; export { BUILT_IN_SYMBOL } from "./core/style/symbol"; export { Theme } from "./core/theme"; export { CreateStyle } from "./core/style/util"; +export { useFocusGroupEdge, setFocusGroupWrap } from "./core/focus-group"; +export type { EdgeDirection, UseFocusGroupEdgeOptions } from "./core/focus-group"; export const Render = Renderer; From b4cb0ce89b25afb385e1093ed9dd1fb1a879bf75 Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Fri, 30 Jan 2026 20:20:42 +0800 Subject: [PATCH 59/62] refactor: simplify LogDetailPage structure and enhance focus navigation --- demo/gateway/pages/LogDetailPage.tsx | 106 +++++---------------- src/render/react/core/focus-group/index.ts | 1 + 2 files changed, 27 insertions(+), 80 deletions(-) diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx index 30c873a70..26f20e5a6 100644 --- a/demo/gateway/pages/LogDetailPage.tsx +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -1,88 +1,52 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { useNavigate, useParams } from "react-router"; +import React, { useMemo, useState } from "react"; +import { useNavigate } from "react-router"; import { CreateStyle, Dimensions, Text, useFocusGroupEdge, useT, View } from "lvgljs-ui"; import { Header } from "../components/Header"; const { width, height } = Dimensions.window; -const TOTAL_PAGES = 5; -const ITEMS_PER_PAGE = 20; -const TOTAL_ITEMS = ITEMS_PER_PAGE * TOTAL_PAGES; +const TOTAL_ITEMS = 10; +function checkIndex(index: number) { + if (index < 0) { + return 0; + } + if (index >= TOTAL_ITEMS) { + return TOTAL_ITEMS - 1; + } + return index; +} export function LogDetailPage() { const t = useT(); const navigate = useNavigate(); - const params = useParams<{ id: string }>(); - const [logId, setLogId] = useState("unknown"); - const [currentPage, setCurrentPage] = useState(1); - const [direction, setDirection] = useState<"prev" | "next">("next"); - const focusItemRef = useRef(null); - - useEffect(() => { - if (params.id) { - setLogId(params.id); - } - }, [params.id]); + const [currentIndex, setCurrentIndex] = useState(0); const allLogDetails = useMemo(() => { return Array.from({ length: TOTAL_ITEMS }).map((_, i) => ({ id: i + 1, - content: `Log entry ${i + 1} for ${logId}`, + content: `Log entry ${i + 1}, now I am focused, and change index by focus group edge event`, })); - }, [logId]); - - const isFirstPage = currentPage <= 1; - const isLastPage = currentPage >= TOTAL_PAGES; - - const currentPageData = useMemo(() => { - const start = (currentPage - 1) * ITEMS_PER_PAGE; - return allLogDetails.slice(start, start + ITEMS_PER_PAGE); - }, [allLogDetails, currentPage]); + }, []); useFocusGroupEdge({ onEdge: (edgeDirection) => { - if (edgeDirection === "next" && !isLastPage) { - setDirection("next"); - setCurrentPage((p) => p + 1); - } else if (edgeDirection === "prev" && !isFirstPage) { - setDirection("prev"); - setCurrentPage((p) => p - 1); + if (edgeDirection === "next") { + setCurrentIndex(checkIndex(currentIndex + 1)); + } else if (edgeDirection === "prev") { + setCurrentIndex(checkIndex(currentIndex - 1)); } } - }); - - useEffect(() => { - const id = setTimeout(() => { - focusItemRef.current?.focus?.(); - }, 0); - return () => clearTimeout(id); - }, [currentPage, direction]); + }); return ( navigate(-1)}>
- - - - {Array.from({ length: ITEMS_PER_PAGE }).map((_, index) => ( - { - if (direction === "next" && index === 0) { - focusItemRef.current = el; - } else if (direction === "prev" && index === ITEMS_PER_PAGE - 1) { - focusItemRef.current = el; - } - }} - autoFocus={index === 0 && isFirstPage} - addToFocusGroup - onFocusedStyle={style.focused} - style={style.logItem} - > - {currentPageData[index]?.content ?? ""} - - ))} - + + {allLogDetails[currentIndex]?.content ?? ""} ); @@ -98,24 +62,6 @@ const style = CreateStyle({ "flex-direction": "column", overflow: "hidden", }, - content: { - width, - height: height - 52, - padding: 12, - display: "flex", - "flex-direction": "column", - }, - scrollBox: { - width: width - 24, - height: height - 52 - 24, - padding: 8, - "background-color": "0x101010", - "border-radius": 10, - overflow: 0, - "overflow-scrolling": 1, - display: "flex", - "flex-direction": "column", - }, logItem: { width: "100%", "min-height": 60, diff --git a/src/render/react/core/focus-group/index.ts b/src/render/react/core/focus-group/index.ts index 3c8c813b6..327dec51d 100644 --- a/src/render/react/core/focus-group/index.ts +++ b/src/render/react/core/focus-group/index.ts @@ -59,6 +59,7 @@ export function useFocusGroupEdge(options: UseFocusGroupEdgeOptions) { FocusGroup.setEdgeCallback(handler); return () => { + FocusGroup.setWrap(true); FocusGroup.setEdgeCallback(null); }; }, [wrap]); From 5d81355158b46f5a50bde31e237f0d13c801b02c Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Mon, 2 Feb 2026 10:43:16 +0800 Subject: [PATCH 60/62] refactor: rename checkIndex to loopIndex and simplify navigation logic in LogDetailPage --- demo/gateway/pages/LogDetailPage.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/demo/gateway/pages/LogDetailPage.tsx b/demo/gateway/pages/LogDetailPage.tsx index 26f20e5a6..fd9512ae6 100644 --- a/demo/gateway/pages/LogDetailPage.tsx +++ b/demo/gateway/pages/LogDetailPage.tsx @@ -6,12 +6,12 @@ import { Header } from "../components/Header"; const { width, height } = Dimensions.window; const TOTAL_ITEMS = 10; -function checkIndex(index: number) { +function loopIndex(index: number) { if (index < 0) { - return 0; + return TOTAL_ITEMS - 1; } if (index >= TOTAL_ITEMS) { - return TOTAL_ITEMS - 1; + return 0; } return index; } @@ -30,11 +30,8 @@ export function LogDetailPage() { useFocusGroupEdge({ onEdge: (edgeDirection) => { - if (edgeDirection === "next") { - setCurrentIndex(checkIndex(currentIndex + 1)); - } else if (edgeDirection === "prev") { - setCurrentIndex(checkIndex(currentIndex - 1)); - } + const result = loopIndex(currentIndex + (edgeDirection === "next" ? 1 : -1)); + setCurrentIndex(result); } }); From 5022770affe66b1ffdd1f2b605ccce8f5e92a14a Mon Sep 17 00:00:00 2001 From: huanghuiqing Date: Wed, 4 Feb 2026 12:02:42 +0800 Subject: [PATCH 61/62] update .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 441397dfd..dbd8df51e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ # Build folders debug/ -build*/ +build/* dev_*/ **/.cache/ From d34d458f5a8966c9b249f4c06476cb877659d34a Mon Sep 17 00:00:00 2001 From: sunnyswag Date: Sun, 22 Feb 2026 23:04:13 +0800 Subject: [PATCH 62/62] chore: translate Chinese comments to English Co-authored-by: Cursor --- demo/gateway/components/ConfirmDialog.tsx | 4 ++-- demo/gateway/pages/ClearLogsPage.tsx | 2 +- demo/navigation/index.tsx | 4 ++-- src/render/react/core/focus-group/index.ts | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/demo/gateway/components/ConfirmDialog.tsx b/demo/gateway/components/ConfirmDialog.tsx index 37efad545..6d33be870 100644 --- a/demo/gateway/components/ConfirmDialog.tsx +++ b/demo/gateway/components/ConfirmDialog.tsx @@ -15,8 +15,8 @@ export function ConfirmDialog({ title, onConfirm, onCancel, - confirmText = "确认", - cancelText = "取消", + confirmText = "Confirm", + cancelText = "Cancel", }: ConfirmDialogProps) { return ( diff --git a/demo/gateway/pages/ClearLogsPage.tsx b/demo/gateway/pages/ClearLogsPage.tsx index a3fc99bbe..6e8651e29 100644 --- a/demo/gateway/pages/ClearLogsPage.tsx +++ b/demo/gateway/pages/ClearLogsPage.tsx @@ -12,7 +12,7 @@ export function ClearLogsPage() { const [showDialog, setShowDialog] = useState(true); const handleConfirm = () => { - // 执行清除日志操作 + // Perform clear logs action setShowDialog(false); navigate(-1); }; diff --git a/demo/navigation/index.tsx b/demo/navigation/index.tsx index dd8a81ce9..77f3eacdf 100644 --- a/demo/navigation/index.tsx +++ b/demo/navigation/index.tsx @@ -498,7 +498,7 @@ const style = CreateStyle({ "background-color": "white", opacity: 255, }, - // 横向滚动容器 + // Horizontal scroll container pager: { width, height: height - 80, @@ -511,7 +511,7 @@ const style = CreateStyle({ overflow: 0, // 0 -> add_flag(SCROLLABLE) "overflow-scrolling": 1, - "scroll-snap-x": 3, // LV_SCROLL_SNAP_CENTER(本仓库 lvgl: NONE=0 START=1 END=2 CENTER=3) + "scroll-snap-x": 3, // LV_SCROLL_SNAP_CENTER (this repo lvgl: NONE=0 START=1 END=2 CENTER=3) }, page: { width, diff --git a/src/render/react/core/focus-group/index.ts b/src/render/react/core/focus-group/index.ts index 327dec51d..33037f448 100644 --- a/src/render/react/core/focus-group/index.ts +++ b/src/render/react/core/focus-group/index.ts @@ -7,20 +7,20 @@ export type EdgeDirection = 'next' | 'prev'; export interface UseFocusGroupEdgeOptions { /** - * 当焦点到达边缘时的回调 - * @param direction 'next' 表示到达底部/右侧边缘,'prev' 表示到达顶部/左侧边缘 + * Callback when focus reaches the edge. + * @param direction 'next' means bottom/right edge, 'prev' means top/left edge */ onEdge: (direction: EdgeDirection) => void; /** - * 是否启用循环(到达边缘后是否回到另一端) - * 默认 false,这样才能触发 edge 回调 + * Whether to enable wrap (focus wraps to the other end when reaching edge). + * Default false so that the edge callback can be triggered. */ wrap?: boolean; } /** - * 监听焦点组边缘事件 + * Listen for focus group edge events * * @example * ```tsx