Skip to content

Commit

Permalink
Replace Context with shared functions
Browse files Browse the repository at this point in the history
  • Loading branch information
aryanpingle committed Jul 6, 2023
1 parent d1337d2 commit e9e2c30
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 89 deletions.
106 changes: 46 additions & 60 deletions src/client/lazy-app/Compress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ import WorkerBridge from '../worker-bridge';
import { resize } from 'features/processors/resize/client';
import type SnackBarElement from 'shared/custom-els/snack-bar';
import { drawableToImageData } from '../util/canvas';
import Modal, { ModalMessage } from '../Modal';
import ModalContext from '../Modal/modal-context';
import { linkRef } from 'shared/prerendered-app/util';
import Modal from '../Modal';

export type OutputType = EncoderType | 'identity';

Expand Down Expand Up @@ -327,8 +325,6 @@ export default class Compress extends Component<Props, State> {
/** For debouncing calls to updateImage for each side. */
private updateImageTimeout?: number;

private modal?: Modal;

constructor(props: Props) {
super(props);
this.widthQuery.addListener(this.onMobileWidthChange);
Expand Down Expand Up @@ -920,12 +916,6 @@ export default class Compress extends Component<Props, State> {
});
}

private showModal(modalMessage: ModalMessage) {
if (!this.modal) return;

this.modal.showModal(modalMessage);
}

