Added resizing and Hooks

This commit is contained in:
Hugo Bernier 2020-04-17 04:19:06 -04:00
parent ce98f07dd9
commit 6b1681ce5b
13 changed files with 87 additions and 166 deletions

View File

@ -4878,6 +4878,11 @@
"integrity": "sha512-NsEzBVa5aMgn/n79piyJtpUQFzJ97tB2R2r8PSJlLnMA6LJmchKuv7ATN+/nZH/3QRd/+uFXEq07/i/ajsqVGQ==",
"dev": true
},
"@rehooks/component-size": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rehooks/component-size/-/component-size-1.0.3.tgz",
"integrity": "sha512-pnYld+8SSF2vXwdLOqBGUyOrv/SjzwLjIUcs/4c1JJgR0q4E9eBtBfuZMD6zUD51fvSehSsbnlQMzotSmPTXPg=="
},
"@types/adal-angular": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/@types/adal-angular/-/adal-angular-1.0.1.tgz",

View File

@ -23,6 +23,7 @@
"@pnp/sp": "^1.2.8",
"@pnp/spfx-controls-react": "^1.11.0",
"@pnp/spfx-property-controls": "^1.13.1",
"@rehooks/component-size": "^1.0.3",
"@types/es6-promise": "0.0.33",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.3",

View File

