Added resizing and Hooks
This commit is contained in:
parent
ce98f07dd9
commit
6b1681ce5b
|
@ -4878,6 +4878,11 @@
|
||||||
"integrity": "sha512-NsEzBVa5aMgn/n79piyJtpUQFzJ97tB2R2r8PSJlLnMA6LJmchKuv7ATN+/nZH/3QRd/+uFXEq07/i/ajsqVGQ==",
|
"integrity": "sha512-NsEzBVa5aMgn/n79piyJtpUQFzJ97tB2R2r8PSJlLnMA6LJmchKuv7ATN+/nZH/3QRd/+uFXEq07/i/ajsqVGQ==",
|
||||||
"dev": true
|
"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": {
|
"@types/adal-angular": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/@types/adal-angular/-/adal-angular-1.0.1.tgz",
|
"resolved": "http://registry.npmjs.org/@types/adal-angular/-/adal-angular-1.0.1.tgz",
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
"@pnp/sp": "^1.2.8",
|
"@pnp/sp": "^1.2.8",
|
||||||
"@pnp/spfx-controls-react": "^1.11.0",
|
"@pnp/spfx-controls-react": "^1.11.0",
|
||||||
"@pnp/spfx-property-controls": "^1.13.1",
|
"@pnp/spfx-property-controls": "^1.13.1",
|
||||||
|
"@rehooks/component-size": "^1.0.3",
|
||||||
"@types/es6-promise": "0.0.33",
|
"@types/es6-promise": "0.0.33",
|
||||||
"@types/react": "16.8.8",
|
"@types/react": "16.8.8",
|
||||||
"@types/react-dom": "16.8.3",
|
"@types/react-dom": "16.8.3",
|
||||||
|
|
|
@ -3,12 +3,11 @@ import { css } from "office-ui-fabric-react/lib/Utilities";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import styles from "./DateBox.module.scss";
|
import styles from "./DateBox.module.scss";
|
||||||
import { DateBoxSize, IDateBoxProps } from ".";
|
import { DateBoxSize, IDateBoxProps } from ".";
|
||||||
import { IDateBoxState } from "./IDateBoxState";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a date in a SharePoint-looking date
|
* 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> {
|
public render(): React.ReactElement<IDateBoxProps> {
|
||||||
// convert start and end date into moments so that we can manipulate them
|
// convert start and end date into moments so that we can manipulate them
|
||||||
const startMoment: moment.Moment = moment(this.props.startDate);
|
const startMoment: moment.Moment = moment(this.props.startDate);
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface IDateBoxState {
|
|
||||||
// you just proved advertising works!
|
|
||||||
}
|
|
|
@ -5,14 +5,13 @@ import * as moment from "moment";
|
||||||
import { ActionButton, DocumentCard, DocumentCardType, FocusZone, css } from "office-ui-fabric-react";
|
import { ActionButton, DocumentCard, DocumentCardType, FocusZone, css } from "office-ui-fabric-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IEventCardProps } from ".";
|
import { IEventCardProps } from ".";
|
||||||
import { IEventCardState } from "./IEventCardState";
|
|
||||||
import { DateBox, DateBoxSize } from "../DateBox";
|
import { DateBox, DateBoxSize } from "../DateBox";
|
||||||
import styles from "./EventCard.module.scss";
|
import styles from "./EventCard.module.scss";
|
||||||
import { Text } from "@microsoft/sp-core-library";
|
import { Text } from "@microsoft/sp-core-library";
|
||||||
/**
|
/**
|
||||||
* Shows an event in a document card
|
* 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> {
|
public render(): React.ReactElement<IEventCardProps> {
|
||||||
const { isNarrow } = this.props;
|
const { isNarrow } = this.props;
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
|
||||||
onClickHref={isEditMode ? null : url}
|
onClickHref={isEditMode ? null : url}
|
||||||
>
|
>
|
||||||
<FocusZone>
|
<FocusZone>
|
||||||
<div className={styles.dateBoxContainer} style={{ height: 160 }} data-automation-id="normal-card-preview">
|
<div className={styles.dateBoxContainer} style={{ height: 160 }}>
|
||||||
<DateBox
|
<DateBox
|
||||||
className={styles.dateBox}
|
className={styles.dateBox}
|
||||||
startDate={start}
|
startDate={start}
|
||||||
|
@ -61,7 +60,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.detailsContainer}>
|
<div className={styles.detailsContainer}>
|
||||||
<div className={styles.category}>{category}</div>
|
<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.datetime}>{dateString}</div>
|
||||||
<div className={styles.location}>{location}</div>
|
<div className={styles.location}>{location}</div>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
|
@ -105,7 +104,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
|
||||||
type={DocumentCardType.compact}
|
type={DocumentCardType.compact}
|
||||||
onClickHref={url}
|
onClickHref={url}
|
||||||
>
|
>
|
||||||
<div data-automation-id="normal-card-preview">
|
<div>
|
||||||
<DateBox
|
<DateBox
|
||||||
className={styles.dateBox}
|
className={styles.dateBox}
|
||||||
startDate={start}
|
startDate={start}
|
||||||
|
@ -114,7 +113,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<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 className={styles.datetime}>{dateString}</div>
|
||||||
</div>
|
</div>
|
||||||
</DocumentCard>
|
</DocumentCard>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface IEventCardState {
|
|
||||||
// Not in use
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface IPagingState {
|
|
||||||
// Not in use
|
|
||||||
}
|
|
|
@ -3,14 +3,13 @@ import { Icon } from "office-ui-fabric-react/lib/Icon";
|
||||||
import { css } from "office-ui-fabric-react/lib/Utilities";
|
import { css } from "office-ui-fabric-react/lib/Utilities";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IPagingProps } from ".";
|
import { IPagingProps } from ".";
|
||||||
import { IPagingState } from "./IPagingState";
|
|
||||||
import styles from "./Paging.module.scss";
|
import styles from "./Paging.module.scss";
|
||||||
import * as strings from "CalendarFeedSummaryWebPartStrings";
|
import * as strings from "CalendarFeedSummaryWebPartStrings";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom pagination control designed to look & feel like Office UI Fabric
|
* 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> {
|
public render(): React.ReactElement<IPagingProps> {
|
||||||
|
|
||||||
const { currentPage } = this.props;
|
const { currentPage } = this.props;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&.filmStrip {
|
&.filmStrip {
|
||||||
margin: 0 -10px;
|
margin-bottom: 27px;
|
||||||
|
|
||||||
:global(.slick-slide) {
|
:global(.slick-slide) {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
|
@ -2,153 +2,91 @@ import { css } from '@uifabric/utilities/lib/css';
|
||||||
import { IconButton } from 'office-ui-fabric-react/lib/Button';
|
import { IconButton } from 'office-ui-fabric-react/lib/Button';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Slider from 'react-slick';
|
import Slider from 'react-slick';
|
||||||
import { IFilmstripLayoutProps } from "./IFilmstripLayoutProps";
|
|
||||||
import { IFilmstripLayoutState} from "./IFilmstripLayoutState";
|
|
||||||
import { SPComponentLoader } from '@microsoft/sp-loader';
|
import { SPComponentLoader } from '@microsoft/sp-loader';
|
||||||
import styles from "./FilmstripLayout.module.scss";
|
import styles from "./FilmstripLayout.module.scss";
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import useComponentSize, { ComponentSize } from '@rehooks/component-size';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filmstrip layout
|
* Filmstrip layout
|
||||||
* Presents the child compoments as a slick slide
|
* Presents the child compoments as a slick slide
|
||||||
*/
|
*/
|
||||||
export class FilmstripLayout extends React.Component<
|
export const FilmstripLayout = (props: { children: any; ariaLabel?: string; }) => {
|
||||||
IFilmstripLayoutProps,
|
let ref: React.MutableRefObject<HTMLDivElement> = useRef<HTMLDivElement>(null);
|
||||||
IFilmstripLayoutState
|
let size: ComponentSize = useComponentSize(ref);
|
||||||
> {
|
let { width } = size;
|
||||||
// the slick slider used in normal views
|
|
||||||
private _slider: Slider;
|
|
||||||
|
|
||||||
private _container: HTMLDivElement;
|
// // the slick slider used in normal views
|
||||||
|
let _slider: React.MutableRefObject<Slider> = useRef<Slider>(null);
|
||||||
|
|
||||||
/**
|
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');
|
||||||
*/
|
|
||||||
constructor(props: IFilmstripLayoutProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
// slick seems to have an issue with having "infinite" mode set to true and having less items than the number of slides per page
|
||||||
dimensions: undefined
|
// set infinite to true only if there are more than 3 children
|
||||||
};
|
let numSlides: number = 3;
|
||||||
|
if (width) {
|
||||||
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css');
|
if (width > 927) {
|
||||||
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css');
|
numSlides = 4;
|
||||||
|
} else if (width <= 695) {
|
||||||
|
numSlides = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount(): void {
|
var isInfinite: boolean = React.Children.count(props.children) > numSlides;
|
||||||
if (this._container) {
|
var settings: any = {
|
||||||
this.setState({
|
accessibility: true,
|
||||||
dimensions: {
|
arrows: false,
|
||||||
width: this._container.offsetWidth,
|
autoplaySpeed: 5000,
|
||||||
height: this._container.offsetHeight,
|
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>
|
||||||
/**
|
|
||||||
* 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'} }}}
|
|
||||||
/>
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface IFilmstripLayoutProps {
|
|
||||||
ariaLabel?: string;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
export interface IFilmstripLayoutState {
|
|
||||||
dimensions: {
|
|
||||||
width: any;
|
|
||||||
height: any;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,2 +1 @@
|
||||||
export * from "./FilmstripLayout";
|
export * from "./FilmstripLayout";
|
||||||
export * from "./IFilmstripLayoutProps";
|
|
||||||
|
|
Loading…
Reference in New Issue