render(
{ onBack }: Props,
{ loading, sides, source, mobileView, preprocessorState }: State,
Expand Down Expand Up @@ -979,55 +969,51 @@ export default class Compress extends Component<Props, State> {

return (
<div class={style.compress}>
<ModalContext.Provider
value={(message: ModalMessage) => this.showModal(message)}
>
<Output
source={source}
mobileView={mobileView}
leftCompressed={leftImageData}
rightCompressed={rightImageData}
leftImgContain={leftImgContain}
rightImgContain={rightImgContain}
preprocessorState={preprocessorState}
onPreprocessorChange={this.onPreprocessorChange}
/>
<button class={style.back} onClick={onBack}>
<svg viewBox="0 0 61 53.3">
<title>Back</title>
<path
class={style.backBlob}
d="M0 25.6c-.5-7.1 4.1-14.5 10-19.1S23.4.1 32.2 0c8.8 0 19 1.6 24.4 8s5.6 17.8 1.7 27a29.7 29.7 0 01-20.5 18c-8.4 1.5-17.3-2.6-24.5-8S.5 32.6.1 25.6z"
/>
<path
class={style.backX}
d="M41.6 17.1l-2-2.1-8.3 8.2-8.2-8.2-2 2 8.2 8.3-8.3 8.2 2.1 2 8.2-8.1 8.3 8.2 2-2-8.2-8.3z"
/>
</svg>
</button>
{mobileView ? (
<div class={style.options}>
<multi-panel class={style.multiPanel} open-one-only>
<div class={style.options1Theme}>{results[0]}</div>
<div class={style.options1Theme}>{options[0]}</div>
<div class={style.options2Theme}>{results[1]}</div>
<div class={style.options2Theme}>{options[1]}</div>
</multi-panel>
</div>
) : (
[
<div class={style.options1} key="options1">
{options[0]}
{results[0]}
</div>,
<div class={style.options2} key="options2">
{options[1]}
{results[1]}
</div>,
]
)}
</ModalContext.Provider>
<Modal ref={linkRef(this, 'modal')}></Modal>
<Output
source={source}
mobileView={mobileView}
leftCompressed={leftImageData}
rightCompressed={rightImageData}
leftImgContain={leftImgContain}
rightImgContain={rightImgContain}
preprocessorState={preprocessorState}
onPreprocessorChange={this.onPreprocessorChange}
/>
<button class={style.back} onClick={onBack}>
<svg viewBox="0 0 61 53.3">
<title>Back</title>
<path
class={style.backBlob}
d="M0 25.6c-.5-7.1 4.1-14.5 10-19.1S23.4.1 32.2 0c8.8 0 19 1.6 24.4 8s5.6 17.8 1.7 27a29.7 29.7 0 01-20.5 18c-8.4 1.5-17.3-2.6-24.5-8S.5 32.6.1 25.6z"
/>
<path
class={style.backX}
d="M41.6 17.1l-2-2.1-8.3 8.2-8.2-8.2-2 2 8.2 8.3-8.3 8.2 2.1 2 8.2-8.1 8.3 8.2 2-2-8.2-8.3z"
/>
</svg>
</button>
{mobileView ? (
<div class={style.options}>
<multi-panel class={style.multiPanel} open-one-only>
<div class={style.options1Theme}>{results[0]}</div>
<div class={style.options1Theme}>{options[0]}</div>
<div class={style.options2Theme}>{results[1]}</div>
<div class={style.options2Theme}>{options[1]}</div>
</multi-panel>
</div>
) : (
[
<div class={style.options1} key="options1">
{options[0]}
{results[0]}
</div>,
<div class={style.options2} key="options2">
{options[1]}
{results[1]}
</div>,
]
)}
<Modal></Modal>
</div>
);
}
Expand Down
64 changes: 35 additions & 29 deletions src/client/lazy-app/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { h, Component, VNode, Fragment } from 'preact';
import * as style from './style.css';
import 'add-css:./style.css';
import { linkRef } from 'shared/prerendered-app/util';
import { cleanSet } from '../util/clean-modify';

interface Props {}

Expand All @@ -26,66 +27,71 @@ export default class Modal extends Component<Props, State> {
shown: false,
};

private modal?: HTMLDialogElement;
private dialogElement!: HTMLDialogElement;
static modalInstance?: Modal | undefined;

componentDidMount() {
// Once a transition ends, check if the modal should be closed (not just hidden)
// dialog.close() instantly hides the modal, so we call it AFTER fading it out i.e. on transition end
this.modal?.addEventListener(
this.dialogElement.addEventListener(
'transitionend',
this._closeOnTransitionEnd.bind(this),
);
this.modal?.setAttribute('inert', 'enabled');
this.dialogElement.setAttribute('inert', 'enabled');

Modal.modalInstance = this;
}

private _closeOnTransitionEnd() {
// If modal does not exist
// Or if it's not being closed at the moment
if (!this.modal || !this.modal.classList.contains(style.modalClosing))
if (
!this.dialogElement ||
!this.dialogElement.classList.contains(style.modalClosing)
)
return;

this.modal.close();
this.modal.classList.remove(style.modalClosing);
this.modal.setAttribute('inert', 'enabled');
this.dialogElement.close();
this.dialogElement.classList.remove(style.modalClosing);
this.dialogElement.setAttribute('inert', 'enabled');
}

static showModal(message: ModalMessage) {
Modal.modalInstance?._showModal(message);
}

/**
* Function to set up the modal and show it
*/
showModal(message: ModalMessage) {
if (!this.modal) return;
static hideModal() {
Modal.modalInstance?._hideModal();
}

private _showModal(message: ModalMessage) {
if (!this.dialogElement) throw Error('Modal missing');

this.setState({
message: message,
shown: true,
});

// Actually show the modal
this.modal.removeAttribute('inert');
this.modal.showModal();
this.dialogElement.removeAttribute('inert');
this.dialogElement.showModal();
}

/**
* Function to hide the modal with a fade-out transition
* Adds the `modal--closing` class which is removed on transition end
*/
hideModal() {
if (!this.modal || !this.modal.open) return;
private _hideModal() {
if (!this.dialogElement || !this.dialogElement.open)
throw Error('Modal missing / hidden');

// Make the modal fade out
this.modal.classList.add(style.modalClosing);
this.dialogElement.classList.add(style.modalClosing);

this.setState({
message: { ...this.state.message },
shown: false,
});
this.setState(cleanSet(this.state, 'shown', false));
}

private _onKeyDown(e: KeyboardEvent) {
// Default behaviour of <dialog> closes it instantly when you press Esc
// So we hijack it to smoothly hide the modal
if (e.key === 'Escape' || e.keyCode == 27) {
this.hideModal();
if (e.key === 'Escape') {
this._hideModal();
e.preventDefault();
e.stopImmediatePropagation();
}
Expand All @@ -94,13 +100,13 @@ export default class Modal extends Component<Props, State> {
render({}: Props, { message, shown }: State) {
return (
<dialog
ref={linkRef(this, 'modal')}
ref={linkRef(this, 'dialogElement')}
onKeyDown={(e) => this._onKeyDown(e)}
>
<header class={style.header}>
<span class={style.modalIcon}>{message.icon}</span>
<span class={style.modalTitle}>{message.title}</span>
<button class={style.closeButton} onClick={() => this.hideModal()}>
<button class={style.closeButton} onClick={() => this._hideModal()}>
<svg viewBox="0 0 480 480" fill="currentColor">
<path
d="M119.356 120L361 361M360.644 120L119 361"
Expand Down

0 comments on commit e9e2c30

Please sign in to comment.