Skip to content

Support @mui/lab in MaterialUIComponent #190

@MarcSkovMadsen

Description

@MarcSkovMadsen

On enhancement/reference-example branch

I have merged with current main branch.

When trying to convert the Timeline in #143 from MaterialPaneBase component to new MaterialUIComponent component I see

Image

es-module-shims.min.js:7 
 
 GET https://cdn.holoviz.org/panel-material-ui/v0.0.1a17/react-shim.js 403 (Forbidden)
bokeh.min.js?v=5b74d…21454cb1b44d480:164 
 Error rendering Bokeh items: TypeError: 403  https://cdn.holoviz.org/panel-material-ui/v0.0.1a17/react-shim.js imported from blob:https://mnr-jupyterhub.de-prod.dk/3bae27a3-3762-4b49-a4d5-d72fdc3317b1
    at De (es-module-shims.min.js:7:14947)
    at async Be (es-module-shims.min.js:7:15089)
    at async es-module-shims.min.js:7:16373
    at async ve (es-module-shims.min.js:7:10200)
    at async Promise.all (index 0)
    at async ve (es-module-shims.min.js:7:10210)
    at async Ce (es-module-shims.min.js:7:12077)
    at async a.lazy_initialize (panel.min.js?v=83f03…0ecec862464:51:3556)
    at async a (bokeh.min.js?v=5b74d…4cb1b44d480:222:892)
    at async t.build_views (bokeh.min.js?v=5b74d…4cb1b44d480:222:410)
es-module-shims.min.js:7 
 
 GET https://cdn.holoviz.org/panel-material-ui/v0.0.1a17/material-ui-styles-shim.js 403 (Forbidden)
es-module-shims.min.js:7 
 
 GET https://cdn.holoviz.org/panel-material-ui/v0.0.1a17/material-ui-shim.js 403 (Forbidden)

On main branch

When trying to create minimum, reproducible issue

import panel as pn
import panel_material_ui as pmu

import param

class Timeline(pmu.MaterialUIComponent):
    """Material‑UI **Timeline** component for Panel.

    References:

    - https://mui.com/material-ui/react-timeline/

    Example:

    >>> config = [
    ...     {"content_title": "Eat", "content": "Because you need strength", "opposite": "08:30", "color": "grey",   "variant": "filled", "icon": "fastfood"},
    ...     {"content_title": "Code", "content": "Because it's awesome!", "opposite": "09:00", "color": "primary", "variant": "filled", "icon": "laptop_mac"},
    ...     {"content_title": "Sleep", "content": "Because you need rest", "opposite": "09:30", "color": "secondary",   "variant": "outlined", "icon": "hotel"},
    ...     {"content_title": "Repeat", "content": "Because this is the life you love!", "opposite": "11:00", "color": "success",      "variant": "filled", "icon": "repeat"},
    ... ]
    >>> Timeline(object=config, width=600)
    """  # noqa: E501
    object = param.List(default=[], doc="""
    A list of dictionaries, each mapping directly onto a `TimelineItem` row.
    Supported keys:

    | key               | type | default | description                                                                                                       |
    |-------------------|------|---------|-------------------------------------------------------------------------------------------------------------------|
    | **content_title** | str  | *None*  | Header of `TimelineContent`.                                                                                      |
    | **content**       | str  | *None*  | Body of `TimelineContent`.                                                                                        |
    | **opposite_title**| str  | *None*  | Header of `TimelineOppositeContent`.                                                                              |
    | **opposite**      | str  | *None*  | Body of `TimelineOppositeContent`.                                                                                |
    | **color**         | str  | primary | Color prop of `TimelineDot`.                                                                                      |
    | **variant**       | str  | filled  | Variant prop of `TimelineDot` (filled/ outlined).                                                                 |
    | **icon**          | str  | *None*  | Lowercase name of `Icon`.                                                                                         |
    | **disable_dot**   | bool | *None*  | If `True`, the `Icon` is shown standalone and not inside the `TimelineDot`.                                       |
    """)
    object = param.List()

    position = param.Selector(default="right", objects=[
      'alternate-reverse',
      'alternate',
      'left',
      'right',
    ], doc="""The position of the content/ opposite content.""")

    def __init__(self, object: list | None=None, **params):
        super().__init__(object=object, **params)

    _esm_base = "script.jsx"

    _importmap = {
      "imports": {
          "@mui/lab": "https://esm.sh/@mui/[email protected]",
      }
    }

pn.extension()

timeline_config = [
    {"content_title": "$2400, Design changes", "content": "22 DEC 7:20 PM", "color": "success", "icon": "notifications", "disable_dot": True},
    {"content_title": "New order #1832412", "content": "21 DEC 11 PM", "color": "error", "icon": "code", "disable_dot": True},
    {"content_title": "Server payments for April", "content": "21 DEC 9:34 PM", "color": "primary", "icon": "shopping_cart", "disable_dot": True},
    {"content_title": "New card added for order #4395133", "content": "20 DEC 2:20 AM", "color": "warning", "icon": "credit_card", "disable_dot": True},
    {"content_title": "Unlock packages for development", "content": "18 DEC 4:54 AM", "color": "error", "icon": "key", "disable_dot": True},
    {"content_title": "New order #9583120", "content": "17 DEC", "color": "dark", "icon": "payments", "disable_dot": True},
]
sx = {
    "& .MuiTimelineItem-root:before": {
        "flex": 0,
        "padding-left": 10,
    },
}
pmu.Paper(
    "#### Orders overview\n\n**24%** this month",
    Timeline(object=timeline_config, sizing_mode="stretch_width", sx=sx),
    margin=10,
    height=550,
    width=500,
).servable()
import {
    Timeline as MUITimeline,
    TimelineItem,
    TimelineSeparator,
    TimelineConnector,
    TimelineContent,
    TimelineOppositeContent,
    TimelineDot,
  } from "@mui/lab";
  import {Icon} from "@mui/material"
  import Typography from "@mui/material/Typography";
  
  export function render({model}) {
    const [items] = model.useState("object")
    const [position] = model.useState("position")
    const [sx] = model.useState("sx")
  
    return (
      <MUITimeline position={position} sx={sx}>
        {items.map((item, idx) => (
          <TimelineItem key={idx}>
            {(item.opposite !== undefined || item.opposite_title !== undefined) && (
              <TimelineOppositeContent sx={item.icon ? {m: "auto 0"} : { }} align="right" variant="body2" color="text.secondary">
                <Typography variant="h6" component="span">
                  {item.opposite_title}
                </Typography>
                <Typography>
                  {item.opposite}
                </Typography>
              </TimelineOppositeContent>
            )}
            <TimelineSeparator>
              {(item.disable_dot && item.icon) ? (
                <Icon sx={{margin: 1}} color={item.color || "grey"}>{item.icon}</Icon>
              ) : (
                <TimelineDot
                  color={item.color || "grey"}
                  variant={item.variant || "filled"}
                >
                  {item.icon !== undefined && (
                    <Icon sx={{margin: 1}}>{item.icon}</Icon>
                  )}
                </TimelineDot>
              )}
              {idx < items.length - 1 && <TimelineConnector />}
            </TimelineSeparator>
            {(item.content !== undefined || item.content_title !== undefined) && (
              <TimelineContent sx={item.icon ? {m: "auto 0"} : { }}>
                <Typography variant="h6" component="span">
                  {item.content_title}
                </Typography>
                <Typography>{item.content}</Typography>
              </TimelineContent>
            )}
          </TimelineItem>
        ))}
      </MUITimeline>
    )
  }

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions