Browse Source

Doc-related updates focusing on the table edition features. (#1818)

- Builder API generated with None default value when needed
- All __init__ files fixed in doc examples directories
- Added dynamic styling and edit example for table
- Added doc for style parameter in page classes
- Details on code examples.
- Update .gitignore files
Fabien Lelaquais 7 months ago
parent
commit
5f982e1a36
37 changed files with 776 additions and 114 deletions
  1. 1 1
      doc/gui/examples/blocks/pane_anchor/__init__.py
  2. 1 1
      doc/gui/examples/blocks/pane_as_page/__init__.py
  3. 1 1
      doc/gui/examples/blocks/pane_persistent/__init__.py
  4. 1 1
      doc/gui/examples/blocks/pane_simple/__init__.py
  5. 1 1
      doc/gui/examples/blocks/pane_simple_lambda/__init__.py
  6. 25 0
      doc/gui/examples/controls/progress-texts.py
  7. 1 1
      doc/gui/examples/controls/progress_styling_circular/__init__.py
  8. 1 1
      doc/gui/examples/controls/progress_styling_linear/__init__.py
  9. 1 1
      doc/gui/examples/controls/progress_styling_linear/markdown.py
  10. 1 1
      doc/gui/examples/controls/selector_checkbox.py
  11. 1 1
      doc/gui/examples/controls/selector_radio.py
  12. 1 1
      doc/gui/examples/controls/slider-multiple.py
  13. 1 0
      doc/gui/examples/controls/table_edit_action/__init__.py
  14. 58 0
      doc/gui/examples/controls/table_edit_action/builder.py
  15. 56 0
      doc/gui/examples/controls/table_edit_action/markdown.py
  16. 49 0
      doc/gui/examples/controls/table_enums.py
  17. 0 0
      doc/gui/examples/controls/table_formatting.py
  18. 99 0
      doc/gui/examples/controls/table_guard_edits.py
  19. 1 0
      doc/gui/examples/controls/table_styling_cells/__init__.py
  20. 68 0
      doc/gui/examples/controls/table_styling_cells/builder.py
  21. 67 0
      doc/gui/examples/controls/table_styling_cells/markdown.py
  22. 1 0
      doc/gui/examples/controls/table_styling_rows/__init__.py
  23. 45 0
      doc/gui/examples/controls/table_styling_rows/builder.py
  24. 45 0
      doc/gui/examples/controls/table_styling_rows/markdown.py
  25. 1 1
      doc/gui/examples/controls/text-md.py
  26. 1 1
      doc/gui/examples/controls/text-pre.py
  27. 60 0
      doc/gui/examples/styling-dynamic.py
  28. 3 0
      taipy/gui/.gitignore
  29. 9 1
      taipy/gui/_renderers/__init__.py
  30. 2 2
      taipy/gui/_renderers/_markdown/preproc.py
  31. 2 0
      taipy/gui/builder/.gitignore
  32. 5 1
      taipy/gui/builder/page.py
  33. 37 18
      taipy/gui/gui.py
  34. 25 1
      taipy/gui/page.py
  35. 16 13
      taipy/gui/utils/table_col_builder.py
  36. 89 65
      taipy/gui/viselements.json
  37. 0 0
      taipy/py.typed

+ 1 - 1
doc/gui/examples/blocks/pane_anchor/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 1 - 1
doc/gui/examples/blocks/pane_as_page/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 1 - 1
doc/gui/examples/blocks/pane_persistent/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 1 - 1
doc/gui/examples/blocks/pane_simple/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 1 - 1
doc/gui/examples/blocks/pane_simple_lambda/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 25 - 0
doc/gui/examples/controls/progress-texts.py

@@ -0,0 +1,25 @@
+# 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
+
+value = 72
+
+page = """
+<|{value}|progress|linear|title=Processing...|title_anchor=top|show_value|>
+"""
+
+if __name__ == "__main__":
+    Gui(page).run(title="Progress - Texts")

+ 1 - 1
doc/gui/examples/controls/progress_styling_circular/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 1 - 1
doc/gui/examples/controls/progress_styling_linear/__init__.py

@@ -1 +1 @@
-# This file makes this directory a module on its own, mandatody for mypy.
+# This file makes this directory a module on its own, mandatory for mypy.

+ 1 - 1
doc/gui/examples/controls/progress_styling_linear/markdown.py

@@ -19,7 +19,7 @@ value = 72
 
 page = Markdown(
     "<|{value}|progress|linear|>",
-    stylex={
+    style={
         ".taipy-progress": {
             "background-color": "red",
             "height": "30px",

+ 1 - 1
doc/gui/examples/controls/selector_checkbox.py

@@ -22,4 +22,4 @@ page = """
 """
 
 if __name__ == "__main__":
-    Gui(page).run(title="Selector - Checkbox")
+    Gui(page).run(title="Selector - Checkbox mode")

+ 1 - 1
doc/gui/examples/controls/selector_radio.py

@@ -22,4 +22,4 @@ page = """
 """
 
 if __name__ == "__main__":
-    Gui(page).run(title="Selector - Radio")
+    Gui(page).run(title="Selector - Radio mode")

+ 1 - 1
doc/gui/examples/controls/slider-multiple.py

@@ -25,4 +25,4 @@ Selection: <|{values}|>
 """
 
 if __name__ == "__main__":
-    Gui(page).run(title="Slider - Range")
+    Gui(page).run(title="Slider - Multiple values")

+ 1 - 0
doc/gui/examples/controls/table_edit_action/__init__.py

@@ -0,0 +1 @@
+# This file makes this directory a module on its own, mandatory for mypy.

+ 58 - 0
doc/gui/examples/controls/table_edit_action/builder.py

@@ -0,0 +1,58 @@
+# 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>
+# -----------------------------------------------------------------------------------------
+import pandas as pd
+
+import taipy.gui.builder as tgb
+from taipy.gui import Gui, State
+
+categories = ["Real Estate", "Stocks", "Cash", "Retirement", "Other"]
+amounts = [190000, 60000, 100000, 110000, 40000]
+
+
+# Return an array where each item represents the percentage of the corresponding value in the
+# input array:
+# [10, 10] -> [50, 50]
+# [1, 2, 3] -> [16, 33, 50]
+def compute_ratio(amounts: list[int]) -> list[int]:
+    total = sum(amounts)
+    return [int((amount / total) * 100) for amount in amounts]
+
+
+# Initialize the ratio array
+ratio = compute_ratio(amounts)
+
+# Create the dataset used by the table
+data = pd.DataFrame({"Category": categories, "Amount": amounts, "%": ratio})
+
+
+# Called when the user edits a cell's value
+def update(state: State, var_name: str, payload: dict):
+    # Batch the updates to the state
+    with state:
+        # Invoke the default processing for 'on_edit'
+        # Because the table data is a Pandas data frame, the cell is updated automatically
+        state.get_gui().table_on_edit(state, var_name, payload)
+        # Update ratios based on the new cell value
+        state.data["%"] = compute_ratio(state.data["Amount"])
+        # Update the control
+        state.refresh(var_name)
+
+
+with tgb.Page() as page:
+    tgb.table("{data}", editable__Amount=True, on_edit=update, on_add=False, on_delete=False, show_all=True)
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Action on edit")

+ 56 - 0
doc/gui/examples/controls/table_edit_action/markdown.py

@@ -0,0 +1,56 @@
+# 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>
+# -----------------------------------------------------------------------------------------
+import pandas as pd
+
+from taipy.gui import Gui, State
+
+categories = ["Real Estate", "Stocks", "Cash", "Retirement", "Other"]
+amounts = [190000, 60000, 100000, 110000, 40000]
+
+
+# Return an array where each item represents the percentage of the corresponding value in the
+# input array:
+# [10, 10] -> [50, 50]
+# [1, 2, 3] -> [16, 33, 50]
+def compute_ratio(amounts: list[int]) -> list[int]:
+    total = sum(amounts)
+    return [int((amount / total) * 100) for amount in amounts]
+
+
+# Initialize the ratio array
+ratio = compute_ratio(amounts)
+
+# Create the dataset used by the table
+data = pd.DataFrame({"Category": categories, "Amount": amounts, "%": ratio})
+
+
+# Called when the user edits a cell's value
+def update(state: State, var_name: str, payload: dict):
+    # Batch the updates to the state
+    with state:
+        # Invoke the default processing for 'on_edit'
+        # Because the table data is a Pandas data frame, the cell is updated automatically
+        state.get_gui().table_on_edit(state, var_name, payload)
+        # Update ratios based on the new cell value
+        state.data["%"] = compute_ratio(state.data["Amount"])
+        # Update the control
+        state.refresh(var_name)
+
+
+page = "<|{data}|table|editable[Amount]|on_edit=update|no on_add|no on_delete|show_all|>"
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Action on edit")

+ 49 - 0
doc/gui/examples/controls/table_enums.py

@@ -0,0 +1,49 @@
+# 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
+
+all_continents = ["Africa", "America", "Antarctica", "Asia", "Europe", "Oceania"]
+cities = [
+    ("Tokyo", "Japan", "Asia", 37),
+    ("Delhi", "India", "Asia", 31),
+    ("Shanghai", "China", "Asia", 26),
+    ("São Paulo", "Brazil", "America", 22),
+    ("Cairo", "Egypt", "Africa", 20),
+    ("Mexico City", "Mexico", "America", 21),
+    ("New York City", "United States", "America", 8.4),
+    ("Lagos", "Nigeria", "Africa", 14),
+    ("Los Angeles", "United States", "America", 4),
+    ("Paris", "France", "Europe", 2.2),
+    ("London", "United Kingdom", "Europe", 9),
+    ("Moscow", "Russia", "Europe", 12.5),
+    ("Seoul", "South Korea", "Asia", 9.7),
+    ("Lima", "Peru", "America", 9.5),
+    ("Bogotá", "Colombia", "America", 10.9),
+    ("Sydney", "Australia", "Oceania", 5.3),
+]
+
+data = {
+    "City": [c[0] for c in cities],
+    "Country": [c[1] for c in cities],
+    "Continent": [c[2] for c in cities],
+    "Population": [c[3] for c in cities],
+}
+
+
+page = "<|{data}|table|lov[Continent]={all_continents}|editable|no on_add|no on_delete|show_all|>"
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Enumerated values")

+ 0 - 0
doc/gui/examples/controls/table-formatting.py → doc/gui/examples/controls/table_formatting.py


+ 99 - 0
doc/gui/examples/controls/table_guard_edits.py

@@ -0,0 +1,99 @@
+# 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>
+# -----------------------------------------------------------------------------------------
+import random
+
+import requests
+
+from taipy.gui import Gui, State, notify
+
+# The RandomAPI API used to generate random user names
+randomuser_url = 'https://randomuser.me/api'
+
+# Create a random person name and salary
+def pick_user() -> tuple[str, int]:
+    # Call the Random User Generator API to create a random person name
+    response = requests.get(randomuser_url)
+    # If the request was successful
+    if response.status_code == 200:
+        # Make a new name and
+        try:
+            person = response.json()["results"][0]
+            name = person["name"]
+            new_user = f"{name['first']} {name['last']}"
+            # Generate a random salary expectation amount
+            salary = random.randint(8, 24) * 5000
+            return (new_user, salary)
+        except ValueError:
+            # There was a back-end error
+            print("ERROR: Invoking the Random User Generator API")  # noqa: F401, T201
+            return ("ERROR", 0)
+    # The API cannot be reached
+    print("ERROR: Could not invoke the Random User Generator API")  # noqa: F401, T201
+    return ("ERROR", 0)
+
+# Generate four random persons with their salary expectation and store them in a dictionary
+candidates: dict[str, list] = {"Name": [], "Salary": []}
+for candidate in [pick_user() for _ in range(4)]:
+    candidates["Name"].append(candidate[0])
+    candidates["Salary"].append(candidate[1])
+
+
+# Triggered when the user clicks the 'Delete' icon and validates
+def check_delete(state: State, var_name: str, payload: dict):
+    # How many candidates are there in the list? (i.e. how many rows in the table)
+    n_candidates = len(state.candidates["Name"])
+    # Check if a candidate can be removed from the list
+    if n_candidates <= 3:
+        # Notify the user that the minimum limit has been reached
+        notify(state, "E", "Too few candidates")
+    else:
+        # Remove the row from the table
+        state.get_gui().table_on_delete(state, var_name, payload)
+
+
+# Triggered when the user clicks the 'Add' icon and validates
+def check_add(state: State, var_name: str, payload: dict):
+    # How many candidates are there in the list? (i.e. how many rows in the table)
+    n_candidates = len(state.candidates["Name"])
+    # Check if a new candidate can be added to the list
+    if n_candidates >= 6:
+        # Notify the user that the maximum limit has been reached
+        notify(state, "E", "Too many candidates")
+    else:
+        # Create new candidate
+        new_row = pick_user()
+        # Add new row at the end of the list
+        payload["index"] = n_candidates
+        # Add the new candidate as a row in the table
+        state.get_gui().table_on_add(state, var_name, payload, new_row=list(new_row))
+
+
+# Triggered when the user changes the value of a cell
+# Force the user-entered value to be a multiple of 5000
+def force_salary(state: State, var_name: str, payload: dict):
+    # Get the salary proposal from the callback's payload
+    proposed_salary = payload["value"]
+    # Round it the the nearest multiple of 5000
+    proposed_salary = round(proposed_salary / 500) * 500
+    # Set it as the value to be stored in the dataset
+    payload["value"] = proposed_salary
+    state.get_gui().table_on_edit(state, var_name, payload)
+
+
+page = "<|{candidates}|table|on_delete=check_delete|on_add=check_add|editable[Salary]|on_edit=force_salary|show_all|>"
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Guard edits")

+ 1 - 0
doc/gui/examples/controls/table_styling_cells/__init__.py

@@ -0,0 +1 @@
+# This file makes this directory a module on its own, mandatory for mypy.

+ 68 - 0
doc/gui/examples/controls/table_styling_cells/builder.py

@@ -0,0 +1,68 @@
+# 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 random import randrange
+
+import taipy.gui.builder as tgb
+from taipy.gui import Gui
+
+x_range = range(0, 11)
+
+# The dataset is made of three arrays:
+# x: an integer value from 0 to 5
+# y: the square of the value in the "x" column
+# z: a random integer betweewn 0 and 5
+data = {"x": x_range, "y": [x * x for x in x_range], "z": [randrange(6) for _ in x_range]}
+
+
+def xy_style(_1, _2, index, _3, column_name):
+    return (
+        # The background color of the 'x' column alternates between two shades of green,
+        # varying in lightness.
+        ("greenish" if index % 2 else "lightgreenish")
+        if column_name == "x"
+        # The background color of the 'y' column alternates between two shades of green,
+        # varying in lightness
+        else ("reddish" if index % 2 else "lightreddish")
+    )
+
+
+def z_style(_, value):
+    # Build a CSS classname from the value.
+    # The lower the value is, the lighter the color is.
+    return f"col{value}"
+
+
+with tgb.Page(
+    style={
+        ".reddish": {"color": "white", "background-color": "#bf1313"},
+        ".lightreddish": {"color": "black", "background-color": "#ff1919", "font-weight": "bold"},
+        ".greenish": {"color": "white", "background-color": "#75bf75"},
+        ".lightgreenish": {"color": "black", "background-color": "#9cff9c", "font-weight": "bold"},
+        ".col0": {"background-color": "#d0d0d0"},
+        ".col1": {"background-color": "#a4a0cf"},
+        ".col2": {"background-color": "#7970cf"},
+        ".col3": {"background-color": "#4e40cf", "color": "white"},
+        ".col4": {"background-color": "#2410cf", "color": "white"},
+        ".col5": {"background-color": "#1b02a8", "color": "white"},
+    }
+) as page:
+    tgb.table("{data}", style__x=xy_style, style__y=xy_style, style__z=z_style, show_all=True)
+    # Using a lambda function instead of z_style:
+    #tgb.table("{data}", style__x=xy_style, style__y=xy_style, style__z=lambda _, v: f"col{v}", show_all=True)
+
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Styling cells")

+ 67 - 0
doc/gui/examples/controls/table_styling_cells/markdown.py

@@ -0,0 +1,67 @@
+# 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 random import randrange
+
+from taipy.gui import Gui, Markdown
+
+x_range = range(0, 11)
+
+# The dataset is made of three arrays:
+# x: an integer value from 0 to 5
+# y: the square of the value in the "x" column
+# z: a random integer betweewn 0 and 5
+data = {"x": x_range, "y": [x * x for x in x_range], "z": [randrange(6) for _ in x_range]}
+
+
+def xy_style(_1, _2, index, _3, column_name):
+    return (
+        # The background color of the 'x' column alternates between two shades of green,
+        # varying in lightness.
+        ("greenish" if index % 2 else "lightgreenish")
+        if column_name == "x"
+        # The background color of the 'y' column alternates between two shades of green,
+        # varying in lightness
+        else ("reddish" if index % 2 else "lightreddish")
+    )
+
+
+def z_style(_, value):
+    # Build a CSS classname from the value.
+    # The lower the value is, the lighter the color is.
+    return f"col{value}"
+
+
+page = Markdown(
+    "<|{data}|table|style[x]=xy_style|style[y]=xy_style|style[z]=z_style|show_all|>",
+    # Using a lambda function instead of z_style:
+    #"<|{data}|table|style[x]=xy_style|style[y]=xy_style|style[z]={lambda _, v: f'col{v}'}|show_all|>",
+    style={
+        ".reddish": {"color": "white", "background-color": "#bf1313"},
+        ".lightreddish": {"color": "black", "background-color": "#ff1919", "font-weight": "bold"},
+        ".greenish": {"color": "white", "background-color": "#75bf75"},
+        ".lightgreenish": {"color": "black", "background-color": "#9cff9c", "font-weight": "bold"},
+        ".col0": {"background-color": "#d0d0d0"},
+        ".col1": {"background-color": "#a4a0cf"},
+        ".col2": {"background-color": "#7970cf"},
+        ".col3": {"background-color": "#4e40cf", "color": "white"},
+        ".col4": {"background-color": "#2410cf", "color": "white"},
+        ".col5": {"background-color": "#1b02a8", "color": "white"},
+    }
+)
+
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Styling cells")

+ 1 - 0
doc/gui/examples/controls/table_styling_rows/__init__.py

@@ -0,0 +1 @@
+# This file makes this directory a module on its own, mandatory for mypy.

+ 45 - 0
doc/gui/examples/controls/table_styling_rows/builder.py

@@ -0,0 +1,45 @@
+# 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>
+# -----------------------------------------------------------------------------------------
+import taipy.gui.builder as tgb
+from taipy.gui import Gui
+
+x_range = range(-10, 11, 4)
+
+data = {"x": x_range, "y": [x * x for x in x_range]}
+
+
+def even_odd_style(_, row):
+    if row % 2:
+        # Odd rows are blue
+        return "blue-row"
+    else:
+        # Even rows are red
+        return "red-row"
+
+
+with tgb.Page(
+    style={
+        ".blue-row>td": {"color": "white", "background-color": "blue"},
+        ".red-row>td": {"color": "yellow", "background-color": "red"},
+    }
+) as page:
+    tgb.table("{data}", style=even_odd_style, show_all=True)
+    # Lambda version, getting rid of even_odd_style():
+    # tgb.table("{data}", style=lambda _, row: "blue-row" if row % 2 else "red-row", show_all=True)
+
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Styling rows")

+ 45 - 0
doc/gui/examples/controls/table_styling_rows/markdown.py

@@ -0,0 +1,45 @@
+# 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, Markdown
+
+x_range = range(-10, 11, 4)
+
+data = {"x": x_range, "y": [x * x for x in x_range]}
+
+
+def even_odd_style(_1, row):
+    if row % 2:
+        # Odd rows are blue
+        return "blue-row"
+    else:
+        # Even rows are red
+        return "red-row"
+
+
+# Lambda version, getting rid of even_odd_style():
+# Replace the table control definition with
+#    <|{data}|table|style={lambda _, row: 'blue-row' if row % 2 else 'red-row'}|show_all|>
+page = Markdown(
+    "<|{data}|table|style=even_odd_style|show_all|>",
+    style={
+        ".blue-row>td": {"color": "white", "background-color": "blue"},
+        ".red-row>td": {"color": "yellow", "background-color": "red"},
+    },
+)
+
+
+if __name__ == "__main__":
+    Gui(page).run(title="Table - Styling rows")

+ 1 - 1
doc/gui/examples/controls/text-md.py

@@ -30,4 +30,4 @@ page = """
 """
 
 if __name__ == "__main__":
-    Gui(page).run(title="Text - Markdown")
+    Gui(page).run(title="Text - Markdown mode")

+ 1 - 1
doc/gui/examples/controls/text-pre.py

@@ -28,4 +28,4 @@ page = """
 """
 
 if __name__ == "__main__":
-    Gui(page).run(title="Text - Pre")
+    Gui(page).run(title="Text - Pre mode")

+ 60 - 0
doc/gui/examples/styling-dynamic.py

@@ -0,0 +1,60 @@
+# 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, Markdown
+
+# The word provided by the user
+word = ""
+# A potential error message
+error_text = ""
+# Is the Validate button enabled?
+valid = False
+# CSS class to add to control showing a problem
+error_cls = None
+
+
+def on_change(state, var_name, value):
+    # If the provided word has changed
+    if var_name == "word":
+        # If not empty and does not have five characters
+        if value and len(value) != 5:
+            # Set the error message
+            state.error_text = " Five characters are required"
+            # Disable the Validate button
+            state.valid = False
+            # Add the invalid-value class, used by the input control and error message
+            state.error_cls = "invalid-value"
+        # The text is valid.
+        else:
+            # Remove error message
+            state.error_text = ""
+            # Enable the Validate button if the word is not empty
+            state.valid = bool(value)
+            # Remove the invalid-value class, used by the input control and error message
+            state.error_cls = None
+
+
+page = Markdown(
+    """
+Enter a five-letter word:
+<|{word}|input|class_name={error_cls}|><|{error_text}|text|class_name={error_cls}|>
+
+<|Validate|button|active={valid}|>
+""",
+    style={".invalid-value": {"background-color": "red"}},
+)
+
+if __name__ == "__main__":
+    Gui(page).run()

+ 3 - 0
taipy/gui/.gitignore

@@ -1,3 +1,6 @@
+# Taipy GUI stuff
+gui.pyi
+
 # Django stuff:
 *.log
 local_settings.py

+ 9 - 1
taipy/gui/_renderers/__init__.py

@@ -149,8 +149,12 @@ class Markdown(_Renderer):
         Arguments:
             content (str): The text content or the path to the file holding the Markdown text
                 to be transformed.<br/>
-                If _content_ is a path to a readable file, the file is read as the Markdown
+                If *content* is a path to a readable file, the file is read as the Markdown
                 template content.
+
+        The `Markdown` constructor supports the *style* parameter as explained in the
+        [section on Styling](../../userman/gui/styling/index.md#style-sheets) and in the
+        `(taipy.gui.Page.)set_style()^` method.
         """
         kwargs["content"] = content
         super().__init__(**kwargs)
@@ -179,6 +183,10 @@ class Html(_Renderer):
                 be transformed.<br/>
                 If *content* is a path to a readable file, the file is read as the HTML
                 template content.
+
+        The `Html` constructor supports the *style* parameter as explained in the
+        [section on Styling](../../userman/gui/styling/index.md#style-sheets) and in the
+        `(taipy.gui.Page.)set_style()^` method.
         """
         kwargs["content"] = content
         super().__init__(**kwargs)

+ 2 - 2
taipy/gui/_renderers/_markdown/preproc.py

@@ -55,10 +55,10 @@ class _Preprocessor(MdPreprocessor):
     #   If <prop_value> is omitted:
     #     '<prop_name>' is equivalent to '<prop_name>=true'
     #     'not <prop_name>' is equivalent to '<prop_name>=false'
-    #       'not', 'dont', 'don't' are equivalent in this context
+    #     'no', 'not', 'dont', 'don't' are equivalent in this context
     #  Note 1: 'not <prop_name>=<prop_value>' is an invalid syntax
     #  Note 2: Space characters after the equal sign are significative
-    __PROPERTY_RE = re.compile(r"((?:don'?t|not)\s+)?([a-zA-Z][\.a-zA-Z_$0-9]*(?:\[(?:.*?)\])?)\s*(?:=(.*))?$")
+    __PROPERTY_RE = re.compile(r"((?:don'?t|not?)\s+)?([a-zA-Z][\.a-zA-Z_$0-9]*(?:\[(?:.*?)\])?)\s*(?:=(.*))?$")
 
     # Error syntax detection regex
     __MISSING_LEADING_PIPE_RE = re.compile(r"<[^|](.*?)\|>")

+ 2 - 0
taipy/gui/builder/.gitignore

@@ -0,0 +1,2 @@
+# Taipy GUI builder stuff
+__init__.pyi

+ 5 - 1
taipy/gui/builder/page.py

@@ -43,9 +43,13 @@ class Page(_Renderer):
         """Initialize a new page.
 
         Arguments:
-            element (*Element*): An optional element, defined in the `taipy.gui.builder` module,
+            element (*Element*): An optional element, defined in the `taipy.gui.builder^` module,
                 that is created in the page.<br/>
                 The default creates a `part` where several elements can be stored.
+
+        The `Page` constructor supports the *style* parameter as explained in the
+        [section on Styling](../../userman/gui/styling/index.md#style-sheets) and in the
+        `(taipy.gui.Page.)set_style()^` method.
         """
         if element is None:
             element = _DefaultBlock()

+ 37 - 18
taipy/gui/gui.py

@@ -1701,33 +1701,48 @@ class Gui:
         return self.__adapter._get_adapted_lov(lov, var_type)
 
     def table_on_edit(self, state: State, var_name: str, payload: t.Dict[str, t.Any]):
-        """
-        TODO: Default implementation of on_edit for tables
-        """
-        try:
-            setattr(state, var_name, self._get_accessor().on_edit(getattr(state, var_name), payload))
-        except Exception as e:
-            _warn("TODO: Table.on_edit", e)
+        """Default implementation of the `on_edit` callback for tables.
 
-    def table_on_delete(self, state: State, var_name: str, payload: t.Dict[str, t.Any]):
-        """
-        TODO: Default implementation of on_delete for tables
+        Arguments:
+            state: the state instance received in the callback.
+            var_name: the name of the variable bound to the table's *data* property.
+            payload: the payload dictionary as it was received from the `on_edit` callback.
         """
         try:
-            setattr(state, var_name, self._get_accessor().on_delete(getattr(state, var_name), payload))
+            setattr(state, var_name, self._get_accessor().on_edit(getattr(state, var_name), payload))
         except Exception as e:
-            _warn("TODO: Table.on_delete", e)
+            _warn("Gui.table_on_edit() failed potentially from a table's on_edit callback.", e)
 
     def table_on_add(
         self, state: State, var_name: str, payload: t.Dict[str, t.Any], new_row: t.Optional[t.List[t.Any]] = None
     ):
-        """
-        TODO: Default implementation of on_add for tables
+        """Default implementation of the `on_add` callback for tables.
+
+        Arguments:
+            state: the state instance received in the callback.
+            var_name: the name of the variable bound to the table's *data* property.
+            payload: the payload dictionary as it was received from the `on_add` callback.
+            new_row: the initial values to be stored in the new row.<br/>
+                This defaults to all values being set to 0, whatever that means depending on the
+                column data type.
         """
         try:
             setattr(state, var_name, self._get_accessor().on_add(getattr(state, var_name), payload, new_row))
         except Exception as e:
-            _warn("TODO: Table.on_add", e)
+            _warn("Gui.table_on_add() failed potentially from a table's on_add callback.", e)
+
+    def table_on_delete(self, state: State, var_name: str, payload: t.Dict[str, t.Any]):
+        """Default implementation of the `on_delete` callback for tables.
+
+        Arguments:
+            state: the state instance received in the callback.
+            var_name: the name of the variable bound to the table's *data* property.
+            payload: the payload dictionary as it was received from the `on_delete` callback.
+        """
+        try:
+            setattr(state, var_name, self._get_accessor().on_delete(getattr(state, var_name), payload))
+        except Exception as e:
+            _warn("Gui.table_on_delete() failed potentially from a table's on_delete callback.", e)
 
     def _tbl_cols(
         self, rebuild: bool, rebuild_val: t.Optional[bool], attr_json: str, hash_json: str, **kwargs
@@ -2815,11 +2830,15 @@ class Gui:
     def set_favicon(self, favicon_path: t.Union[str, Path], state: t.Optional[State] = None):
         """Change the favicon for all clients.
 
-        This function dynamically changes the favicon of Taipy GUI pages for all connected client.
-        favicon_path can be an URL (relative or not) or a file path.
-        TODO The *favicon* parameter to `(Gui.)run()^` can also be used to change
+        This function dynamically changes the favicon of Taipy GUI pages for a single or all
+        connected clients.
+        Note that the *favicon* parameter to `(Gui.)run()^` can also be used to change
          the favicon when the application starts.
 
+        Arguments:
+            favicon_path: the path to the image file to use.<br/>
+                This can be expressed as a path name or a URL (relative or not).
+            state: the state to apply the change to.
         """
         if state or self.__favicon != favicon_path:
             if not state:

+ 25 - 1
taipy/gui/page.py

@@ -145,8 +145,32 @@ class Page:
     def set_style(self, style: t.Dict[str, t.Dict[str, t.Any]]) -> Page:
         """Set the style for this page.
 
+        The *style* parameter must contain a series of CSS rules that apply to the generated
+        page.<br/>
+        Each key of this dictionary should be a CSS selector and its associated value must be
+        a CSS declaration or a CSS rule itself, benefiting from
+        [nested CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting)
+        features.
+
+        For example, you could set the *style* parameter to:
+        ```python
+        {
+          "class1": {
+            "css_property1": "css_value1",
+          }
+          "class2": {
+            "class3": {
+                "css_property2": "css_value2",
+            }
+          }
+        }
+        ```
+        That would set the "css_property1" to "css_value1" for all elements with the "class1"
+        class, and "css_property2" to "css_value2" for all elements with the "class3" class that
+        are descendants of elements with the "class2" class.
+
         Arguments:
-            style (dict): A dict describing the style as CSS or Nested CSS.
+            style (dict): A dictionary describing the style as CSS or Nested CSS.
 
         Returns:
             This `Page` instance.

+ 16 - 13
taipy/gui/utils/table_col_builder.py

@@ -39,7 +39,7 @@ def _update_col_desc_from_indexed(
             if col_desc.get(_to_camel_case(name)) is None:
                 col_desc[_to_camel_case(name)] = str(v)
         else:
-            _warn(f"{elt_name}: {name}[{k}] is not in the list of displayed columns.")
+            _warn(f"{elt_name}: '{k}' is not a displayed column in {name}[].")
 
 
 def _enhance_columns(  # noqa: C901
@@ -53,21 +53,21 @@ def _enhance_columns(  # noqa: C901
             if col_desc := _get_column_desc(columns, k):
                 col_desc["filter"] = True
             else:
-                _warn(f"{elt_name}: filter[{k}] is not in the list of displayed columns.")
+                _warn(f"{elt_name}: '{k}' is not a displayed column for filter[].")
     editables = _get_name_indexed_property(attributes, "editable")
     for k, v in editables.items():
         if _is_boolean(v):
             if col_desc := _get_column_desc(columns, k):
                 col_desc["notEditable"] = not _is_true(v)
             else:
-                _warn(f"{elt_name}: editable[{k}] is not in the list of displayed columns.")
+                _warn(f"{elt_name}: '{k}' is not a displayed column in editable[].")
     group_by = _get_name_indexed_property(attributes, "group_by")
     for k, v in group_by.items():
         if _is_true(v):
             if col_desc := _get_column_desc(columns, k):
                 col_desc["groupBy"] = True
             else:
-                _warn(f"{elt_name}: group_by[{k}] is not in the list of displayed columns.")
+                _warn(f"{elt_name}: '{k}' is not a displayed column in group_by[].")
     apply = _get_name_indexed_property(attributes, "apply")
     for k, v in apply.items():  # pragma: no cover
         if col_desc := _get_column_desc(columns, k):
@@ -76,27 +76,30 @@ def _enhance_columns(  # noqa: C901
             elif isinstance(v, str):
                 value = v.strip()
             else:
-                _warn(f"{elt_name}: apply[{k}] should be a user or predefined function.")
+                _warn(f"{elt_name}: invalid user or predefined function in apply[].")
                 value = None
             if value:
                 col_desc["apply"] = value
         else:
-            _warn(f"{elt_name}: apply[{k}] is not in the list of displayed columns.")
+            _warn(f"{elt_name}: '{k}' is not a displayed column in apply[].")
+    # TODO: rename to cell_class_name
     styles = _get_name_indexed_property(attributes, "style")
     for k, v in styles.items():  # pragma: no cover
         if col_desc := _get_column_desc(columns, k):
             if callable(v):
+                # TODO: rename to row_class_name
                 value = hash_names.get(f"style[{k}]")
             elif isinstance(v, str):
                 value = v.strip()
             else:
                 value = None
             if value in columns.keys():
-                _warn(f"{elt_name}: style[{k}] cannot reference a column's name '{value}'.")
+                # TODO: rename to cell_class_name
+                _warn(f"{elt_name}: '{k}' is not a valid column in style[].")
             elif value:
                 col_desc["style"] = value
         else:
-            _warn(f"{elt_name}: style[{k}] is not in the list of displayed columns.")
+            _warn(f"{elt_name}: '{k}' is not a displayed column in style[].")
     tooltips = _get_name_indexed_property(attributes, "tooltip")
     for k, v in tooltips.items():  # pragma: no cover
         if col_desc := _get_column_desc(columns, k):
@@ -107,11 +110,11 @@ def _enhance_columns(  # noqa: C901
             else:
                 value = None
             if value in columns.keys():
-                _warn(f"{elt_name}: tooltip[{k}] cannot reference a column's name '{value}'.")
+                _warn(f"{elt_name}: '{k}' is not a valid column in tooltip[].")
             elif value:
                 col_desc["tooltip"] = value
         else:
-            _warn(f"{elt_name}: tooltip[{k}] is not in the list of displayed columns.")
+            _warn(f"{elt_name}: '{k}' is not a displayed column in tooltip[].")
     formats = _get_name_indexed_property(attributes, "format_fn")
     for k, v in formats.items():  # pragma: no cover
         if col_desc := _get_column_desc(columns, k):
@@ -122,11 +125,11 @@ def _enhance_columns(  # noqa: C901
             else:
                 value = None
             if value in columns.keys():
-                _warn(f"{elt_name}: format_fn[{k}] cannot reference a column's name '{value}'.")
+                _warn(f"{elt_name}: '{k}' is not a valid column in format_fn[].")
             elif value:
                 col_desc["formatFn"] = value
         else:
-            _warn(f"{elt_name}: format_fn[{k}] is not in the list of displayed columns.")
+            _warn(f"{elt_name}: '{k}' is not a displayed column in format_fn[].")
     editable = attributes.get("editable", False)
     loveable = _is_boolean(editable) and _is_true(editable)
     loves = _get_name_indexed_property(attributes, "lov")
@@ -148,5 +151,5 @@ def _enhance_columns(  # noqa: C901
                     value = new_value
                 col_desc["lov"] = value
         elif not col_desc:
-            _warn(f"{elt_name}: lov[{k}] is not in the list of displayed columns.")
+            _warn(f"{elt_name}: '{k}' is not a displayed column in lov[].")
     return columns

+ 89 - 65
taipy/gui/viselements.json

@@ -56,8 +56,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when the button is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button it it has one.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the button is pressed.<br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the button it it has one.</li><li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -126,7 +126,7 @@
                         "name": "type",
                         "type": "str",
                         "default_value": "\"text\"",
-                        "doc": "The type of generated input HTML element, as defined in [HTML input types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types).<br/>This value forces certain values to be entered and can be set to \"text\", \"tel\", \"url\", \"url\"..., among other choices."
+                        "doc": "The type of generated input HTML element, as defined in [HTML input types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types).<br/>This value forces certain values to be entered and can be set to \"text\", \"tel\", \"email\", \"url\"..., among other choices."
                     }
                 ]
             }
@@ -213,7 +213,7 @@
                         "name": "text_anchor",
                         "type": "str",
                         "default_value": "\"bottom\"",
-                        "doc": "When the <i>lov</i> property is used, this property indicates the location of the label.<br/>Possible values are:\n<ul>\n<li>\"bottom\"</li>\n<li>\"top\"</li>\n<li>\"left\"</li>\n<li>\"right\"</li>\n<li>\"none\" (no label is displayed)</li>\n</ul>"
+                        "doc": "When the <i>lov</i> property is used, this property indicates the location of the label.<br/>Possible values are:\n<ul>\n<li>\"bottom\"</li><li>\"top\"</li><li>\"left\"</li><li>\"right\"</li><li>\"none\" (no label is displayed)</li></ul>"
                     },
                     {
                         "name": "labels",
@@ -418,19 +418,19 @@
                         "default_property": true,
                         "required": true,
                         "type": "dynamic(Any)",
-                        "doc": "The data object bound to this chart control.<br/>See the section on the <a href=\"#the-data-property\"><i>data</i> property</a> below for details."
+                        "doc": "The data object bound to this chart control.<br/>See the section on the <a href=\"#the-data-property\"><i>data</i> property</a> below for more details."
                     },
                     {
                         "name": "type",
                         "type": "indexed(str)",
                         "default_value": "\"scatter\"",
-                        "doc": "Chart type.<br/>See the Plotly <a href=\"https://plotly.com/javascript/reference/\">chart type</a> documentation for details."
+                        "doc": "Chart type.<br/>See the Plotly <a href=\"https://plotly.com/javascript/reference/\">chart type</a> documentation for more details."
                     },
                     {
                         "name": "mode",
                         "type": "indexed(str)",
                         "default_value": "\"lines+markers\"",
-                        "doc": "Chart mode.<br/>See the Plotly <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-mode\">chart mode</a> documentation for details."
+                        "doc": "Chart mode.<br/>See the Plotly <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-mode\">chart mode</a> documentation for more details."
                     },
                     {
                         "name": "x",
@@ -520,7 +520,7 @@
                     {
                         "name": "base",
                         "type": "indexed(str)",
-                        "doc": "Column name for the <i>base</i> value. Used in bar charts only.<br/>See the Plotly <a href=\"https://plotly.com/javascript/reference/bar/#bar-base\">bar chart base</a> documentation for details.\""
+                        "doc": "Column name for the <i>base</i> value. Used in bar charts only.<br/>See the Plotly <a href=\"https://plotly.com/javascript/reference/bar/#bar-base\">bar chart base</a> documentation for more details.\""
                     },
                     {
                         "name": "title",
@@ -535,8 +535,8 @@
                     },
                     {
                         "name": "on_range_change",
-                        "type": "Callable",
-                        "doc": "The callback function that is invoked when the visible part of the x axis changes.<br/>The function receives three parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the chart control if it has one.</li>\n<li>payload (dict[str, Any]): the full details on this callback's invocation, as emitted by <a href=\"https://plotly.com/javascript/plotlyjs-events/#update-data\">Plotly</a>.</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the visible part of the x axis changes.<br/>This function is invoked with the following parameters:<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the chart control if it has one.</li><li>payload (dict[str, Any]): the full details on this callback's invocation, as emitted by <a href=\"https://plotly.com/javascript/plotlyjs-events/#update-data\">Plotly</a>.</li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -556,7 +556,7 @@
                         "name": "columns",
                         "type": "Union[str,list[str],dict[str,dict[str,str]]]",
                         "default_value": "<i>All columns</i>",
-                        "doc": "The list of column names to represent.\n<ul>\n<li>str: ;-separated list of column names</li>\n<li>list[str]: list of names</li>\n<li>dict: {\"column_name\": {format: \"format\", index: 1}} if index is specified, it represents the display order of the columns.\nIf not, the list order defines the index</li>\n</ul><br/>If <i>columns</i> is omitted or set to None, all columns of <i>data</i> are represented."
+                        "doc": "The list of column names to represent.\n<ul>\n<li>str: ;-separated list of column names</li><li>list[str]: list of names</li><li>dict: {\"column_name\": {format: \"format\", index: 1}} if index is specified, it represents the display order of the columns.\nIf not, the list order defines the index</li></ul><br/>If <i>columns</i> is omitted or set to None, all columns of <i>data</i> are represented."
                     },
                     {
                         "name": "label",
@@ -586,17 +586,17 @@
                     {
                         "name": "marker",
                         "type": "indexed(dict[str, Any])",
-                        "doc": "The type of markers used for the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-marker\">marker</a> for details.<br/>Color, opacity, size and symbol can be column name."
+                        "doc": "The type of markers used for the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-marker\">marker</a> for more details.<br/>Color, opacity, size and symbol can be column names."
                     },
                     {
                         "name": "line",
                         "type": "indexed(Union[str,dict[str,Any]])",
-                        "doc": "The configuration of the line used for the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-line\">line</a> for details.<br/>If the value is a string, it must be a dash type or pattern (see <a href=\"https://plotly.com/python/reference/scatter/#scatter-line-dash\">dash style of lines</a> for details)."
+                        "doc": "The configuration of the line used for the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-line\">line</a> for more details.<br/>If the value is a string, it must be a dash type or pattern (see <a href=\"https://plotly.com/python/reference/scatter/#scatter-line-dash\">dash style of lines</a> for more details)."
                     },
                     {
                         "name": "selected_marker",
                         "type": "indexed(dict[str, Any])",
-                        "doc": "The type of markers used for selected points in the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-selected-marker\">selected marker for details."
+                        "doc": "The type of markers used for selected points in the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-selected-marker\">selected marker for more details."
                     },
                     {
                         "name": "layout",
@@ -677,8 +677,8 @@
                     },
                     {
                         "name": "on_click",
-                        "type": "Callable",
-                        "doc": "The callback that is invoked when the user clicks in the chart background.<br/>The function receives three parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the chart control if it has one.</li>\n<li>payload (dict[str, Any]): a dictionary containing the <i>x</i> and <i>y</i> coordinates of the click <b>or</b> <i>latitude</i> and <i>longitude</i> in the case of a map. This feature relies on non-public Plotly structured information.</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user clicks in the chart background.<br/>This function is invoked with the following parameters:<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the chart control if it has one.</li><li>payload (dict[str, Any]): a dictionary containing the <i>x</i> and <i>y</i> coordinates of the click <b>or</b> <i>latitude</i> and <i>longitude</i> in the case of a map. This feature relies on non-public Plotly structured information.</li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -756,7 +756,7 @@
                         "name": "columns",
                         "type": "Union[str,list[str],dict[str,dict[str,Union[str,int]]]]",
                         "default_value": "<i>All columns</i>",
-                        "doc": "The list of the column names to display.\n<ul>\n<li>str: Semicolon (';')-separated list of column names.</li>\n<li>list[str]: The list of column names.</li>\n<li>dict: A dictionary with entries matching: {\"&lt;column_name&gt;\": {\"format\": \"&lt;format&gt;\", \"index\": 1}}.<br/>\nif <i>index</i> is specified, it represents the display order of this column.\nIf <i>index</i> is not specified, the list order defines the index.<br/>\nIf <i>format</i> is specified, it is used for numbers or dates.</li>\n</ul><br/>If <i>columns</i> is omitted or set to None, all columns of <i>data</i> are represented."
+                        "doc": "The list of the column names to display.\n<ul>\n<li>str: semicolon (';')-separated list of column names.</li><li>list[str]: the list of column names.</li><li>dict: a dictionary with entries matching: {\"&lt;column_name&gt;\": {\"format\": \"&lt;format&gt;\", \"index\": 1}}.<br/>\nif <i>index</i> is specified, it represents the display order of this column.\nIf <i>index</i> is not specified, the list order defines the index.<br/>\nIf <i>format</i> is specified, it is used for numbers or dates.</li></ul><br/>If <i>columns</i> is omitted or set to None, all columns of <i>data</i> are represented."
                     },
                     {
                         "name": "date_format",
@@ -773,38 +773,62 @@
                         "name": "group_by[<i>column_name</i>]",
                         "type": "bool",
                         "default_value": "False",
-                        "doc": "Indicates, if True, that the given column can be aggregated.<br/>See <a href=\"#aggregation\">below</a> for details."
+                        "doc": "Indicates, if True, that the given column can be aggregated.<br/>See <a href=\"#aggregation\">below</a> for more details."
                     },
                     {
                         "name": "apply[<i>column_name</i>]",
                         "type": "str",
                         "default_value": "\"first\"",
-                        "doc": "The name of the aggregation function to use.<br/>This is used only if <i>group_by[column_name]</i> is set to True.<br/>See <a href=\"#aggregation\">below</a> for details."
+                        "doc": "The name of the aggregation function to use.<br/>This is used only if <i>group_by[column_name]</i> is set to True.<br/>See <a href=\"#aggregation\">below</a> for more details."
                     },
                     {
+                        "//TODO": "rename to 'row_class_name",
                         "name": "style",
                         "type": "Union[str, Callable]",
-                        "doc": "Allows the styling of table lines.<br/>See <a href=\"#dynamic-styling\">below</a> for details."
+                        "doc": "Allows for styling rows.<br/>This property must be a function or the name of a function that return the name of a CSS class for table rows.<br/>This function is invoked with the following parameters:<ul><li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>index</i> (int): the index of the row.</li><li><i>row</i> (Any): all the values for this row.</li></ul><br/>See <a href=\"#dynamic-styling\">below</a> for more details."
                     },
                     {
+                        "//TODO": "rename to 'cell_class_name",
                         "name": "style[<i>column_name</i>]",
                         "type": "Union[str, Callable]",
-                        "doc": "Allows the styling of table cells.<br/>See <a href=\"#dynamic-styling\">below</a> for details."
+                        "doc": "Allows for styling cells.<br/>This property must be a function or the name of a function that return the name of a CSS class for table cells.<br/>This function is invoked with the following parameters:<ul><li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>value</i> (Any): the value of the cell.</li><li><i>index</i> (int): the index of the row.</li><li><i>row</i> (Any): all the values for this row.</li><li><i>column_name</i> (str): the name of the column.</li></ul><br/>See <a href=\"#dynamic-styling\">below</a> for more details."
                     },
                     {
                         "name": "tooltip",
                         "type": "Union[str, Callable]",
-                        "doc": "The name of the function that must return a tooltip text for a cell.<br/>See <a href=\"#cell-tooltips\">below</a> for details."
+                        "doc": "Enables tooltips on cells.<br/>This property must be a function or the name of a function that must return a tooltip text for a cell.<br/>See <a href=\"#cell-tooltips\">below</a> for more details."
                     },
                     {
                         "name": "tooltip[<i>column_name</i>]",
                         "type": "Union[str, Callable]",
-                        "doc": "The name of the function that must return a tooltip text for a cell.<br/>See <a href=\"#cell-tooltips\">below</a> for details."
+                        "doc": "Enables tooltips on cells at a column level.<br/>This property must be a function or the name of a the function that must return a tooltip text for a cell.<br/>See <a href=\"#cell-tooltips\">below</a> for more details."
                     },
                     {
                         "name": "format_fn[<i>column_name</i>]",
                         "type": "Union[str, Callable]",
-                        "doc": "TODO: The name of the function that must return a formatted value for a cell.<br/>See <a href=\"#cell-formats\">below</a> for details."
+                        "doc": "Defines custom formatting for table cells. This property must be a function or the name of a function that returns a formatted string for each cell.<br/>The function is invoked when the cells in the specified column (<i>column_name</i>) are rendered. It should return a string that represents the cell value to provide the best user experience.<br/>This function is invoked with the following parameters:<ul>  <li><i>state</i> (<code>State^</code>): the state instance.</li>  <li><i>value</i> (Any): the value of the cell.</li>  <li><i>index</i> (int): the index of the row.</li>  <li><i>row</i> (Any): the entire row. The type depends on the type of <i>data</i>.</li>  <li><i>column_name</i> (str): the name of the column.</li></ul>By default, no custom formatting is applied to the column.<br/>For more details, see the <a href=\"#cell-formats\">section</a>.",
+                        "signature": [
+                            [
+                                "state",
+                                "State"
+                            ],
+                            [
+                                "value",
+                                "Any"
+                            ],
+                            [
+                                "index",
+                                "int"
+                            ],
+                            [
+                                "row",
+                                "Any"
+                            ],
+                            [
+                                "column_name",
+                                "str"
+                            ]
+                        ]
                     },
                     {
                         "name": "width",
@@ -846,7 +870,7 @@
                         "name": "editable",
                         "type": "dynamic(bool)",
                         "default_value": "False",
-                        "doc": "Indicates, if True, that all columns can be edited."
+                        "doc": "Indicates, if True, that all cells can be edited."
                     },
                     {
                         "name": "editable[<i>column_name</i>]",
@@ -856,9 +880,9 @@
                     },
                     {
                         "name": "on_edit",
-                        "type": "Union[Callable, bool]",
+                        "type": "Union[bool, Callable]",
                         "default_value": "<i>default implementation</i>",
-                        "doc": "The name of the function triggered when a cell edition is validated.<br/>All the parameters of that function are optional:\n<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li>\n<li><i>var_name</i> (str): the name of the tabular data variable.</li>\n<li><i>payload</i> (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li><i>index</i> (int): the row index.</li>\n<li><i>col</i> (str): the column name.</li>\n<li><i>value</i> (Any): the new cell value cast to the type of the column.</li>\n<li><i>user_value</i> (str): the new cell value, as it was provided by the user.</li>\n<li><i>tz</i> (str): the timezone if the column type is <tt>date</tt>.</li>\n</ul>\n</li>\n</ul><br/>If this property is not set and the type of <i>data</i> allows it, the table uses the default implementation for editing cells.",
+                        "doc": "A function or the name of a function triggered when an edited cell is validated.<br/>This function is invoked with the following parameters:<ul><li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>var_name</i> (str): the name of the tabular data variable.</li><li><i>payload</i> (dict): a dictionary containing details about the callback invocation, with the following keys:<ul><li><i>index</i> (int): the row index.</li><li><i>col</i> (str): the column name.</li><li><i>value</i> (Any): the new cell value, cast to the column's data type.</li><li><i>user_value</i> (str): the new cell value, as entered by the user.</li><li><i>tz</i> (str): the timezone, if the column type is <tt>date</tt>.</li></ul></li></ul>If this property is set to False, the table does not provide the cell editing functionality.<br/>If this property is not set, the table will use the default implementation for editing cells.",
                         "signature": [
                             [
                                 "state",
@@ -876,8 +900,8 @@
                     },
                     {
                         "name": "on_add",
-                        "type": "Union[Callable, bool]",
-                        "doc": "The name of a function that is triggered when the user requests a row to be added to the table.<br/>All parameters of that function are optional:\n<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li>\n<li><i>var_name</i> (str): the name of the tabular data variable.</li>\n<li><i>payload</i> (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li><i>index</i> (int): the row index.</li>\n</ul>\n</li>\n</ul><br/>If this property is not set and the type of <i>data</i> supports it, the table uses the default implementation for adding a new row<br/>If this property is set to False, you cannot add new rows.",
+                        "type": "Union[bool, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user requests a row to be added to the table.<br/>This function is invoked with the following parameters:\n<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>var_name</i> (str): the name of the tabular data variable.</li><li><i>payload</i> (dict): the details on this callback's invocation.<br/>This dictionary has the following key:\n<ul>\n<li><i>index</i> (int): the row index.</li></ul></li></ul><br/>If this property is not set, the table uses the default implementation for adding a new row<br/>If this property is set to False, you cannot add new rows.",
                         "signature": [
                             [
                                 "state",
@@ -895,9 +919,9 @@
                     },
                     {
                         "name": "on_delete",
-                        "type": "Union[Callable, bool]",
+                        "type": "Union[bool, Callable]",
                         "default_value": "<i>default implementation</i>",
-                        "doc": "The name of the function triggered when a row is deleted.<br/>All the parameters of that function are optional:\n<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li>\n<li><i>var_name</i> (str): the name of the tabular data variable.</li>\n<li><i>payload</i> (dict): the details on this callback's invocation.<br/>\nThis dictionary has one key:\n<ul>\n<li><i>index</i> (int): the row index.</li>\n</ul>\n</li>\n</ul><br/>If this property is not set and the type of <i>data</i> allows it, the table uses the default implementation for deleting rows.",
+                        "doc": "A function or the name of a function triggered when a row is deleted.<br/>This function is invoked with the following parameters:\n<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>var_name</i> (str): the name of the tabular data variable.</li><li><i>payload</i> (dict): the details on this callback's invocation.<br/>\nThis dictionary has one key:\n<ul>\n<li><i>index</i> (int): the row index.</li></ul></li></ul><br/>If this property is not set, the table uses the default implementation for deleting rows.",
                         "signature": [
                             [
                                 "state",
@@ -915,8 +939,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when the user selects a row.<br/>All parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>var_name (str): the name of the tabular data variable.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>index (int): the row index.</li>\n<li>col (str): the column name.</li>\n<li>reason (str): the origin of the action: \"click\", or \"button\" if the cell contains a Markdown link syntax.</li>\n<li>value (str): the <i>link value</i> indicated in the cell when using a Markdown link syntax (that is, <i>reason</i> is set to \"button\").</li></ul></li></ul>.",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user selects a row.<br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>var_name (str): the name of the tabular data variable.</li><li>payload (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li><li>index (int): the row index.</li><li>col (str): the column name.</li><li>reason (str): the origin of the action: \"click\", or \"button\" if the cell contains a Markdown link syntax.</li><li>value (str): the <i>link value</i> indicated in the cell when using a Markdown link syntax (that is, <i>reason</i> is set to \"button\").</li></ul></li></ul>.",
                         "signature": [
                             [
                                 "state",
@@ -957,8 +981,8 @@
                     },
                     {
                         "name": "on_compare",
-                        "type": "Callable",
-                        "doc": "A data comparison function that would return a structure that identifies the differences between the different data passed as name. The default implementation compares the default data with the data[1] value.",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that compares data. This function should return a structure that identifies the differences between the different data passed as name. The default implementation compares the default data with the data[1] value.",
                         "signature": [
                             [
                                 "state",
@@ -1000,7 +1024,7 @@
                     {
                         "name": "mode",
                         "type": "str",
-                        "doc": "Define the way the selector is displayed:\n<ul><li>&quot;radio&quot;: list of radio buttons</li><li>&quot;check&quot;: list of check buttons</li><li>any other value: selector as usual."
+                        "doc": "Define the way the selector is displayed:\n<ul><li>&quot;radio&quot;: as a list of radio buttons</li><li>&quot;check&quot;: as a list of check boxes</li><li>any other value: a plain list."
                     },
                     {
                         "name": "dropdown",
@@ -1046,7 +1070,7 @@
                         "name": "content",
                         "default_property": true,
                         "type": "dynamic(Union[path,file,URL,ReadableBuffer,None])",
-                        "doc": "The content to transfer.<br/>If this is a string, a URL, or a file, then the content is read from this source.<br/>If a readable buffer is provided (such as an array of bytes...), and to prevent the bandwidth from being consumed too much, the way the data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the buffer size is smaller than this setting, then the raw content is generated as a data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li>\n<li>If the buffer size exceeds this setting, then it is transferred through a temporary file.</li>\n</ul>If this property is set to None, that indicates that dynamic content is generated. Please take a look at the examples below for details on dynamic generation."
+                        "doc": "The content to transfer.<br/>If this is a string, a URL, or a file, then the content is read from this source.<br/>If a readable buffer is provided (such as an array of bytes...), and to prevent the bandwidth from being consumed too much, the way the data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the buffer size is smaller than this setting, then the raw content is generated as a data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li><li>If the buffer size exceeds this setting, then it is transferred through a temporary file.</li></ul>If this property is set to None, that indicates that dynamic content is generated. Please take a look at the examples below for more details on dynamic generation."
                     },
                     {
                         "name": "label",
@@ -1055,8 +1079,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when the download is terminated (or on user action if <i>content</i> is None).<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has two keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: A list of two elements: <i>args[0]</i> reflects the <i>name</i> property and <i>args[1]</i> holds the file URL.</li>\n</ul>\n</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the download is terminated (or on user action if <i>content</i> is None).<br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the button if it has one.</li><li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has two keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li><li>args: a list of two elements: <i>args[0]</i> reflects the <i>name</i> property and <i>args[1]</i> holds the file URL.</li></ul></li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -1125,8 +1149,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of the function that will be triggered.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that will be triggered.<br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the button if it has one.</li><li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -1187,7 +1211,7 @@
                         "name": "content",
                         "default_property": true,
                         "type": "dynamic(Union[path,URL,file,ReadableBuffer])",
-                        "doc": "The image source.<br/>If a buffer is provided (string, array of bytes...), and in order to prevent the bandwidth to be consumed too much, the way the image data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the size of the buffer is smaller than this setting, then the raw content is generated as a\n  data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li>\n<li>If the size of the buffer is greater than this setting, then it is transferred through a temporary\n  file.</li>\n</ul>"
+                        "doc": "The image source.<br/>If a buffer is provided (string, array of bytes...), and in order to prevent the bandwidth to be consumed too much, the way the image data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the size of the buffer is smaller than this setting, then the raw content is generated as a\n  data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li><li>If the size of the buffer is greater than this setting, then it is transferred through a temporary\n  file.</li></ul>"
                     },
                     {
                         "name": "label",
@@ -1196,8 +1220,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when the user clicks on the image.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user clicks on the image.<br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the button if it has one.</li><li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -1244,7 +1268,7 @@
                         "name": "type",
                         "default_value": "\"circular\"",
                         "type": "str",
-                        "doc": "The type of the gauge.<br/>Possible values are:\n<ul>\n<li>\"none\"</li>\n<li>\"circular\"</li>\n<li>\"linear\"</li></ul>Setting this value to \"none\" remove the gauge."
+                        "doc": "The type of the gauge.<br/>Possible values are:\n<ul>\n<li>\"none\"</li><li>\"circular\"</li><li>\"linear\"</li></ul>Setting this value to \"none\" remove the gauge."
                     },
                     {
                         "name": "min",
@@ -1377,7 +1401,7 @@
                         "name": "title_anchor",
                         "type": "str",
                         "default_value": "\"bottom\"",
-                        "doc": "The anchor of the title.<br/>Possible values are:\n<ul>\n<li>\"bottom\"</li>\n<li>\"top\"</li>\n<li>\"left\"</li>\n<li>\"right\"</li>\n<li>\"none\" (no title is displayed)</li>\n</ul>"
+                        "doc": "The anchor of the title.<br/>Possible values are:\n<ul>\n<li>\"bottom\"</li><li>\"top\"</li><li>\"left\"</li><li>\"right\"</li><li>\"none\" (no title is displayed)</li></ul>"
                     },
                     {
                         "name": "render",
@@ -1504,8 +1528,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of the function that is triggered when a menu option is selected.<br/><br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: List where the first element contains the id of the selected option.</li>\n</ul>\n</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when a menu option is selected.<br/><br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the button, if it has one.</li><li>payload (dict): a dictionary containing details about the callback invocation, with the following keys:<ul>\n<li>action: the name of the action that triggered this callback.</li><li>args: a list where the first element contains the identifier of the selected option.</li></ul></li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -1536,7 +1560,7 @@
                         "name": "lov",
                         "default_property": true,
                         "type": "dict[str, Any]",
-                        "doc": "The list of pages. The keys should be:\n<ul>\n<li>page id (start with \"/\")</li>\n<li>or full URL</li>\n</ul>\nThe values are labels. See the <a href=\"../../../../../userman/gui/binding/#list-of-values\">section on List of Values</a> for details."
+                        "doc": "The list of pages. The keys should be:\n<ul>\n<li>page id (start with \"/\")</li><li>or full URL</li></ul>\nThe values are labels. See the <a href=\"../../../../../userman/gui/binding/#list-of-values\">section on List of Values</a> for more details."
                     }
                 ]
             }
@@ -1579,8 +1603,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of the function that is triggered when the dialog button is pressed.<br/><br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: a list with three elements:\n<ul><li>The first element is the username</li><li>The second element is the password</li><li>The third element is the current page name</li></ul></li></li>\n</ul>\n</li>\n</ul><br/>When the button is pressed, and if this property is not set, Taipy will try to find a callback function called <i>on_login()</i> and invoke it with the parameters listed above.",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the dialog button is pressed.<br/><br/>This function is invoked with the following parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the button if it has one.</li><li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li><li>args: a list with three elements:\n<ul><li>The first element is the username</li><li>The second element is the password</li><li>The third element is the current page name</li></ul></li></li></ul></li></ul><br/>When the button is pressed, and if this property is not set, Taipy will try to find a callback function called <i>on_login()</i> and invoke it with the parameters listed above.",
                         "signature": [
                             [
                                 "state",
@@ -1622,7 +1646,7 @@
                     {
                         "name": "users",
                         "type": "dynamic(list[Union[str,Icon]])",
-                        "doc": "The list of users. See the <a href=\"../../../../../userman/gui/binding/#list-of-values\">section on List of Values</a> for details."
+                        "doc": "The list of users. See the <a href=\"../../../../../userman/gui/binding/#list-of-values\">section on List of Values</a> for more details."
                     },
                     {
                         "name": "sender_id",
@@ -1638,8 +1662,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when the user enters a new message.<br/>All the parameters of that function are optional:\n<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li>\n<li><i>var_name</i> (str): the name of the variable bound to the <i>messages</i> property.</li>\n<li><i>payload</i> (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li><i>action</i>: the name of the action that triggered this callback.</li>\n<li><i>args</i> (list): A list composed of a reason (\"click\" or \"Enter\"), the variable name, message, the user identifier of the sender.</li></ul></li></ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user enters a new message.<br/>This function is invoked with the following parameters:<ul>\n<li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>var_name</i> (str): the name of the variable bound to the <i>messages</i> property.</li><li><i>payload</i> (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li><i>action</i>: the name of the action that triggered this callback.</li><li><i>args</i> (list): a list composed of a reason (\"click\" or \"Enter\"), the variable name, the message, and the user identifier of the sender.</li></ul></li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -1676,7 +1700,7 @@
                         "name": "mode",
                         "type": "str",
                         "default_value": "\"markdown\"",
-                        "doc": "Define the way the messages are processed:\n<ul><li>&quot;raw&quot; no processing</li><li>&quot;pre&quot;: keeps spaces and new lines</li><li>&quot;markdown&quot; or &quot;md&quot;: basic support for Markdown.</li></ul>"
+                        "doc": "Define the way the messages are processed when they are displayed:\n<ul><li>&quot;raw&quot; no processing</li><li>&quot;pre&quot;: keeps spaces and new lines</li><li>&quot;markdown&quot; or &quot;md&quot;: basic support for Markdown.</li></ul>"
                     }
                 ]
             }
@@ -1796,8 +1820,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "Name of a function triggered when a button is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the dialog if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: a list where the first element contains the index of the selected label.</li>\n</ul>\n</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function triggered when a button is pressed.<br/>This function is invoked with the following parameters:<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the dialog if it has one.</li><li>payload (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li><li>args: a list where the first element contains the index of the selected label.</li></ul></li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -1849,7 +1873,7 @@
                         "default_property": true,
                         "type": "str",
                         "default_value": "\"1 1\"",
-                        "doc": "The list of weights for each column.<br/>For example, \"1 2\" creates a 2 column grid:\n<ul>\n<li>1fr</li>\n<li>2fr</li>\n</ul><br/>The creation of multiple same size columns can be simplified by using the multiply sign eg. \"5*1\" is equivalent to \"1 1 1 1 1\"."
+                        "doc": "The list of weights for each column.<br/>For example, \"1 2\" creates a 2 column grid:\n<ul>\n<li>1fr</li><li>2fr</li></ul><br/>The creation of multiple same size columns can be simplified by using the multiply sign eg. \"5*1\" is equivalent to \"1 1 1 1 1\"."
                     },
                     {
                         "name": "columns[mobile]",
@@ -1885,8 +1909,8 @@
                     },
                     {
                         "name": "on_close",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when this pane is closed (if the user clicks outside of it or presses the Esc key).<br/>All parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the close button if it has one.</li>\n</ul><br/>If this property is not set, no function is called when this pane is closed.",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when this pane is closed (if the user clicks outside of it or presses the Esc key).<br/>This function is invoked with the following parameters:<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (optional[str]): the identifier of the <i>close</i> button if it has one.</li></ul><br/>If this property is not set, no function is called when this pane is closed.",
                         "signature": [
                             [
                                 "state",
@@ -1962,7 +1986,7 @@
                     {
                         "name": "lov",
                         "type": "dict[str, Any]",
-                        "doc": "The list of values. See the <a href=\"../../../../../userman/gui/binding/#list-of-values\">section on List of Values</a> for details."
+                        "doc": "The list of values. See the <a href=\"../../../../../userman/gui/binding/#list-of-values\">section on List of Values</a> for more details."
                     },
                     {
                         "name": "adapter",
@@ -1991,8 +2015,8 @@
                 "properties": [
                     {
                         "name": "on_change",
-                        "type": "Callable",
-                        "doc": "The name of a function that is triggered when the value is updated.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>var_name (str): the variable name.</li>\n<li>value (Any): the new value.</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the value is updated.<br/>This function is invoked with the following parameters:<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>var_name (str): the variable name.</li><li>value (Any): the new value.</li></ul>",
                         "signature": [
                             [
                                 "state",
@@ -2057,8 +2081,8 @@
                     },
                     {
                         "name": "on_action",
-                        "type": "Callable",
-                        "doc": "Name of a function that is triggered when a specific key is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the control if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args (list):\n<ul><li>key name</li><li>variable name</li><li>current value</li></ul>\n</li>\n</ul>\n</li>\n</ul>",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when a specific key is pressed.<br/>This function is invoked with the following parameters:<ul>\n<li>state (<code>State^</code>): the state instance.</li><li>id (str): the identifier of the control if it has one.</li><li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li><li>args (list):\n<ul><li>key name</li><li>variable name</li><li>current value</li></ul></li></ul></li></ul>",
                         "signature": [
                             [
                                 "state",

+ 0 - 0
taipy/py.typed