namnguyen пре 7 месеци
родитељ
комит
2e0267e82f

+ 31 - 0
doc/gui/examples/controls/menu_on_action.py

@@ -0,0 +1,31 @@
+# Copyright 2021-2024 Avaiga Private Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+# -----------------------------------------------------------------------------------------
+# To execute this script, make sure that the taipy-gui package is installed in your
+# Python environment and run:
+#     python <script>
+# -----------------------------------------------------------------------------------------
+from taipy.gui import Gui
+
+options = [("a", "Option A"), ("b", "Option B"), ("c", "Option C"), ("d", "Option D")]
+selected = ["a", "b"]
+
+def menu_action(_1, _2, payload):
+    selected_options = payload["args"]
+    for option in selected_options:
+        print(f"Selected: {option}") # noqa: F401, T201
+
+page = """
+<|menu|lov={options}|selected={selected}|on_action=menu_action|>
+"""
+
+if __name__ == "__main__":
+    Gui(page).run(title="Menu - On Action")

+ 14 - 19
frontend/taipy-gui/src/components/Taipy/Menu.spec.tsx

@@ -1,16 +1,3 @@
-/*
- * Copyright 2021-2024 Avaiga Private Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-
 import React from "react";
 import { render } from "@testing-library/react";
 import "@testing-library/jest-dom";
@@ -22,13 +9,13 @@ import { TaipyContext } from "../../context/taipyContext";
 import { LovItem } from "../../utils/lov";
 
 const lov: LovItem[] = [
-    {id: "id1", item: "Item 1"},
-    {id: "id2", item:"Item 2"},
-    {id: "id3", item:"Item 3"},
-    {id: "id4", item:"Item 4"},
+    { id: "id1", item: "Item 1" },
+    { id: "id2", item: "Item 2" },
+    { id: "id3", item: "Item 3" },
+    { id: "id4", item: "Item 4" },
 ];
 
-const imageItem: LovItem = {id: "ii1", item: { path: "/img/fred.png", text: "Image" }};
+const imageItem: LovItem = { id: "ii1", item: { path: "/img/fred.png", text: "Image" } };
 
 describe("Menu Component", () => {
     it("renders", async () => {
@@ -36,44 +23,52 @@ describe("Menu Component", () => {
         const elt = getByText("Item 1");
         expect(elt.tagName).toBe("SPAN");
     });
+
     it("uses the class", async () => {
         const { getByText } = render(<Menu lov={lov} className="taipy-menu" />);
         const elt = getByText("Item 1");
         expect(elt.closest(".taipy-menu")).not.toBeNull();
     });
+
     it("can display an avatar with initials", async () => {
         const lovWithImage = [...lov, imageItem];
         const { getByText } = render(<Menu lov={lovWithImage} />);
         const elt = getByText("I2");
         expect(elt.tagName).toBe("DIV");
     });
+
     it("can display an image", async () => {
         const lovWithImage = [...lov, imageItem];
         const { getByAltText } = render(<Menu lov={lovWithImage} />);
         const elt = getByAltText("Image");
         expect(elt.tagName).toBe("IMG");
     });
+
     it("is disabled", async () => {
         const { getAllByRole } = render(<Menu lov={lov} active={false} />);
         const elts = getAllByRole("button");
         elts.forEach((elt, idx) => idx > 0 && expect(elt).toHaveClass("Mui-disabled"));
     });
+
     it("is enabled by default", async () => {
         const { getAllByRole } = render(<Menu lov={lov} />);
         const elts = getAllByRole("button");
         elts.forEach((elt) => expect(elt).not.toHaveClass("Mui-disabled"));
     });
+
     it("is enabled by active", async () => {
         const { getAllByRole } = render(<Menu lov={lov} active={true} />);
         const elts = getAllByRole("button");
         elts.forEach((elt) => expect(elt).not.toHaveClass("Mui-disabled"));
     });
+
     it("can disable a specific item", async () => {
         const { getByText } = render(<Menu lov={lov} inactiveIds={[lov[0].id]} />);
         const elt = getByText(lov[0].item as string);
-        const button = elt.closest('[role="button"]')
+        const button = elt.closest('[role="button"]');
         expect(button).toHaveClass("Mui-disabled");
     });
+
     it("dispatch a well formed message", async () => {
         const dispatch = jest.fn();
         const state: TaipyState = INITIAL_STATE;

+ 4 - 5
frontend/taipy-gui/src/components/Taipy/lovUtils.tsx

@@ -41,6 +41,7 @@ export interface LovProps<T = string | string[], U = string> extends TaipyActive
     defaultValue?: U;
     height?: string | number;
     valueById?: boolean;
+    selected?: T;
 }
 
 /**
@@ -112,7 +113,7 @@ export const LovImage = ({
     item: Icon;
     disableTypo?: boolean;
     height?: string;
-    titleTypographyProps?: TypographyProps<"span", { component?: "span"; }>;
+    titleTypographyProps?: TypographyProps<"span", { component?: "span" }>;
 }) => {
     const sx = useMemo(
         () => (height ? { height: height, "& .MuiAvatar-img": { objectFit: "contain" } } : undefined) as SxProps,
@@ -121,9 +122,7 @@ export const LovImage = ({
     return (
         <CardHeader
             sx={cardSx}
-            avatar={
-                <IconAvatar img={item} sx={sx} />
-            }
+            avatar={<IconAvatar img={item} sx={sx} />}
             title={item.text}
             disableTypography={disableTypo}
             titleTypographyProps={titleTypographyProps}
@@ -147,7 +146,7 @@ export interface ItemProps {
     item: stringIcon;
     disabled: boolean;
     withAvatar?: boolean;
-    titleTypographyProps?: TypographyProps<"span", { component?: "span"; }>;
+    titleTypographyProps?: TypographyProps<"span", { component?: "span" }>;
 }
 
 export const SingleItem = ({

+ 0 - 5
taipy/gui/viselements.json

@@ -1536,11 +1536,6 @@
                         "default_value": "<i>Type name of the first lov element</i>",
                         "doc": "This property is required if <i>lov</i> contains a non-specific type of data (e.g., a dictionary).<br/>Then:<ul><li><i>value</i> must be of that type</li><li><i>lov</i> must be an iterable containing elements of this type</li><li>The function set to <i>adapter</i> will receive an object of this type.</li></ul><br/>The default value is the type of the first element in <i>lov</i>."
                     },
-                    {
-                        "name": "label",
-                        "type": "str",
-                        "doc": "The title of the menu."
-                    },
                     {
                         "name": "width",
                         "type": "str",