Skip to content

Commit

Permalink
Merge next in main (#544)
Browse files Browse the repository at this point in the history
* fix: fix export image rendering (#543)
  • Loading branch information
riccardoperra authored Jun 17, 2023
1 parent 08c8828 commit 93e590d
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 36 deletions.
17 changes: 15 additions & 2 deletions apps/codeimage/src/components/CustomEditor/PreviewExportEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,30 @@ function syncDispatch(tr: Transaction, other: EditorView) {

const CustomEditor = lazy(() => import('./CustomEditor'));

export default function PreviewExportEditor() {
interface PreviewExportEditorProps {
onSetEditorView(editorView: EditorView | undefined): void;
}

export default function PreviewExportEditor(props: PreviewExportEditorProps) {
const [editorView, setEditorView] = createSignal<EditorView>();

createEffect(
on(editorView, editorView => {
if (!editorView) return;
getRootEditorStore().canvasEditorEvents.listen(tr => {
setTimeout(() => syncDispatch(tr, editorView), 250);
setInterval(() => editorView.requestMeasure());
});
}),
);

return <CustomEditor onEditorViewChange={setEditorView} readOnly={true} />;
return (
<CustomEditor
onEditorViewChange={editorView => {
props.onSetEditorView(editorView);
setEditorView(editorView);
}}
readOnly={true}
/>
);
}
1 change: 0 additions & 1 deletion apps/codeimage/src/components/Frame/Frame.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export const previewPortal = style({
width: 'auto',
height: 'auto',
opacity: 0,
transform: `scale(0.01)`,
transformOrigin: 'left top',
});

Expand Down
3 changes: 2 additions & 1 deletion apps/codeimage/src/components/Frame/PreviewFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
VoidProps,
} from 'solid-js';
import {Portal} from 'solid-js/web';
import {setPreviewEditorView} from '../../hooks/export-snippet';
import {useHotkey} from '../../hooks/use-hotkey';
import {DynamicTerminal} from '../Terminal/DynamicTerminal/DynamicTerminal';
import * as styles from './Frame.css';
Expand Down Expand Up @@ -121,7 +122,7 @@ export function PreviewFrame(props: VoidProps<PreviewFrameProps>) {
themeId={editor.state.options.themeId}
>
<Show when={getActiveEditorStore().editor()}>
<PreviewExportEditor />
<PreviewExportEditor onSetEditorView={setPreviewEditorView} />
</Show>
</DynamicTerminal>
</div>
Expand Down
9 changes: 3 additions & 6 deletions apps/codeimage/src/components/Toolbar/ExportButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ import {
Show,
untrack,
} from 'solid-js';
import {
ExportExtension,
ExportMode,
useExportImage,
} from '../../hooks/use-export-image';
import {useExportSnippet} from '../../hooks/export-snippet';
import {ExportExtension, ExportMode} from '../../hooks/use-export-image';
import {useHotkey} from '../../hooks/use-hotkey';
import {AppLocaleEntries} from '../../i18n';
import {DownloadIcon} from '../Icons/Download';
Expand All @@ -52,7 +49,7 @@ export const ExportButton: Component<ExportButtonProps> = props => {
const modality = useModality();
const buttonSize = () => (modality === 'full' ? 'sm' : 'xs');
const [open, setOpen] = createSignal(false);
const [data, notify] = useExportImage();
const [data, notify] = useExportSnippet();

const label = () => t('toolbar.export');

Expand Down
5 changes: 3 additions & 2 deletions apps/codeimage/src/components/Toolbar/ExportNewTabButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {Button} from '@codeui/kit';
import {getUmami} from '@core/constants/umami';
import {useModality} from '@core/hooks/isMobile';
import {Component, createEffect, untrack} from 'solid-js';
import {ExportMode, useExportImage} from '../../hooks/use-export-image';
import {useExportSnippet} from '../../hooks/export-snippet';
import {ExportMode} from '../../hooks/use-export-image';
import {useHotkey} from '../../hooks/use-hotkey';
import {AppLocaleEntries} from '../../i18n';
import {ExternalLinkIcon} from '../Icons/ExternalLink';
Expand All @@ -19,7 +20,7 @@ export const ExportInNewTabButton: Component<ExportButtonProps> = props => {
const modality = useModality();
const [t] = useI18n<AppLocaleEntries>();

const [data, notify] = useExportImage();
const [data, notify] = useExportSnippet();

const label = () => t('toolbar.openNewTab');

Expand Down
48 changes: 48 additions & 0 deletions apps/codeimage/src/hooks/export-snippet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {EditorView} from '@codemirror/view';
import {createAsyncAction} from '@core/hooks/async-action';
import {Resource} from 'solid-js';
import {exportImage, ExportImagePayload} from './use-export-image';

type ViewState = {printing: boolean};

type InternalEditorView = EditorView & {
viewState?: ViewState;
measure?(): void;
};

export let previewEditorView!: EditorView;

export function setPreviewEditorView(editorView: EditorView) {
previewEditorView = editorView;
}

export function exportSnippet(options: ExportImagePayload) {
const editorView = previewEditorView as InternalEditorView;
if (editorView.viewState && editorView.measure) {
// We need to set the viewState `printing` property to true in order to render the entire code block
editorView.viewState.printing = true;
// Then we measure again the editor in order to render every block
editorView.measure();
}
return exportImage(options).finally(() => {
if (editorView.viewState) {
// At the end of the render we need to put the printing property to false
editorView.viewState.printing = false;
}
// Then we do a request measure since this event can be scheduled
editorView.requestMeasure();
});
}

export function useExportSnippet(): [
Resource<Blob | string | undefined>,
(data: ExportImagePayload) => void,
] {
const [data, {notify}] = createAsyncAction(
async (ref: ExportImagePayload) => {
return exportSnippet(ref);
},
);

return [data, notify];
}
19 changes: 1 addition & 18 deletions apps/codeimage/src/hooks/use-export-image.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import {type HtmlExportOptions} from '@codeimage/dom-export';
import {EXPORT_EXCLUDE} from '@core/directives/exportExclude';
import {createAsyncAction} from '@core/hooks/async-action';
import {useWebshare} from '@core/hooks/use-webshare';
import {isIOS} from '@solid-primitives/platform';
import download from 'downloadjs';
import {Resource} from 'solid-js';

function loadDomExport() {
return import('@codeimage/dom-export');
Expand All @@ -30,26 +28,11 @@ export interface ExportOptions {
quality: number;
}

interface ExportImagePayload {
export interface ExportImagePayload {
ref: HTMLElement | null | undefined;
options: ExportOptions;
}

export function useExportImage(): [
Resource<Blob | string | undefined>,
(data: ExportImagePayload) => void,
] {
const [data, {notify}] = createAsyncAction(
async (ref: ExportImagePayload) => {
// @bad Find another way to prevent flickering
await new Promise(r => setTimeout(r, 50));
return exportImage(ref);
},
);

return [data, notify];
}

function resolveMimeType(extension: ExportExtension): string {
switch (extension) {
case ExportExtension.jpeg:
Expand Down
11 changes: 5 additions & 6 deletions apps/codeimage/src/state/effects/onCopyToClipboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ import {toast} from '@codeimage/ui';
import {getUmami} from '@core/constants/umami';
import {catchError, EMPTY, exhaustMap, from, pipe, switchMap, tap} from 'rxjs';
import {getOwner, runWithOwner} from 'solid-js';
import {
exportImage,
ExportMode,
ExportOptions,
} from '../../hooks/use-export-image';
import {exportSnippet} from '../../hooks/export-snippet';
import {ExportMode, ExportOptions} from '../../hooks/use-export-image';
import {AppLocaleEntries} from '../../i18n';

interface CopyToClipboardEvent {
Expand All @@ -30,7 +27,9 @@ export const dispatchCopyToClipboard = effect<CopyToClipboardEvent>(
extension: exportSettings.get.extension,
};
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return from(runWithOwner(owner, () => exportImage({ref, options}))!).pipe(
return from(
runWithOwner(owner, () => exportSnippet({ref, options}))!,
).pipe(
switchMap(data => {
if (!(data instanceof Blob)) return EMPTY;
return from(
Expand Down

0 comments on commit 93e590d

Please sign in to comment.