Dash Mantine Components Release 2.4.1 - RichTextEditor image resize and anchorProps

:mega: Dash Mantine Components 2.4.1 is now available

  • Added withAlignedLabels prop to support offsetting the selected check icon in Select and MultiSelect #675 by @AnnMarieW.

  • Updated to Mantine (8.3.10), Recharts (2.15.4), and TipTap (3.14.0) #675

  • Added anchorProps to Anchor allowing to pass any valid attribute (like download) to the Anchor component. Thanks to first time contributor @jksinton for PR #676.


The update to the latest TipTap enables features like image resize in the RichTextEditor



import dash_mantine_components as dmc
from dash import Dash, html

app = Dash(__name__)

initial_content = """
<h2 style="text-align: center;">Resizable Image Demo</h2>
<p>Click and drag the resize handles on the image corners to resize:</p>
<img src="https://placehold.co/800x400/6366f1/white?text=Drag+corners+to+resize" />
<p>Try adding more images and resizing them!</p>
"""

app.layout = dmc.MantineProvider(
    html.Div([
        dmc.RichTextEditor(
            id="rte-resizable",
            html=initial_content,
            extensions=[
                "StarterKit",
                {
                    "Image": {
                        "resize": {
                            "enabled": True,
                            "directions": ["top", "bottom", "left", "right"],
                            "minWidth": 50,
                            "minHeight": 50,
                            "alwaysPreserveAspectRatio": True

                        }
                    }
                },
            ],
            # "alwaysPreserveAspectRatio": True,
            editable=True,
            toolbar={
                "sticky": True,
                "controlsGroups": [
                    ["Bold", "Italic", "Underline"],
                    ["H1", "H2", "H3"],
                    ["BulletList", "OrderedList"],
                ],
            },

        ),
    ], )
)

if __name__ == "__main__":
    app.run(debug=True)



Here’s the .css file

.tiptap :first-child {
  margin-top: 0;
}

.tiptap img {
  display: block;
}

.tiptap [data-resize-handle] {
  position: absolute;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.8);
  border-radius: 2px;
  z-index: 10;
}

.tiptap [data-resize-handle]:hover {
  background: rgba(0, 0, 0, 0.8);
}

/* Corner handles - always visible */
.tiptap [data-resize-handle='top-left'],
.tiptap [data-resize-handle='top-right'],
.tiptap [data-resize-handle='bottom-left'],
.tiptap [data-resize-handle='bottom-right'] {
  width: 8px;
  height: 8px;
}

.tiptap [data-resize-handle='top-left'] {
  top: -4px;
  left: -4px;
  cursor: nwse-resize;
}

.tiptap [data-resize-handle='top-right'] {
  top: -4px;
  right: -4px;
  cursor: nesw-resize;
}

.tiptap [data-resize-handle='bottom-left'] {
  bottom: -4px;
  left: -4px;
  cursor: nesw-resize;
}

.tiptap [data-resize-handle='bottom-right'] {
  bottom: -4px;
  right: -4px;
  cursor: nwse-resize;
}

/* Edge handles - hidden by default */
.tiptap [data-resize-handle='top'],
.tiptap [data-resize-handle='bottom'] {
  height: 6px;
  left: 8px;
  right: 8px;
  opacity: 0;
  transition: opacity 0.2s;
}

.tiptap [data-resize-handle='left'],
.tiptap [data-resize-handle='right'] {
  width: 6px;
  top: 8px;
  bottom: 8px;
  opacity: 0;
  transition: opacity 0.2s;
}

/* Show edge handles on wrapper hover */
.tiptap [data-resize-wrapper]:hover [data-resize-handle='top'],
.tiptap [data-resize-wrapper]:hover [data-resize-handle='bottom'],
.tiptap [data-resize-wrapper]:hover [data-resize-handle='left'],
.tiptap [data-resize-wrapper]:hover [data-resize-handle='right'] {
  opacity: 1;
}

.tiptap [data-resize-handle='top'] {
  top: -3px;
  cursor: ns-resize;
}

.tiptap [data-resize-handle='bottom'] {
  bottom: -3px;
  cursor: ns-resize;
}

.tiptap [data-resize-handle='left'] {
  left: -3px;
  cursor: ew-resize;
}

.tiptap [data-resize-handle='right'] {
  right: -3px;
  cursor: ew-resize;
}

.tiptap [data-resize-state='true'] [data-resize-wrapper] {
  outline: 1px solid rgba(0, 0, 0, 0.25);
  border-radius: 0.125rem;
}


5 Likes