@ -3,12 +3,11 @@ import { css } from "office-ui-fabric-react/lib/Utilities";
import * as React from "react";
import styles from "./DateBox.module.scss";
import { DateBoxSize, IDateBoxProps } from ".";
import { IDateBoxState } from "./IDateBoxState";
/**
* Shows a date in a SharePoint-looking date
*/
export class DateBox extends React.Component<IDateBoxProps, IDateBoxState> {
export class DateBox extends React.Component<IDateBoxProps, {}> {
public render(): React.ReactElement<IDateBoxProps> {
// convert start and end date into moments so that we can manipulate them
const startMoment: moment.Moment = moment(this.props.startDate);

View File

@ -1,3 +0,0 @@
export interface IDateBoxState {
// you just proved advertising works!
}

View File

@ -5,14 +5,13 @@ import * as moment from "moment";
import { ActionButton, DocumentCard, DocumentCardType, FocusZone, css } from "office-ui-fabric-react";
import * as React from "react";
import { IEventCardProps } from ".";
import { IEventCardState } from "./IEventCardState";
import { DateBox, DateBoxSize } from "../DateBox";
import styles from "./EventCard.module.scss";
import { Text } from "@microsoft/sp-core-library";
/**
* Shows an event in a document card
*/
export class EventCard extends React.Component<IEventCardProps, IEventCardState> {
export class EventCard extends React.Component<IEventCardProps, {}> {
public render(): React.ReactElement<IEventCardProps> {
const { isNarrow } = this.props;
@ -51,7 +50,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
onClickHref={isEditMode ? null : url}
>
<FocusZone>
<div className={styles.dateBoxContainer} style={{ height: 160 }} data-automation-id="normal-card-preview">
<div className={styles.dateBoxContainer} style={{ height: 160 }}>
<DateBox
className={styles.dateBox}
startDate={start}
@ -61,7 +60,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
</div>
<div className={styles.detailsContainer}>
<div className={styles.category}>{category}</div>
<div className={styles.title} data-automation-id="event-card-title">{title}</div>
<div className={styles.title}>{title}</div>
<div className={styles.datetime}>{dateString}</div>
<div className={styles.location}>{location}</div>
<ActionButton
@ -105,7 +104,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
type={DocumentCardType.compact}
onClickHref={url}
>
<div data-automation-id="normal-card-preview">
<div>
<DateBox
className={styles.dateBox}
startDate={start}
@ -114,7 +113,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
/>
</div>
<div>
<div className={styles.title} data-automation-id="event-card-title">{title}</div>
<div className={styles.title}>{title}</div>
<div className={styles.datetime}>{dateString}</div>
</div>
</DocumentCard>

View File

@ -1,3 +0,0 @@
export interface IEventCardState {
// Not in use
}

View File

@ -1,3 +0,0 @@
export interface IPagingState {
// Not in use
}

View File

@ -3,14 +3,13 @@ import { Icon } from "office-ui-fabric-react/lib/Icon";
import { css } from "office-ui-fabric-react/lib/Utilities";
import * as React from "react";
import { IPagingProps } from ".";
import { IPagingState } from "./IPagingState";
import styles from "./Paging.module.scss";
import * as strings from "CalendarFeedSummaryWebPartStrings";
/**
* A custom pagination control designed to look & feel like Office UI Fabric
*/
export class Paging extends React.Component<IPagingProps, IPagingState> {
export class Paging extends React.Component<IPagingProps, {}> {
public render(): React.ReactElement<IPagingProps> {
const { currentPage } = this.props;

View File

@ -7,7 +7,7 @@
position: relative;
&.filmStrip {
margin: 0 -10px;
margin-bottom: 27px;
:global(.slick-slide) {
box-sizing: border-box;

View File

@ -2,153 +2,91 @@ import { css } from '@uifabric/utilities/lib/css';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import * as React from 'react';
import Slider from 'react-slick';
import { IFilmstripLayoutProps } from "./IFilmstripLayoutProps";
import { IFilmstripLayoutState} from "./IFilmstripLayoutState";
import { SPComponentLoader } from '@microsoft/sp-loader';
import styles from "./FilmstripLayout.module.scss";
import { useRef } from 'react';
import useComponentSize, { ComponentSize } from '@rehooks/component-size';
/**
* Filmstrip layout
* Presents the child compoments as a slick slide
*/
export class FilmstripLayout extends React.Component<
IFilmstripLayoutProps,
IFilmstripLayoutState
> {
// the slick slider used in normal views
private _slider: Slider;
export const FilmstripLayout = (props: { children: any; ariaLabel?: string; }) => {
let ref: React.MutableRefObject<HTMLDivElement> = useRef<HTMLDivElement>(null);
let size: ComponentSize = useComponentSize(ref);
let { width } = size;
private _container: HTMLDivElement;
// // the slick slider used in normal views
let _slider: React.MutableRefObject<Slider> = useRef<Slider>(null);
/**
*
*/
constructor(props: IFilmstripLayoutProps) {
super(props);
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css');
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css');
this.state = {
dimensions: undefined
};
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css');
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css');
// slick seems to have an issue with having "infinite" mode set to true and having less items than the number of slides per page
// set infinite to true only if there are more than 3 children
let numSlides: number = 3;
if (width) {
if (width > 927) {
numSlides = 4;
} else if (width <= 695) {
numSlides = 2;
}
}
public componentDidMount(): void {
if (this._container) {
this.setState({
dimensions: {
width: this._container.offsetWidth,
height: this._container.offsetHeight,
},
});
}
}
/**
* Renders a slick switch, a slide for each child, and next/previous arrows
*/
public render(): React.ReactElement<IFilmstripLayoutProps> {
// slick seems to have an issue with having "infinite" mode set to true and having less items than the number of slides per page
// set infinite to true only if there are more than 3 children
let numSlides: number = 3;
if (this.state.dimensions) {
if (this.state.dimensions.width > 927) {
numSlides = 4;
} else if (this.state.dimensions.width <= 695) {
numSlides = 2;
}
}
var isInfinite: boolean = React.Children.count(this.props.children) > numSlides;
var settings: any = {
accessibility: true,
arrows: false,
autoplaySpeed: 5000,
dots: true,
//dotsClass: css("slick-dots", styles.slickDots),
customPaging: (i:number)=> {
return (
<a>
<div role="button" className={styles.carouselDotsContainer} aria-label={`Carousel Dot ${i}`} data-is-focusable={true} tabIndex={0}>
<span className={styles.carouselDot} tabIndex={-1}></span>
</div>
</a>
);
},
infinite: isInfinite,
slidesToShow: numSlides,
slidesToScroll: numSlides,
speed: 500,
centerPadding: styles.centerPadding,
pauseOnHover: true,
variableWidth: false,
useCSS: true,
rows: 1,
respondTo: "slider",
// responsive: [
// // {
// // breakpoint: 1440,
// // settings: {
// // slidesToShow: 4,
// // slidesToScroll: 4,
// // infinite: isInfinite,
// // dots: true
// // }
// // },
// {
// breakpoint: 1024,
// settings: {
// slidesToShow: 3,
// slidesToScroll: 3,
// infinite: isInfinite,
// dots: true
// }
// },
// {
// // breakpoint: 754,
// breakpoint: 767,
// settings: {
// slidesToShow: 2,
// slidesToScroll: 2,
// infinite: isInfinite,
// dots: true
// }
// }
// ]
};
console.log("Dimensions", this.state.dimensions);
return (
<div>
WIDTH: {this.state.dimensions && this.state.dimensions.width}
<div className={css(styles.filmstripLayout, styles.filmStrip)} aria-label={this.props.ariaLabel} ref={(el: HTMLDivElement) => (this._container = el)}>
<Slider ref={(c:Slider) => (this._slider = c)} {...settings}>
{this.props.children}
</Slider>
<div
className={css(styles.indexButtonContainer, styles.sliderButtons)}
style={{ left: "10px" }}
onClick={() => this._slider.slickPrev()}
>
<IconButton
className={css(styles.indexButton, styles.leftPositioned)}
iconProps={{ iconName: "ChevronLeft", styles: {root: { fontSize:'28px', fontWeight:'400'} }}}
/>
</div>
<div
className={css(styles.indexButtonContainer, styles.sliderButtons)}
style={{ right: "10px" }}
onClick={() => this._slider.slickNext()}
>
<IconButton
className={css(styles.indexButton, styles.rightPositioned)}
iconProps={{ iconName: "ChevronRight", styles: {root: { fontSize:'28px', fontWeight:'400'} }}}
/>
var isInfinite: boolean = React.Children.count(props.children) > numSlides;
var settings: any = {
accessibility: true,
arrows: false,
autoplaySpeed: 5000,
dots: true,
customPaging: (i: number) => {
return (
<a>
<div role="button" className={styles.carouselDotsContainer} aria-label={`Carousel Dot ${i}`} data-is-focusable={true} tabIndex={0}>
<span className={styles.carouselDot} tabIndex={-1}></span>
</div>
</a>
);
},
infinite: isInfinite,
slidesToShow: numSlides,
slidesToScroll: numSlides,
speed: 500,
centerPadding: styles.centerPadding,
pauseOnHover: true,
variableWidth: false,
useCSS: true,
rows: 1,
respondTo: "slider",
};
return (
<div>
<div className={css(styles.filmstripLayout, styles.filmStrip)} aria-label={props.ariaLabel} ref={ref}>
<Slider ref={_slider} {...settings}>
{props.children}
</Slider>
<div
className={css(styles.indexButtonContainer, styles.sliderButtons)}
style={{ left: "10px" }}
onClick={() => _slider.current.slickPrev()}
>
<IconButton
className={css(styles.indexButton, styles.leftPositioned)}
iconProps={{ iconName: "ChevronLeft", styles: { root: { fontSize: '28px', fontWeight: '400' } } }}
/>
</div>
<div
className={css(styles.indexButtonContainer, styles.sliderButtons)}
style={{ right: "10px" }}
onClick={() => _slider.current.slickNext()}
>
<IconButton
className={css(styles.indexButton, styles.rightPositioned)}
iconProps={{ iconName: "ChevronRight", styles: { root: { fontSize: '28px', fontWeight: '400' } } }}
/>
</div>
</div>
);
}
}
</div>
);
};

View File

@ -1,3 +0,0 @@
export interface IFilmstripLayoutProps {
ariaLabel?: string;
}

View File

@ -1,7 +0,0 @@
export interface IFilmstripLayoutState {
dimensions: {
width: any;
height: any;
};
}

View File

@ -1,2 +1 @@
export * from "./FilmstripLayout";
export * from "./IFilmstripLayoutProps";