Skip to content

Commit

Permalink
Merge pull request #572 from prezly/feature/dev-13410-pitch-aside-cli…
Browse files Browse the repository at this point in the history
…cking-log-coverage-from-coverage-placeholder

[DEV-13410] Fix - Coverage placeholder fixes
  • Loading branch information
kudlajz authored Oct 31, 2024
2 parents cfd80b5 + bab1d03 commit 100b24c
Show file tree
Hide file tree
Showing 16 changed files with 120 additions and 40 deletions.
12 changes: 10 additions & 2 deletions packages/slate-editor/src/components/SearchInput/Panel.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@
background: white;

border: 1px solid $grey-200;
border-bottom-left-radius: $border-radius-base;
border-bottom-right-radius: $border-radius-base;
overflow: hidden;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.11);

display: flex;
flex-direction: column;

&.top {
border-top-left-radius: $border-radius-base;
border-top-right-radius: $border-radius-base;
}

&.bottom {
border-bottom-left-radius: $border-radius-base;
border-bottom-right-radius: $border-radius-base;
}
}

.Footer {
Expand Down
13 changes: 11 additions & 2 deletions packages/slate-editor/src/components/SearchInput/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { type Placement } from '@popperjs/core';
import classNames from 'classnames';
import type { HTMLAttributes, ReactNode } from 'react';
import React, { forwardRef } from 'react';
Expand All @@ -7,12 +8,20 @@ import styles from './Panel.module.scss';
export interface Props extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
footer?: ReactNode;
placement?: Placement;
}

