Skip to content

Commit

Permalink
Rendered member login form in Shadow DOM instead of an iframe
Browse files Browse the repository at this point in the history
refs TryGhost#16960
Attempted to fix the issue of password managers not autofilling in the login form. Shadow DOM would allow to preserve the style encapsulation, while not requiring too many changes. Unfortunately, it did not work.
  • Loading branch information
vadimavdeev committed Aug 14, 2023
1 parent da919c8 commit ae20e51
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 25 deletions.
17 changes: 4 additions & 13 deletions apps/portal/src/components/Global.styles.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const GlobalStyles = `
/* Colors
/* ----------------------------------------------------- */
:root {
:host {
--black: #000;
--blackrgb: 0,0,0;
--grey0: #1d1d1d;
Expand All @@ -27,28 +27,19 @@ export const GlobalStyles = `
--darkerRed: #C50202;
--yellow: #FFDC15;
--green: #7FC724;
}
/* Globals
/* ----------------------------------------------------- */
html {
font-size: 62.5%;
height: 100%;
}
body {
margin: 0px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
font-size: 1.6rem;
height: 100%;
line-height: 1.6em;
font-weight: 400;
font-style: normal;
color: var(--grey2);
box-sizing: border-box;
overflow: hidden;
}
/* Globals
/* ----------------------------------------------------- */
button,
button span {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
Expand Down
8 changes: 4 additions & 4 deletions apps/portal/src/components/Notification.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import Frame from './Frame';
import ShadowRoot from './ShadowRoot';
import AppContext from '../AppContext';
import NotificationStyle from './Notification.styles';
import {ReactComponent as CloseIcon} from '../images/icons/close.svg';
Expand Down Expand Up @@ -216,7 +216,7 @@ export default class Notification extends React.Component {

renderFrameStyles() {
const styles = `
:root {
:host {
--brandcolor: ${this.context.brandColor}
}
` + NotificationStyle;
Expand All @@ -236,9 +236,9 @@ export default class Notification extends React.Component {
const {type, status, autoHide, duration} = this.state;
if (type && status) {
return (
<Frame style={frameStyle} title="portal-notification" head={this.renderFrameStyles()} className='gh-portal-notification-iframe' >
<ShadowRoot style={frameStyle} title="portal-notification" head={this.renderFrameStyles()} className='gh-portal-notification-iframe' >
<NotificationContent {...{type, status, autoHide, duration}} onHideNotification={e => this.onHideNotification(e)} />
</Frame>
</ShadowRoot>
);
}
return null;
Expand Down
8 changes: 4 additions & 4 deletions apps/portal/src/components/PopupModal.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import Frame from './Frame';
import ShadowRoot from './ShadowRoot';
import {hasMode} from '../utils/check-mode';
import AppContext from '../AppContext';
import {getFrameStyles} from './Frame.styles';
Expand Down Expand Up @@ -257,7 +257,7 @@ export default class PopupModal extends React.Component {
const {site} = this.context;
const FrameStyle = getFrameStyles({site});
const styles = `
:root {
:host {
--brandcolor: ${this.context.brandColor}
}
` + FrameStyle;
Expand Down Expand Up @@ -293,10 +293,10 @@ export default class PopupModal extends React.Component {

return (
<div style={Styles.modalContainer}>
<Frame style={frameStyle} title="portal-popup" head={this.renderFrameStyles()} dataTestId='portal-popup-frame'>
<ShadowRoot style={frameStyle} title="portal-popup" head={this.renderFrameStyles()} dataTestId='portal-popup-frame'>
<div className={className} onClick = {e => this.handlePopupClose(e)}></div>
<PopupContent isMobile={isMobile} />
</Frame>
</ShadowRoot>
</div>
);
}
Expand Down
52 changes: 52 additions & 0 deletions apps/portal/src/components/ShadowRoot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {Component} from 'react';
import {createPortal} from 'react-dom';

export default class ShadowRoot extends Component {
static isSupported() {
return (
typeof window !== 'undefined' &&
window.Element &&
window.Element.prototype.hasOwnProperty('attachShadow')
);
}

constructor(props) {
super(props);
this.state = { ready: false };
}

componentDidMount() {
this.shadowRoot = this.node.attachShadow({
mode: 'open',
});

this.setState({ ready: true });
}

render() {
const {
children,
head,
style = {},
dataTestId = '',
...rest
} = this.props;
return (
<div
data-testid={dataTestId}
ref={(node) => (this.node = node)}
style={style}
{...rest}
>
{this.state.ready &&
createPortal(
<>
{head}
{children}
</>,
this.shadowRoot
)}
</div>
);
}
}
8 changes: 4 additions & 4 deletions apps/portal/src/components/TriggerButton.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import Frame from './Frame';
import ShadowRoot from './ShadowRoot';
import MemberGravatar from './common/MemberGravatar';
import AppContext from '../AppContext';
import {ReactComponent as UserIcon} from '../images/icons/user.svg';
Expand Down Expand Up @@ -230,7 +230,7 @@ export default class TriggerButton extends React.Component {

renderFrameStyles() {
const styles = `
:root {
:host {
--brandcolor: ${this.context.brandColor}
}
` + TriggerButtonStyle;
Expand Down Expand Up @@ -259,9 +259,9 @@ export default class TriggerButton extends React.Component {
}

return (
<Frame dataTestId='portal-trigger-frame' className='gh-portal-triggerbtn-iframe' style={frameStyle} title="portal-trigger" head={this.renderFrameStyles()}>
<ShadowRoot dataTestId='portal-trigger-frame' className='gh-portal-triggerbtn-iframe' style={frameStyle} title="portal-trigger" head={this.renderFrameStyles()}>
<TriggerButtonContent isPopupOpen={showPopup} updateWidth={width => this.onWidthChange(width)} />
</Frame>
</ShadowRoot>
);
}
}

0 comments on commit ae20e51

Please sign in to comment.