diff --git a/examples/simple-app/src/App.module.css b/examples/simple-app/src/App.module.css
index 3ee1159e..0245df79 100644
--- a/examples/simple-app/src/App.module.css
+++ b/examples/simple-app/src/App.module.css
@@ -7,4 +7,4 @@
align-items: center;
justify-content: center;
font-size: 1rem;
-}
\ No newline at end of file
+}
diff --git a/shell/src/PluginLoader.jsx b/shell/src/PluginLoader.jsx
index ee1178df..03d7233a 100644
--- a/shell/src/PluginLoader.jsx
+++ b/shell/src/PluginLoader.jsx
@@ -10,64 +10,49 @@ const PluginResizeInner = ({
propsFromParent,
resizePluginHeight,
resizePluginWidth,
+ clientWidth,
}) => {
- const divRef = useRef()
- const innerDivRef = useRef()
+ const resizeDivRef = useRef()
+
useEffect(() => {
- if (divRef && divRef.current && resizePluginHeight) {
- const container = divRef.current
+ if (resizeDivRef?.current) {
+ const resizeDiv = resizeDivRef.current
const resizeObserver = new ResizeObserver(() => {
- // the additional pixels currently account for possible horizontal scroll bar
- resizePluginHeight(container.offsetHeight + 20)
+ if (resizePluginHeight) {
+ // offsetHeight takes into account possible scrollbar size
+ resizePluginHeight(resizeDiv.offsetHeight)
+ }
+ if (resizePluginWidth) {
+ resizePluginWidth(resizeDiv.scrollWidth)
+ }
})
- resizeObserver.observe(container)
- return () => {
- resizeObserver.unobserve(container)
- resizeObserver.disconnect()
- }
- }
- }, [resizePluginHeight])
- const previousWidth = useRef()
+ resizeObserver.observe(resizeDiv)
- const resetWidth = useCallback(() => {
- const currentWidth = innerDivRef.current?.scrollWidth
- if (resizePluginWidth && currentWidth) {
- if (
- previousWidth.current &&
- Math.abs(currentWidth - previousWidth.current) > 20
- ) {
- resizePluginWidth(currentWidth + 20)
+ return () => {
+ resizeObserver.unobserve(resizeDiv)
+ resizeObserver.disconnect()
}
- previousWidth.current = currentWidth
- }
- requestAnimationFrame(resetWidth)
- }, [resizePluginWidth])
-
- useEffect(() => {
- if (resizePluginWidth) {
- requestAnimationFrame(resetWidth)
}
- }, [resetWidth, resizePluginWidth])
+ }, [resizePluginHeight, resizePluginWidth])
- // inner div disables margin collapsing which would prevent computing correct height
+ // For the width to be content-driven, the clientWidth needs to be specified
+ // so that width is not just 'auto'. Then, when content resizes, it will
+ // actually trigger the resize observer, updating the parent's iframe size
return (
-
-
+
+
)
}
PluginResizeInner.propTypes = {
D2App: PropTypes.object,
+ clientWidth: PropTypes.string,
config: PropTypes.object,
propsFromParent: PropTypes.object,
resizePluginHeight: PropTypes.func,
@@ -80,15 +65,13 @@ const PluginInner = ({
propsFromParent,
resizePluginHeight,
resizePluginWidth,
+ clientWidth,
}) => {
+ // If a resize function isn't defined, that value is container-driven and
+ // doesn't need resizing.
+ // If neither are defined, then don't need the ResizeInner
if (!resizePluginHeight && !resizePluginWidth) {
- return (
-
- )
+ return
}
return (
)
}
PluginInner.propTypes = {
D2App: PropTypes.object,
+ clientWidth: PropTypes.string,
config: PropTypes.object,
propsFromParent: PropTypes.object,
resizePluginHeight: PropTypes.func,
@@ -116,8 +101,15 @@ export const PluginLoader = ({ config, requiredProps, D2App }) => {
const [showAlertsInPlugin, setShowAlertsInPlugin] = useState(false)
const [onPluginError, setOnPluginError] = useState(() => () => {})
const [clearPluginError, setClearPluginError] = useState(() => () => {})
+ // These two can be populated with callbacks from the parent. They can be
+ // called with a new value for the respective dimension, which will be set
+ // on the iframe element to resize the plugin
const [resizePluginHeight, setResizePluginHeight] = useState(null)
const [resizePluginWidth, setResizePluginWidth] = useState(null)
+ // This value will be used as the 'width' property of the div wrapping the
+ // app inside the plugin. Gets set by a prop from the parent.
+ // See the Plugin docs or the PluginResizeInner component for more info
+ const [clientWidth, setClientWidth] = useState(null)
const receivePropsFromParent = useCallback(
(event) => {
@@ -127,11 +119,10 @@ export const PluginLoader = ({ config, requiredProps, D2App }) => {
setCommunicationReceived,
alertsAdd,
showAlertsInPlugin,
- height,
setPluginHeight,
- width,
setPluginWidth,
onError,
+ clientWidth: clientWidthFromParent,
...explicitlyPassedProps
} = receivedProps
@@ -173,12 +164,21 @@ export const PluginLoader = ({ config, requiredProps, D2App }) => {
setShowAlertsInPlugin(Boolean(showAlertsInPlugin))
}
- if (!height && setPluginHeight) {
+ // if these resize callbacks are defined, then that dimension isn't
+ // fixed or container-driven; add them to the props list here.
+ // It will be called by a resize observer in ResizePluginInner
+ if (setPluginHeight) {
setResizePluginHeight(() => (height) => setPluginHeight(height))
}
+ // same as height
+ if (setPluginWidth) {
+ setResizePluginWidth(() => (width) => {
+ setPluginWidth(width)
+ })
+ }
- if (!width && setPluginWidth) {
- setResizePluginWidth(() => (width) => setPluginWidth(width))
+ if (clientWidthFromParent) {
+ setClientWidth(clientWidthFromParent)
}
},
[
@@ -189,6 +189,7 @@ export const PluginLoader = ({ config, requiredProps, D2App }) => {
setShowAlertsInPlugin,
setResizePluginHeight,
setResizePluginWidth,
+ setClientWidth,
]
)
@@ -247,6 +248,7 @@ export const PluginLoader = ({ config, requiredProps, D2App }) => {
propsFromParent={propsFromParent}
resizePluginHeight={resizePluginHeight}
resizePluginWidth={resizePluginWidth}
+ clientWidth={clientWidth}
/>