SPFx React Accordion sample (#599)
* React Accordion Webpart added * Updated to imgur image url
This commit is contained in:
parent
53d14f2898
commit
4a47af2d14
|
@ -0,0 +1,25 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,32 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Visual Studio files
|
||||
.ntvs_analysis.dat
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
|
||||
# Resx Generated Code
|
||||
*.resx.ts
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.5.1",
|
||||
"libraryName": "react-accordion",
|
||||
"libraryId": "6d6cf05b-cfe5-4d12-af19-19ec3aedcaf9",
|
||||
"packageManager": "npm",
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
## Using React Accordion plugin with SPFx
|
||||
|
||||
## Summary
|
||||
|
||||
This is a sample web Part that illustrates the use of React Accessible Accordion plugin for building SharePoint Framework client-side web parts to show SharePoint list data in Accordion format.
|
||||
|
||||
![Sample Web Part built using SPFx with React Framework showing list data in accordion format](https://i.stack.imgur.com/QsZ6o.png)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-1.5.1-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-accordion | Gautam Sheth (SharePoint Consultant, RapidCircle)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|August 17, 2018|Initial release
|
||||
|
||||
## Disclaimer
|
||||
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||
|
||||
---
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- clone this repo
|
||||
- in the command line run:
|
||||
- `npm i`
|
||||
- `gulp serve --nobrowser`
|
||||
- in your SharePoint Site create a custom list named FAQ
|
||||
- in the FAQ list, create a column Description(internal name) of type Enhanced rich text
|
||||
- add some list items with Title and Description values
|
||||
|
||||
- navigate to the hosted version of SharePoint workbench, eg. **https://contoso.sharepoint.com/sites/test/_layouts/15/workbench.aspx**
|
||||
- add the Web Part to canvas and in its configuration specify:
|
||||
- name of the list where list items are stored, eg. **FAQ**
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
This project contains sample client-side web part built on the SharePoint Framework illustrating how to show list data in Accordion format using React framework.
|
||||
|
||||
This sample illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
- general
|
||||
- performing SharePoint GET operation in React using inbuilt SP Http Client
|
||||
- Using Fabric UI button component for pagination
|
||||
- optimizing REST responses for performance using nometadata option of JSON light
|
||||
- using PnP Webpart title control of @pnp/spfx-controls-react library
|
||||
- showing SharePoint list data in Accordion format using React Accessible Accordion plugin
|
||||
- searching in the fetched data by making use of Search Box from Office Fabric UI
|
||||
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-accordion" />
|
||||
|
||||
### Build options
|
||||
|
||||
gulp clean - TODO
|
||||
gulp test - TODO
|
||||
gulp serve - TODO
|
||||
gulp bundle - TODO
|
||||
gulp package-solution - TODO
|
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"react-accordion-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/reactAccordion/ReactAccordionWebPart.js",
|
||||
"manifest": "./src/webparts/reactAccordion/ReactAccordionWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"ReactAccordionWebPartStrings": "lib/webparts/reactAccordion/loc/{locale}.js",
|
||||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-accordion",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "react-accordion-client-side-solution",
|
||||
"id": "6d6cf05b-cfe5-4d12-af19-19ec3aedcaf9",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-accordion.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/tslint.schema.json",
|
||||
// Display errors as warnings
|
||||
"displayAsWarning": true,
|
||||
// The TSLint task may have been configured with several custom lint rules
|
||||
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
|
||||
// project). If true, this flag will deactivate any of these rules.
|
||||
"removeExistingRules": true,
|
||||
// When true, the TSLint task is configured with some default TSLint "rules.":
|
||||
"useDefaultConfigAsBase": false,
|
||||
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
|
||||
// which are active, other than the list of rules below.
|
||||
"lintConfig": {
|
||||
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
"forin": false,
|
||||
"label-position": false,
|
||||
"member-access": true,
|
||||
"no-arg": false,
|
||||
"no-console": false,
|
||||
"no-construct": false,
|
||||
"no-duplicate-case": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": false,
|
||||
"no-function-expression": true,
|
||||
"no-internal-module": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
"typedef": false,
|
||||
"typedef-whitespace": false,
|
||||
"use-named-parameter": true,
|
||||
"valid-typeof": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const gulp = require('gulp');
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
|
||||
|
||||
build.initialize(gulp);
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "react-accordion",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.5.1",
|
||||
"@microsoft/sp-lodash-subset": "1.5.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.5.1",
|
||||
"@microsoft/sp-webpart-base": "1.5.1",
|
||||
"@pnp/spfx-controls-react": "1.7.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "15.6.6",
|
||||
"@types/react-dom": "15.5.6",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"react": "15.6.2",
|
||||
"react-accessible-accordion": "1.0.2",
|
||||
"react-dom": "15.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.5.1",
|
||||
"@microsoft/sp-module-interfaces": "1.5.1",
|
||||
"@microsoft/sp-webpart-workbench": "1.5.1",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"ajv": "~5.2.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "97a28c00-64ee-4ec7-b373-723e39069a96",
|
||||
"alias": "ReactAccordionWebPart",
|
||||
"componentType": "WebPart",
|
||||
// The "*" signifies that the version should be taken from the package.json
|
||||
"version": "*",
|
||||
"manifestVersion": 2,
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed.
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": {
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "React Accordion App"
|
||||
},
|
||||
"description": {
|
||||
"default": "SPFx webpart which shows SharePoint list data in Accordion format"
|
||||
},
|
||||
"officeFabricIconFontName": "Questionnaire",
|
||||
"properties": {
|
||||
"description": "SPFx webpart which shows SharePoint list data in Accordion format",
|
||||
"listName": "FAQ",
|
||||
"maxItemsPerPage": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version, DisplayMode } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneSlider
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
|
||||
import * as strings from 'ReactAccordionWebPartStrings';
|
||||
import ReactAccordion from './components/ReactAccordion';
|
||||
import { IReactAccordionProps } from './components/IReactAccordionProps';
|
||||
|
||||
export interface IReactAccordionWebPartProps {
|
||||
listName: string;
|
||||
choice: string;
|
||||
title: string;
|
||||
displayMode: DisplayMode;
|
||||
maxItemsPerPage: number;
|
||||
updateProperty: (value: string) => void;
|
||||
}
|
||||
|
||||
export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactAccordionWebPartProps> {
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IReactAccordionProps> = React.createElement(
|
||||
ReactAccordion,
|
||||
{
|
||||
listName: this.properties.listName,
|
||||
spHttpClient: this.context.spHttpClient,
|
||||
siteUrl: this.context.pageContext.web.absoluteUrl,
|
||||
title: this.properties.title,
|
||||
displayMode: this.displayMode,
|
||||
maxItemsPerPage: this.properties.maxItemsPerPage,
|
||||
updateProperty: (value: string) => {
|
||||
this.properties.title = value;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('listName', {
|
||||
label: strings.ListNameLabel
|
||||
}),
|
||||
PropertyPaneSlider('maxItemsPerPage', {
|
||||
label: strings.MaxItemsPerPageLabel,
|
||||
ariaLabel: strings.MaxItemsPerPageLabel,
|
||||
min: 3,
|
||||
max: 20,
|
||||
value: 5,
|
||||
showValue: true,
|
||||
step: 1
|
||||
}),
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import { SPHttpClient } from '@microsoft/sp-http';
|
||||
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||
|
||||
export interface IReactAccordionProps {
|
||||
listName: string;
|
||||
spHttpClient: SPHttpClient;
|
||||
siteUrl: string;
|
||||
title: string,
|
||||
displayMode: DisplayMode,
|
||||
maxItemsPerPage: number,
|
||||
updateProperty: (value: string) => void;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import IAccordionListItem from '../models/IAccordionListItem';
|
||||
|
||||
export interface IReactAccordionState {
|
||||
status: string;
|
||||
items: IAccordionListItem[];
|
||||
listItems: IAccordionListItem[];
|
||||
isLoading: boolean;
|
||||
loaderMessage: string;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
|
||||
|
||||
.reactAccordion {
|
||||
.container {
|
||||
max-width: 100%;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-white;
|
||||
background-color: $ms-color-themeDark;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.column {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg10;
|
||||
@include ms-xl8;
|
||||
@include ms-xlPush2;
|
||||
@include ms-lgPush1;
|
||||
}
|
||||
|
||||
.title {
|
||||
@include ms-font-xl;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.description {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.button {
|
||||
// Our button
|
||||
text-decoration: none;
|
||||
height: 32px;
|
||||
|
||||
// Primary Button
|
||||
min-width: 80px;
|
||||
background-color: $ms-color-themePrimary;
|
||||
border-color: $ms-color-themePrimary;
|
||||
color: $ms-color-white;
|
||||
|
||||
// Basic Button
|
||||
outline: transparent;
|
||||
position: relative;
|
||||
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: $ms-font-size-m;
|
||||
font-weight: $ms-font-weight-regular;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 0 16px;
|
||||
|
||||
.label {
|
||||
font-weight: $ms-font-weight-semibold;
|
||||
font-size: $ms-font-size-m;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 4px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
import * as React from 'react';
|
||||
import styles from './ReactAccordion.module.scss';
|
||||
import { IReactAccordionProps } from './IReactAccordionProps';
|
||||
import { SPHttpClient, SPHttpClientResponse, ISPHttpClientOptions } from '@microsoft/sp-http';
|
||||
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox';
|
||||
import {
|
||||
Spinner,
|
||||
SpinnerSize
|
||||
} from 'office-ui-fabric-react/lib/Spinner';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
AccordionItemTitle,
|
||||
AccordionItemBody,
|
||||
} from 'react-accessible-accordion';
|
||||
import 'react-accessible-accordion/dist/react-accessible-accordion.css';
|
||||
import { IReactAccordionState } from "./IReactAccordionState";
|
||||
import IAccordionListItem from "../models/IAccordionListItem";
|
||||
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
|
||||
import './accordion.css';
|
||||
|
||||
export default class ReactAccordion extends React.Component<IReactAccordionProps, IReactAccordionState> {
|
||||
|
||||
constructor(props: IReactAccordionProps, state: IReactAccordionState) {
|
||||
super(props);
|
||||
this.state = {
|
||||
status: this.listNotConfigured(this.props) ? 'Please configure list in Web Part properties' : 'Ready',
|
||||
items: [],
|
||||
listItems: [],
|
||||
isLoading: false,
|
||||
loaderMessage: ''
|
||||
};
|
||||
|
||||
if (!this.listNotConfigured(this.props)) {
|
||||
this.readItems();
|
||||
}
|
||||
|
||||
this.searchTextChange = this.searchTextChange.bind(this);
|
||||
|
||||
}
|
||||
|
||||
private listNotConfigured(props: IReactAccordionProps): boolean {
|
||||
return props.listName === undefined ||
|
||||
props.listName === null ||
|
||||
props.listName.length === 0;
|
||||
}
|
||||
|
||||
private searchTextChange(event) {
|
||||
|
||||
if (event === undefined ||
|
||||
event === null ||
|
||||
event === "") {
|
||||
let listItemsCollection = [...this.state.listItems];
|
||||
this.setState({ items: listItemsCollection.splice(0, this.props.maxItemsPerPage) });
|
||||
}
|
||||
else {
|
||||
var updatedList = [...this.state.listItems];
|
||||
updatedList = updatedList.filter((item) => {
|
||||
return item.Title.toLowerCase().search(
|
||||
event.toLowerCase()) !== -1 || item.Description.toLowerCase().search(
|
||||
event.toLowerCase()) !== -1;
|
||||
});
|
||||
this.setState({ items: updatedList });
|
||||
}
|
||||
}
|
||||
|
||||
private readItems(): void {
|
||||
let restAPI = this.props.siteUrl + `/_api/web/Lists/GetByTitle('${this.props.listName}')/items?$select=Title,Description`;
|
||||
|
||||
this.props.spHttpClient.get(restAPI, SPHttpClient.configurations.v1, {
|
||||
headers: {
|
||||
'Accept': 'application/json;odata=nometadata',
|
||||
'odata-version': ''
|
||||
}
|
||||
})
|
||||
.then((response: SPHttpClientResponse): Promise<{ value: IAccordionListItem[] }> => {
|
||||
return response.json();
|
||||
})
|
||||
.then((response: { value: IAccordionListItem[] }): void => {
|
||||
|
||||
let listItemsCollection = [...response.value];
|
||||
|
||||
this.setState({
|
||||
status: "",
|
||||
items: listItemsCollection.splice(0, this.props.maxItemsPerPage),
|
||||
listItems: response.value,
|
||||
isLoading: false,
|
||||
loaderMessage: ""
|
||||
});
|
||||
}, (error: any): void => {
|
||||
this.setState({
|
||||
status: 'Loading all items failed with error: ' + error,
|
||||
items: [],
|
||||
isLoading: false,
|
||||
loaderMessage: ""
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IReactAccordionProps> {
|
||||
let displayLoader;
|
||||
let faqTitle;
|
||||
let { listItems } = this.state;
|
||||
let pageCountDivisor: number = this.props.maxItemsPerPage;
|
||||
let pageCount: number;
|
||||
let pageButtons = [];
|
||||
|
||||
let _pagedButtonClick = (pageNumber: number, listData: any) => {
|
||||
let startIndex: number = (pageNumber - 1) * pageCountDivisor;
|
||||
let listItemsCollection = [...listData];
|
||||
this.setState({ items: listItemsCollection.splice(startIndex, pageCountDivisor) });
|
||||
};
|
||||
|
||||
const items: JSX.Element[] = this.state.items.map((item: IAccordionListItem, i: number): JSX.Element => {
|
||||
return (
|
||||
<AccordionItem>
|
||||
<AccordionItemTitle className="accordion__title">
|
||||
<h3 className="u-position-relative ms-fontColor-white">{item.Title}</h3>
|
||||
<div className="accordion__arrow ms-fontColor-white" role="presentation" />
|
||||
</AccordionItemTitle>
|
||||
<AccordionItemBody className="accordion__body">
|
||||
<div className="" dangerouslySetInnerHTML={{ __html: item.Description }}>
|
||||
</div>
|
||||
</AccordionItemBody>
|
||||
</AccordionItem>
|
||||
);
|
||||
});
|
||||
|
||||
if (this.state.isLoading) {
|
||||
displayLoader = (<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
|
||||
<div className='ms-Grid-col ms-u-lg12'>
|
||||
<Spinner size={SpinnerSize.large} label={this.state.loaderMessage} />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
else {
|
||||
displayLoader = (null);
|
||||
}
|
||||
|
||||
if (this.state.listItems.length > 0) {
|
||||
pageCount = Math.ceil(this.state.listItems.length / pageCountDivisor);
|
||||
}
|
||||
for (let i = 0; i < pageCount; i++) {
|
||||
pageButtons.push(<PrimaryButton onClick={() => { _pagedButtonClick(i + 1, listItems); }}> {i + 1} </PrimaryButton>);
|
||||
}
|
||||
return (
|
||||
<div className={styles.reactAccordion}>
|
||||
<div className={styles.container}>
|
||||
{faqTitle}
|
||||
{displayLoader}
|
||||
<WebPartTitle displayMode={this.props.displayMode}
|
||||
title={this.props.title}
|
||||
updateProperty={this.props.updateProperty} />
|
||||
<div className='ms-Grid-row'>
|
||||
<div className='ms-Grid-col ms-u-lg12'>
|
||||
<SearchBox
|
||||
onChange={this.searchTextChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`ms-Grid-row`}>
|
||||
<div className='ms-Grid-col ms-u-lg12'>
|
||||
{this.state.status}
|
||||
<Accordion accordion={false}>
|
||||
{items}
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
<div className='ms-Grid-row'>
|
||||
<div className='ms-Grid-col ms-u-lg12'>
|
||||
{pageButtons}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
.accordion__title > *:last-child,
|
||||
.accordion__body > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.accordion__arrow {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 24px;
|
||||
height: 12px;
|
||||
right: 10px;
|
||||
margin-top: -28px;
|
||||
color: white !important;
|
||||
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
.accordion__arrow::after,
|
||||
.accordion__arrow::before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
background-color: currentColor;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.accordion__arrow::before {
|
||||
left: 4px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
[aria-expanded="true"] .accordion__arrow::before {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.accordion__arrow::after {
|
||||
right: 4px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
[aria-expanded="true"] .accordion__arrow::after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.accordion__arrow::before, .accordion__arrow::after {
|
||||
transition: transform .25s ease, -webkit-transform .25s ease;
|
||||
}
|
||||
|
||||
.accordion__item {
|
||||
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.accordion {
|
||||
padding-top: 10px;
|
||||
|
||||
}
|
||||
.accordion__item .accordion__title {
|
||||
padding: 5px 20px;;
|
||||
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||
}
|
||||
.accordion__item .accordion__title h3 {
|
||||
font-weight: normal;
|
||||
width: 88%;
|
||||
}
|
||||
.accordion__item .accordion__body {
|
||||
padding: 15px 20px;
|
||||
background-color: "[theme: themeLighterAlt, default: #0078d7]";
|
||||
color: "[theme: bodyText, default: #333333]";
|
||||
}
|
||||
|
||||
.accordion__item .accordion__body a {
|
||||
color: "[theme: themePrimary, default: #0078d7]" !important;
|
||||
}
|
||||
.accordion__item .accordion__body p {
|
||||
color: "[theme: bodyText, default: #333333]";
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
/* ---------------- Animation part ------------------ */
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
@keyframes move-down {
|
||||
0% { transform: translateY(0); }
|
||||
10% { transform: translateY(0); }
|
||||
20% { transform: translateY(5px); }
|
||||
30% { transform: translateY(0); }
|
||||
100% { transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes move-up {
|
||||
0% { transform: translateY(0); }
|
||||
10% { transform: translateY(0); }
|
||||
20% { transform: translateY(-5px); }
|
||||
30% { transform: translateY(0); }
|
||||
100% { transform: translateY(0); }
|
||||
}
|
||||
|
||||
.accordion__title--animated:hover .accordion__arrow {
|
||||
animation-name: move-down;
|
||||
animation-duration: 1.5s;
|
||||
}
|
||||
|
||||
.accordion__title--animated[aria-expanded="true"]:hover .accordion__arrow {
|
||||
animation-name: move-up;
|
||||
animation-duration: 1.5s;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
define([], function () {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"ListNameLabel": "List Name",
|
||||
"MaxItemsPerPageLabel": "Max number of items per page"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
declare interface IReactAccordionWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
ListNameLabel: string;
|
||||
MaxItemsPerPageLabel: string
|
||||
}
|
||||
|
||||
declare module 'ReactAccordionWebPartStrings' {
|
||||
const strings: IReactAccordionWebPartStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
interface IAccordionListItem {
|
||||
Id: number;
|
||||
Title: string;
|
||||
Description: string;
|
||||
}
|
||||
export default IAccordionListItem;
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"rulesDirectory": "./config"
|
||||
}
|
Loading…
Reference in New Issue