export const Panel = forwardRef<HTMLDivElement, Props>(
({ children, className, footer, ...attributes }, forwardedRef) => {
({ children, className, footer, placement = 'bottom', ...attributes }, forwardedRef) => {
return (
<div {...attributes} ref={forwardedRef} className={classNames(className, styles.Panel)}>
<div
{...attributes}
ref={forwardedRef}
className={classNames(className, styles.Panel, {
[styles.top]: placement === 'top',
[styles.bottom]: placement === 'bottom',
})}
>
{children}
{footer && <div className={styles.Footer}>{footer}</div>}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export function WithFooter() {
renderSuggestions={({ activeElement, query, suggestions, children }) => (
<SearchInput.Suggestions<string>
activeElement={activeElement}
origin={null}
query={query}
suggestions={suggestions}
footer={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export function SearchInput<T = unknown>({
suggestions,
onClose: handleClose,
onSelect,
origin: rootRef.current,
children: suggestions.map((suggestion) =>
renderSuggestion({
suggestion,
Expand Down Expand Up @@ -184,6 +185,7 @@ export namespace SearchInput {
activeElement: HTMLElement | undefined;
activeSuggestion: Suggestion<T> | undefined;
loading: boolean;
origin: HTMLElement | null;
query: string;
suggestions: Suggestion<T>[];
onClose: () => void;
Expand Down Expand Up @@ -227,13 +229,15 @@ function defaultRenderSuggestions<T>({
activeElement,
query,
suggestions,
origin,
children,
}: SearchInput.Props.Suggestions<T>) {
return (
<SearchInput.Suggestions<T>
activeElement={activeElement}
query={query}
suggestions={suggestions}
origin={origin}
>
{children}
</SearchInput.Suggestions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.Suggestions {
display: flex;
flex-direction: column;
width: 100%;
}
66 changes: 35 additions & 31 deletions packages/slate-editor/src/components/SearchInput/Suggestions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { FlipModifier } from '@popperjs/core/lib/modifiers/flip';
import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow';
import classNames from 'classnames';
import type { HTMLAttributes, ReactNode } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { usePopper } from 'react-popper';

import { useFunction } from '#lib';

Expand All @@ -12,55 +15,60 @@ import type { Suggestion } from './types';

export interface Props<T> extends HTMLAttributes<HTMLDivElement> {
activeElement: HTMLElement | undefined;
minHeight?: number;
footer?: ReactNode;
maxHeight?: number;
origin: HTMLElement | null;
query: string;
suggestions: Suggestion<T>[];
footer?: ReactNode;
}

export function Suggestions<T>({
activeElement,
children,
className,
footer,
minHeight = 200,
maxHeight = 500,
origin,
query,
suggestions,
...attributes
}: Props<T>) {
const [height, setHeight] = useState<number>();
const [calculatedMaxHeight, setMaxHeight] = useState<number>();
const container = useRef<HTMLDivElement | null>(null);
const childrenContainer = useRef<HTMLDivElement | null>(null);
const [scrollarea, setScrollarea] = useState<FancyScrollbars | null>(null);

const updatePanelSize = useFunction(() => {
setHeight(childrenContainer.current?.getBoundingClientRect().height);
const popper = usePopper(origin, container.current, {
modifiers: [
{
name: 'flip',
enabled: true,
options: {
fallbackPlacements: ['top'],
},
} satisfies Partial<FlipModifier>,
{
name: 'preventOverflow',
enabled: true,
options: {
altAxis: true,
mainAxis: true,
},
} satisfies Partial<PreventOverflowModifier>,
],
placement: 'bottom',
});

if (container.current) {
const viewport = document.body.getBoundingClientRect();
const rect = container.current.getBoundingClientRect();
setMaxHeight(clamp(viewport.height - rect.top - 4, minHeight, maxHeight));
} else {
setMaxHeight(undefined);
}
const updatePanelSizeAndPosition = useFunction(() => {
setHeight(childrenContainer.current?.getBoundingClientRect().height);
popper.update?.();
});

useEffect(() => {
updatePanelSize();

window.addEventListener('scroll', updatePanelSize);
window.addEventListener('resize', updatePanelSize);

return () => {
window.removeEventListener('scroll', updatePanelSize);
window.removeEventListener('resize', updatePanelSize);
};
}, [updatePanelSize]);
updatePanelSizeAndPosition();
}, [updatePanelSizeAndPosition]);

useEffect(updatePanelSize, [query, suggestions, minHeight, maxHeight]);
useEffect(updatePanelSizeAndPosition, [query, suggestions, maxHeight]);

useEffect(() => {
if (activeElement) {
Expand All @@ -71,20 +79,16 @@ export function Suggestions<T>({
return (
<Panel
{...attributes}
style={{ maxHeight: calculatedMaxHeight, ...attributes.style }}
{...popper.attributes.popper}
style={{ maxHeight, ...attributes.style, ...popper.styles.popper }}
ref={container}
className={classNames(className, styles.Suggestions)}
footer={footer}
placement={popper.state?.placement}
>
<FancyScrollbars ref={setScrollarea} style={{ flexGrow: 1, height }}>
<div ref={childrenContainer}>{children}</div>
</FancyScrollbars>
</Panel>
);
}

function clamp(num: number, min: number, max: number) {
if (num < min) return min;
if (num > max) return max;
return num;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import styles from './InputPlaceholder.module.scss';
import type { ContentRenderProps } from './Placeholder';

export interface Props extends Omit<BaseProps, 'title' | 'onSubmit'> {
children?: ReactNode;
title: ReactNode | FunctionComponent<ContentRenderProps>;
description: ReactNode | FunctionComponent<ContentRenderProps>;
// Input properties
Expand All @@ -28,6 +29,7 @@ export interface Props extends Omit<BaseProps, 'title' | 'onSubmit'> {
const isEsc = isHotkey('esc');

export function InputPlaceholder({
children,
className,
action,
title,
Expand Down Expand Up @@ -135,6 +137,7 @@ export function InputPlaceholder({
value={value}
/>
</form>
{children}
</Frame>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export function ContactPlaceholderElement({
query={props.query}
suggestions={props.suggestions}
footer={renderSuggestionsFooter?.(props)}
origin={props.origin}
>
{props.children}
</SearchInput.Suggestions>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "styles/variables";

.action {
margin: $spacing-2 0 0;
}

.button {
text-decoration: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import React, { type DragEvent, useEffect, useState } from 'react';
import { Transforms } from 'slate';
import { useSelected, useSlateStatic } from 'slate-react';

import { SearchInput } from '#components';
import { PlaceholderCoverage } from '#icons';
import { Button, SearchInput } from '#components';
import { PlaceholderCoverage, Upload } from '#icons';
import { URL_WITH_OPTIONAL_PROTOCOL_REGEXP, useFunction } from '#lib';

import { createCoverage } from '#extensions/coverage';
import { EventsEditor } from '#modules/events';
import { UploadcareEditor } from '#modules/uploadcare';

import { InputPlaceholder } from '../components/InputPlaceholder';
import { withLoadingDots } from '../components/LoadingDots';
Expand All @@ -24,6 +25,8 @@ import { replacePlaceholder } from '../lib';
import type { PlaceholderNode } from '../PlaceholderNode';
import { PlaceholdersManager, usePlaceholderManagement } from '../PlaceholdersManager';

import styles from './CoveragePlaceholderElement.module.scss';

type Url = string;
type CoverageRef = Pick<CoverageNode, 'coverage'>;
type Mode = 'search' | 'create';
Expand All @@ -49,6 +52,22 @@ export function CoveragePlaceholderElement({
PlaceholdersManager.activate(element);
});

const handleUpload = useFunction(async () => {
const files = await UploadcareEditor.upload(editor, { multiple: false });
if (!files) {
return;
}

setMode('search');
const uploading = toProgressPromise(files[0]).then(async (fileInfo: PrezlyFileInfo) => {
const file = UploadcareFile.createFromUploadcareWidgetPayload(fileInfo);
const ref = await onCreateCoverage(file);

return { coverage: { id: ref.coverage.id } };
});
PlaceholdersManager.register(element.type, element.uuid, uploading);
});

const handleDrop = useFunction((event: DragEvent) => {
event.preventDefault();
event.stopPropagation();
Expand Down Expand Up @@ -126,17 +145,19 @@ export function CoveragePlaceholderElement({
query={props.query}
suggestions={props.suggestions}
footer={renderSuggestionsFooter?.({ ...props, onMode })}
origin={props.origin}
>
{props.children}
</SearchInput.Suggestions>
)}
renderFrame={() =>
mode === 'create' ? (
<InputPlaceholder
autoFocus
format="card"
selected={isSelected}
title="Coverage"
description="Type the URL of the new Coverage you want to add"
title="Log new coverage"
description="Paste a coverage URL or upload a coverage file (you can also drop it here)."
placeholder="www.website.com/article"
pattern={URL_WITH_OPTIONAL_PROTOCOL_REGEXP.source}
action="Add coverage"
Expand All @@ -145,7 +166,18 @@ export function CoveragePlaceholderElement({
onEsc={() => PlaceholdersManager.deactivate(element)}
onRemove={handleRemove}
onSubmit={handleSubmitUrl}
/>
>
<div className={styles.action}>
<Button
className={styles.button}
icon={Upload}
onClick={handleUpload}
variant="underlined"
>
Upload a coverage file
</Button>
</div>
</InputPlaceholder>
) : undefined
}
inputTitle="Coverage"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export function GalleryBookmarkPlaceholderElement({
query={props.query}
suggestions={props.suggestions}
footer={renderSuggestionsFooter?.(props)}
origin={props.origin}
>
{props.children}
</SearchInput.Suggestions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export function InlineContactPlaceholderElement({
query={props.query}
suggestions={props.suggestions}
footer={renderSuggestionsFooter?.(props)}
origin={props.origin}
>
{props.children}
</SearchInput.Suggestions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export function StoryBookmarkPlaceholderElement({
query={props.query}
suggestions={props.suggestions}
footer={renderSuggestionsFooter?.(props)}
origin={props.origin}
>
{props.children}
</SearchInput.Suggestions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export function StoryEmbedPlaceholderElement({
query={props.query}
suggestions={props.suggestions}
footer={renderSuggestionsFooter?.(props)}
origin={props.origin}
>
{props.children}
</SearchInput.Suggestions>
Expand Down
3 changes: 3 additions & 0 deletions packages/slate-editor/src/icons/Upload.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/slate-editor/src/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export { default as Resize } from './Resize.svg';
export { default as Search } from './Search.svg';
export { default as SocialFacebook } from './Social-Facebook.svg';
export { default as SocialTwitter } from './Social-Twitter.svg';
export { default as Upload } from './Upload.svg';
export { default as User } from './User.svg';
export { default as Video } from './Video.svg';
export { default as WarningCircle } from './Warning-Circle.svg';
Expand Down

0 comments on commit 100b24c

Please sign in to comment.