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==",
|
||||
"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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 * 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>
|
||||
|
|
|
@ -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 * 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;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
position: relative;
|
||||
|
||||
&.filmStrip {
|
||||
margin: 0 -10px;
|
||||
margin-bottom: 27px;
|
||||
|
||||
:global(.slick-slide) {
|
||||
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 * 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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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 "./IFilmstripLayoutProps";
|
||||
|
|
Loading…
Reference in New Issue