Skip to content

Commit

Permalink
Constrain drop zone height based on inherited wrapper height
Browse files Browse the repository at this point in the history
  • Loading branch information
Solona Armstrong authored and elileto committed Feb 20, 2019
1 parent 1cf3f2a commit c4a52d4
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 138 deletions.
2 changes: 2 additions & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f

### Bug fixes

- Constrained `DropZone` height based on inherited wrapper height [#908](https://github.com/Shopify/polaris-react/pull/908)

### Documentation

### Development workflow
Expand Down
12 changes: 12 additions & 0 deletions src/components/DropZone/DropZone.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ $dropzone-overlay-border-color-error: color('red');
$dropzone-overlay-background: color('indigo', 'lighter');
$dropzone-overlay-background-error: color('red', 'lighter');

.DropZoneWrapper {
height: inherit;
}

.DropZone {
position: relative;
display: flex;
justify-content: center;
background-color: $dropzone-background;
border-radius: $dropzone-border-radius;
height: inherit;
}

.hasOutline {
Expand All @@ -36,6 +41,10 @@ $dropzone-overlay-background-error: color('red', 'lighter');
cursor: not-allowed;
}

.isMeasuring {
visibility: hidden;
}

.sizeExtraLarge {
min-height: $dropzone-min-height-extra-large;
}
Expand All @@ -57,6 +66,9 @@ $dropzone-overlay-background-error: color('red', 'lighter');

.Container {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}

.Overlay {
Expand Down
135 changes: 84 additions & 51 deletions src/components/DropZone/DropZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,23 @@ import {FileUpload, Provider} from './components';
import {dragDrop, alertCircle} from './icons';

import {fileAccepted, getDataTransferFiles} from './utils';
import {DropZoneContext} from './types';
import {DropZoneContext, Size} from './types';

import styles from './DropZone.scss';

export type Type = 'file' | 'image';

export interface State {
id: string;
size: string;
height: Size;
width: Size;
type?: string;
error?: boolean;
dragging: boolean;
overlayText?: string;
errorOverlayText?: string;
numFiles: number;
measuring: boolean;
}

export interface Props {
Expand Down Expand Up @@ -108,7 +110,6 @@ export interface Props {
export type CombinedProps = Props & WithAppProviderProps;

const getUniqueID = createUniqueIDFactory('DropZone');

export class DropZone extends React.Component<CombinedProps, State> {
public static FileUpload: typeof FileUpload = FileUpload;
public static defaultProps: Partial<CombinedProps> = {
Expand Down Expand Up @@ -170,19 +171,23 @@ export class DropZone extends React.Component<CombinedProps, State> {
this.state = {
type,
id: props.id || getUniqueID(),
size: 'extraLarge',
height: Size.ExtraLarge,
dragging: false,
error: false,
overlayText: translate(`Polaris.DropZone.overlayText${suffix}`),
errorOverlayText: translate(`Polaris.DropZone.errorOverlayText${suffix}`),
numFiles: 0,
width: Size.ExtraLarge,
measuring: true,
};
}

get getContext(): DropZoneContext {
const {width, height, type = 'file'} = this.state;
return {
size: this.state.size,
type: this.state.type || 'file',
width,
height,
type,
};
}

Expand All @@ -191,9 +196,11 @@ export class DropZone extends React.Component<CombinedProps, State> {
id,
dragging,
error,
size,
height,
width,
overlayText,
errorOverlayText,
measuring,
} = this.state;
const {
label,
Expand Down Expand Up @@ -223,61 +230,77 @@ export class DropZone extends React.Component<CombinedProps, State> {
styles.DropZone,
outline && styles.hasOutline,
(active || dragging) && styles.isDragging,
measuring && styles.isMeasuring,
error && styles.hasError,
size && size === 'extraLarge' && styles.sizeExtraLarge,
size && size === 'large' && styles.sizeLarge,
size && size === 'medium' && styles.sizeMedium,
size && size === 'small' && styles.sizeSmall,
height === Size.ExtraLarge && styles.sizeExtraLarge,
height === Size.Large && styles.sizeLarge,
height === Size.Medium && styles.sizeMedium,
height === Size.Small && styles.sizeSmall,
);

const extraLargeDropZoneSize =
width === Size.ExtraLarge && height !== Size.Small;

const mediumLargeDropZoneSize =
(width === Size.Medium || width === Size.Large) && height !== Size.Small;

const dragOverlayDisplayText = extraLargeDropZoneSize && (
<DisplayText size="small" element="p">
{overlayText}
</DisplayText>
);

const dragOverlayCaption = mediumLargeDropZoneSize && (
<Caption>{overlayText}</Caption>
);

const dragOverlay =
(active || dragging) && !error && overlay ? (
<div className={styles.Overlay}>
<Stack vertical spacing="tight">
<Icon source={dragDrop} color="indigo" />
{size === 'extraLarge' && (
<DisplayText size="small" element="p">
{overlayText}
</DisplayText>
)}
{(size === 'medium' || size === 'large') && (
<Caption>{overlayText}</Caption>
)}
{dragOverlayDisplayText}
{dragOverlayCaption}
</Stack>
</div>
) : null;

const dragErrorOverlayDisplayText = extraLargeDropZoneSize && (
<DisplayText size="small" element="p">
{errorOverlayText}
</DisplayText>
);

const dragErrorOverlayCaption = mediumLargeDropZoneSize && (
<Caption>{errorOverlayText}</Caption>
);

const dragErrorOverlay =
dragging && error ? (
<div className={styles.Overlay}>
<Stack vertical spacing="tight">
<Icon source={alertCircle} color="red" />
{size === 'extraLarge' && (
<DisplayText size="small" element="p">
{errorOverlayText}
</DisplayText>
)}
{(size === 'medium' || size === 'large') && (
<Caption>{errorOverlayText}</Caption>
)}
{dragErrorOverlayDisplayText}
{dragErrorOverlayCaption}
</Stack>
</div>
) : null;

const dropZoneMarkup = (
<div
ref={this.setNode}
className={classes}
aria-disabled={disabled}
onClick={this.handleClick}
onDragStart={handleDragStart}
>
{dragOverlay}
{dragErrorOverlay}
<div className={styles.Container}>{children}</div>
<VisuallyHidden>
<input {...inputAttributes} />
</VisuallyHidden>
<div ref={this.setNode} className={styles.DropZoneWrapper}>
<div
className={classes}
aria-disabled={disabled}
onClick={this.handleClick}
onDragStart={handleDragStart}
>
{dragOverlay}
{dragErrorOverlay}
<div className={styles.Container}>{children}</div>
<VisuallyHidden>
<input {...inputAttributes} />
</VisuallyHidden>
</div>
</div>
);

Expand Down Expand Up @@ -355,25 +378,35 @@ export class DropZone extends React.Component<CombinedProps, State> {
this.fileInputNode.click();
}

@autobind
private setWrapperSize(size: string, node: HTMLElement) {
let wrapperSize;
const getSize = size === 'height' ? 'height' : 'width';
const wrapper = node.getBoundingClientRect()[getSize];

if (wrapper < Size.Small) {
wrapperSize = Size.Small;
} else if (wrapper < Size.Medium) {
wrapperSize = Size.Medium;
} else if (wrapper < Size.Large) {
wrapperSize = Size.Large;
} else {
wrapperSize = Size.ExtraLarge;
}
return wrapperSize;
}

@autobind
@debounce(50, {trailing: true})
private adjustSize() {
if (!this.node) {
return;
}

let size = 'extraLarge';
const width = this.node.getBoundingClientRect().width;

if (width < 100) {
size = 'small';
} else if (width < 160) {
size = 'medium';
} else if (width < 300) {
size = 'large';
}
const height = this.setWrapperSize('height', this.node);
const width = this.setWrapperSize('width', this.node);

this.setState({size});
this.setState({height, width, measuring: false});
}

@autobind
Expand Down
5 changes: 3 additions & 2 deletions src/components/DropZone/components/Context/Context.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';
import {DropZoneContext} from '../../types';
import {DropZoneContext, Size} from '../../types';

const {Provider, Consumer} = React.createContext<DropZoneContext>({
size: 'extraLarge',
width: Size.ExtraLarge,
height: Size.ExtraLarge,
type: 'file',
});

Expand Down
Loading

0 comments on commit c4a52d4

Please sign in to comment.