diff --git a/CHANGELOG.JSON b/CHANGELOG.JSON index 0378530df..c3c431076 100644 --- a/CHANGELOG.JSON +++ b/CHANGELOG.JSON @@ -1,5 +1,34 @@ { "versions": [ + { + "version": "2.1.0", + "changes": { + "new": [], + "enhancements": [ + "`Carousel`: Ability to display indicators in a dedicated block [#681](https://github.com/pnp/sp-dev-fx-controls-react/pull/681)", + "`FilePicker`: Org Assets are not displayed for non-admin users [#687](https://github.com/pnp/sp-dev-fx-controls-react/pull/687)", + "`ListView`: Drag and Drop option [#679](https://github.com/pnp/sp-dev-fx-controls-react/issues/679)", + "`FolderExplorerService`: support special characters if folder name [#691](https://github.com/pnp/sp-dev-fx-controls-react/pull/691)", + "`ListView`: Sticky Header [#634](https://github.com/pnp/sp-dev-fx-controls-react/issues/634)", + "`IconPicker`: get icons from `@uifabric/icons/lib/data/AllIconNames.json`", + "`ListView`: Sticky header with `className` instead of additional components [#696](https://github.com/pnp/sp-dev-fx-controls-react/pull/696)", + "`ListView`: `StickyHeader` code consistency [#697](https://github.com/pnp/sp-dev-fx-controls-react/pull/697)", + "`TreeView`: Added (optional) property 'defaultExpandedChildren' that controls the behavior of the expansion of child elements.[#698](https://github.com/pnp/sp-dev-fx-controls-react/pull/698)" + ], + "fixes": [ + "`RichText`: Cannot add link in first line [#672](https://github.com/pnp/sp-dev-fx-controls-react/issues/672)", + "`TaxonomyPicker`: Ability to reset the TaxonomyPicker (Remove all selected Terms) [#367](https://github.com/pnp/sp-dev-fx-controls-react/issues/367)", + "Documentation fix for `TaxonomyPicker`: the `disabled` property is a `boolean` and not a `string` as currently specified [#695](https://github.com/pnp/sp-dev-fx-controls-react/pull/695)", + "`ComboBoxListItemPicker`: update options when `listId` has been changed [#683](https://github.com/pnp/sp-dev-fx-controls-react/issues/683)", + "`FilePicker`: styles are updated to match OOB control [#700](https://github.com/pnp/sp-dev-fx-controls-react/issues/700)" + ] + }, + "contributions": [ + "[Abderahman88](https://github.com/Abderahman88)", + "[André Lage](https://github.com/aaclage)", + "[Gautam Sheth](https://github.com/gautamdsheth)" + ] + }, { "version": "2.0.0", "changes": { diff --git a/CHANGELOG.md b/CHANGELOG.md index ea7307729..943b20508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Releases +## 2.1.0 + +### Enhancements + +- `Carousel`: Ability to display indicators in a dedicated block [#681](https://github.com/pnp/sp-dev-fx-controls-react/pull/681) +- `FilePicker`: Org Assets are not displayed for non-admin users [#687](https://github.com/pnp/sp-dev-fx-controls-react/pull/687) +- `ListView`: Drag and Drop option [#679](https://github.com/pnp/sp-dev-fx-controls-react/issues/679) +- `FolderExplorerService`: support special characters if folder name [#691](https://github.com/pnp/sp-dev-fx-controls-react/pull/691) +- `ListView`: Sticky Header [#634](https://github.com/pnp/sp-dev-fx-controls-react/issues/634) +- `IconPicker`: get icons from `@uifabric/icons/lib/data/AllIconNames.json` +- `ListView`: Sticky header with `className` instead of additional components [#696](https://github.com/pnp/sp-dev-fx-controls-react/pull/696) +- `ListView`: `StickyHeader` code consistency [#697](https://github.com/pnp/sp-dev-fx-controls-react/pull/697) +- `TreeView`: Added (optional) property 'defaultExpandedChildren' that controls the behavior of the expansion of child elements.[#698](https://github.com/pnp/sp-dev-fx-controls-react/pull/698) + +### Fixes + +- `RichText`: Cannot add link in first line [#672](https://github.com/pnp/sp-dev-fx-controls-react/issues/672) +- `TaxonomyPicker`: Ability to reset the TaxonomyPicker (Remove all selected Terms) [#367](https://github.com/pnp/sp-dev-fx-controls-react/issues/367) +- Documentation fix for `TaxonomyPicker`: the `disabled` property is a `boolean` and not a `string` as currently specified [#695](https://github.com/pnp/sp-dev-fx-controls-react/pull/695) +- `ComboBoxListItemPicker`: update options when `listId` has been changed [#683](https://github.com/pnp/sp-dev-fx-controls-react/issues/683) +- `FilePicker`: styles are updated to match OOB control [#700](https://github.com/pnp/sp-dev-fx-controls-react/issues/700) + +### Contributors + +Special thanks to our contributors (in alphabetical order): [Abderahman88](https://github.com/Abderahman88), [André Lage](https://github.com/aaclage), [Gautam Sheth](https://github.com/gautamdsheth). + ## 2.0.0 ### Enhancements diff --git a/docs/documentation/docs/about/release-notes.md b/docs/documentation/docs/about/release-notes.md index ea7307729..943b20508 100644 --- a/docs/documentation/docs/about/release-notes.md +++ b/docs/documentation/docs/about/release-notes.md @@ -1,5 +1,31 @@ # Releases +## 2.1.0 + +### Enhancements + +- `Carousel`: Ability to display indicators in a dedicated block [#681](https://github.com/pnp/sp-dev-fx-controls-react/pull/681) +- `FilePicker`: Org Assets are not displayed for non-admin users [#687](https://github.com/pnp/sp-dev-fx-controls-react/pull/687) +- `ListView`: Drag and Drop option [#679](https://github.com/pnp/sp-dev-fx-controls-react/issues/679) +- `FolderExplorerService`: support special characters if folder name [#691](https://github.com/pnp/sp-dev-fx-controls-react/pull/691) +- `ListView`: Sticky Header [#634](https://github.com/pnp/sp-dev-fx-controls-react/issues/634) +- `IconPicker`: get icons from `@uifabric/icons/lib/data/AllIconNames.json` +- `ListView`: Sticky header with `className` instead of additional components [#696](https://github.com/pnp/sp-dev-fx-controls-react/pull/696) +- `ListView`: `StickyHeader` code consistency [#697](https://github.com/pnp/sp-dev-fx-controls-react/pull/697) +- `TreeView`: Added (optional) property 'defaultExpandedChildren' that controls the behavior of the expansion of child elements.[#698](https://github.com/pnp/sp-dev-fx-controls-react/pull/698) + +### Fixes + +- `RichText`: Cannot add link in first line [#672](https://github.com/pnp/sp-dev-fx-controls-react/issues/672) +- `TaxonomyPicker`: Ability to reset the TaxonomyPicker (Remove all selected Terms) [#367](https://github.com/pnp/sp-dev-fx-controls-react/issues/367) +- Documentation fix for `TaxonomyPicker`: the `disabled` property is a `boolean` and not a `string` as currently specified [#695](https://github.com/pnp/sp-dev-fx-controls-react/pull/695) +- `ComboBoxListItemPicker`: update options when `listId` has been changed [#683](https://github.com/pnp/sp-dev-fx-controls-react/issues/683) +- `FilePicker`: styles are updated to match OOB control [#700](https://github.com/pnp/sp-dev-fx-controls-react/issues/700) + +### Contributors + +Special thanks to our contributors (in alphabetical order): [Abderahman88](https://github.com/Abderahman88), [André Lage](https://github.com/aaclage), [Gautam Sheth](https://github.com/gautamdsheth). + ## 2.0.0 ### Enhancements diff --git a/docs/documentation/docs/assets/ListView-DragDrop.png b/docs/documentation/docs/assets/ListView-DragDrop.png new file mode 100644 index 000000000..e711b037e Binary files /dev/null and b/docs/documentation/docs/assets/ListView-DragDrop.png differ diff --git a/docs/documentation/docs/controls/Carousel.md b/docs/documentation/docs/controls/Carousel.md index 573fd0cd7..9332937da 100644 --- a/docs/documentation/docs/controls/Carousel.md +++ b/docs/documentation/docs/controls/Carousel.md @@ -128,7 +128,10 @@ The Carousel component can be configured with the following properties: | indicatorShape | CarouselIndicatorShape | no | Specifies indicators' shape. If onRenderIndicator is provided - this property is ignored | | indicatorClassName | string | no | Specifies additional class applied to slide position indicators | | indicatorStyle | React.CSSProperties | no | Specifies additional styles applied to slide position indicators | -| onRenderIndicator | (index: number, onClick: (e: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>, selectedIndex: number) => void) => JSX.Element | no | Function to render indicator element | +| onRenderIndicator | (index: number, onClick: (e: React.MouseEvent<HTMLElement> \| React.TouchEvent<HTMLElement>, selectedIndex: number) => void) => JSX.Element | no | Function to render indicator element | +| indicatorsDisplay | CarouselIndicatorsDisplay | no | Specifies display mode of the indicators. Default value `overlap`. | +| rootStyles | ICssInput | no | Allows to specify own styles for root element | +| indicatorsContainerStyles | ICssInput | no | Allows to specify own styles for indicators container when indicatorsDisplay is set to "block" | enum `CarouselButtonsLocation` @@ -160,6 +163,13 @@ Provides options for carousel indicators' shape. | square | Indicators displayed as squares | | rectangle | Indicators displayed as rectangles | +enum `CarouselIndicatorsDisplay` + +Provides options for carousel indicators display mode. +| Value | Description | +| overlap | Indicators are displayed on top of the carousel content | +| block | Reserves space for indicators | + Interface `ICarouselImageProps` Allows to easily render a set of `CarouselImage` components in the carousel diff --git a/docs/documentation/docs/controls/ListView.md b/docs/documentation/docs/controls/ListView.md index 04054e077..41e55eefe 100644 --- a/docs/documentation/docs/controls/ListView.md +++ b/docs/documentation/docs/controls/ListView.md @@ -8,6 +8,10 @@ This control renders a list view for the given set of items. ![ListView control with grouping](../assets/ListView-grouping.png) +**List view control with drag and drop applied** + +![ListView control with grouping](../assets/ListView-DragDrop.png) + ## How to use this control in your solutions - Check that you installed the `@pnp/spfx-controls-react` dependency. Check out the [getting started](../../#getting-started) page for more information about installing the dependency. @@ -30,7 +34,10 @@ import { ListView, IViewField, SelectionMode, GroupOrder, IGrouping } from "@pnp showFilter={true} defaultFilter="John" filterPlaceHolder="Search..." - groupByFields={groupByFields} /> + groupByFields={groupByFields} + dragDropFiles={true} + onDrop={this._getDropFiles} + stickyHeader={true} /> ``` - The control provides full text filtering through all the columns. If you want to exectue filtering on the specified columns, you can use syntax : ``:``. Use `':'` as a separator between column name and value. Control support both `'fieldName'` and `'name'` properties of IColumn interface. @@ -41,7 +48,6 @@ private _getSelection(items: any[]) { console.log('Selected items:', items); } ``` - - With the `groupByFields` property you can define an array of field objects which will be used for grouping. **Important**: the same order of the fields defines how grouping will be applied. In the snippet the `ListView` control will first group by the `Extension` and after that by the `Author` field. @@ -61,6 +67,16 @@ const groupByFields: IGrouping[] = [ !!! note "Extend ListView with a ContextualMenu" To extend the `ListView` control with a [ContextualMenu](https://developer.microsoft.com/en-us/fabric#/components/contextualmenu) refer to [ListView.ContextualMenu](./ListView.ContextualMenu.md). +- With the `onDrop` handler you can define a method that returns files that where drag and drop by user in the list view: + +```typescript +private _getDropFiles = (files) => { + for (var i = 0; i < files.length; i++) { + console.log(files[i].name); + } + } +``` + ## Implementation The ListView control can be configured with the following properties: @@ -78,6 +94,9 @@ The ListView control can be configured with the following properties: | filterPlaceHolder | string | no | Specify the placeholder for the filter text box. Default 'Search' | | showFilter | boolean | no | Specify if the filter text box should be rendered. | | defaultFilter | string | no | Specify the initial filter to be applied to the list. | +| dragDropFiles | boolean | no | Specify the drag and drop files area option. Default false. | +| onDrop | file | no | Event handler returns files from drag and drop. | +| stickyHeader | boolean | no | Specifies if the header of the `ListView`, including search box, is sticky | The `IViewField` has the following implementation: diff --git a/docs/documentation/docs/controls/PeoplePicker.md b/docs/documentation/docs/controls/PeoplePicker.md index 0eae79b8e..783d22931 100644 --- a/docs/documentation/docs/controls/PeoplePicker.md +++ b/docs/documentation/docs/controls/PeoplePicker.md @@ -35,13 +35,13 @@ import { PeoplePicker, PrincipalType } from "@pnp/spfx-controls-react/lib/People showtooltip={true} isRequired={true} disabled={true} - selectedItems={this._getPeoplePickerItems} + onChange={this._getPeoplePickerItems} showHiddenInUI={false} principalTypes={[PrincipalType.User]} resolveDelay={1000} /> ``` -- With the `selectedItems` property you can get the selected People in the Peoplepicker : +- With the `onChange` property you can get the selected People in the `PeoplePicker` : ```typescript private _getPeoplePickerItems(items: any[]) { diff --git a/docs/documentation/docs/controls/TaxonomyPicker.md b/docs/documentation/docs/controls/TaxonomyPicker.md index 037f8a131..6be321343 100644 --- a/docs/documentation/docs/controls/TaxonomyPicker.md +++ b/docs/documentation/docs/controls/TaxonomyPicker.md @@ -152,7 +152,7 @@ The TaxonomyPicker control can be configured with the following properties: | ---- | ---- | ---- | ---- | | panelTitle | string | yes | TermSet Picker Panel title. | | label | string | yes | Text displayed above the Taxonomy Picker. | -| disabled | string | no | Specify if the control needs to be disabled. | +| disabled | boolean | no | Specify if the control needs to be disabled. | | context | WebPartContext \| ExtensionContext | yes | Context of the current web part or extension. | | initialValues | IPickerTerms | no | Defines the selected by default term sets. | | allowMultipleSelections | boolean | no | Defines if the user can select only one or many term sets. Default value is false. | diff --git a/docs/documentation/docs/controls/TreeView.md b/docs/documentation/docs/controls/TreeView.md index 15d275871..df20dbf0a 100644 --- a/docs/documentation/docs/controls/TreeView.md +++ b/docs/documentation/docs/controls/TreeView.md @@ -39,6 +39,7 @@ import { TreeView, ITreeItem } from "@pnp/spfx-controls-react/lib/TreeView"; treeItemActionsDisplayMode={TreeItemActionsDisplayMode.ContextualMenu} defaultSelectedKeys={['key1', 'key2']}, expandToSelected={true} + defaultExpandedChildren={true} onSelect={this.onTreeItemSelect} onExpandCollapse={this.onTreeItemExpandCollapse} onRenderItem={this.renderCustomTreeItem} /> @@ -88,7 +89,7 @@ The `TreeView` control can be configured with the following properties: | Property | Type | Required | Description | |--------------------------------|----------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------| | items | ITreeItem[] | yes | An array of tree items to display. refer [example](#example-of-array-of-tree-items-used-to-render-control-as-in-first-screenshot). | -| defaultExpanded | boolean | no | Specify if the tree items are displayed as expanded by default (defaults to false). | +| defaultExpanded | boolean | no | Specify if the tree items are displayed as expanded by default (defaults to false. | | selectionMode | enum | no | Specifies the selection mode of tree view (defaults to Single selection). | | selectChildrenIfParentSelected | boolean | no | Specifies if the childrens should be selected when parent item is selected (defaults to false). | | showCheckboxes | boolean | yes | Specify if the checkboxes should be displayed for selection. | @@ -98,6 +99,7 @@ The `TreeView` control can be configured with the following properties: | onExpandCollapse | function | no | Defines a onExpandCollapse function to raise when the tree item has expanded or collapsed. | | onSelect | function | no | Captures the event of when the tree item selection has changed. | | onRenderItem | function | no | Optional callback to provide custom rendering of the item (default is simple text of item label and a checkbox for selection). | +| defaultExpandedChildren | boolean | no | Default expand / collapse behavior for the child nodes. By default this is set to true. | Enum `TreeViewSelectionMode` diff --git a/docs/documentation/docs/controls/fields/FieldRendererHelper.md b/docs/documentation/docs/controls/fields/FieldRendererHelper.md index 10b48e801..503eeea22 100644 --- a/docs/documentation/docs/controls/fields/FieldRendererHelper.md +++ b/docs/documentation/docs/controls/fields/FieldRendererHelper.md @@ -7,7 +7,7 @@ FieldRendererHelper class is used to automatically apply needed Field Control ba - Import the following modules to your component: ```TypeScript -import { FieldRendererHelper } from "@pnp/spfx-controls-react/lib/Utilities/FieldRendererHelper"; +import { FieldRendererHelper } from "@pnp/spfx-controls-react/lib/Utilities"; ``` - Use the `FieldRendererHelper.getFieldRenderer` method to asynchronously request proper React control (As the method returns `Promise` it should be called in one of React component lifecycle methods, for example, `componentWillMount` that will occur before `render`): diff --git a/docs/documentation/docs/index.md b/docs/documentation/docs/index.md index 3ea7965ed..e69039049 100644 --- a/docs/documentation/docs/index.md +++ b/docs/documentation/docs/index.md @@ -2,13 +2,13 @@ This repository provides developers with a set of reusable React controls that can be used in SharePoint Framework (SPFx) solutions. The project provides controls for building web parts and extensions. +![Placeholder example](./assets/placeholder-intro.png) + !!! attention In order to migrate to `v2` it is advicded to follow this guide: [Migrating from V1](./guides/migrate-from-v1). -![Placeholder example](./assets/placeholder-intro.png) - !!! attention - The controls project has a minimal dependency on SharePoint Framework version `1.3.0`. Be aware that the controls might not work in solutions your building for SharePoint 2016 with Feature Pack 2 on-premises. As for SharePoint 2016 with Feature Pack 2 version `1.1.0` of the SharePoint framework is the only version that can be used. SharePoint 2019 on-premises uses SharePoint framework `v1.4.0` and therefore should be fine to use with these controls. +`v2` version of the controls project has a minimal dependency on SharePoint Framework version `1.11.0`. `v1` has a minimal dependency on SharePoint Framework version `1.3.0`. Be aware that the controls might not work in solutions your building for SharePoint 2016 with Feature Pack 2 on-premises. As for SharePoint 2016 with Feature Pack 2 version `1.1.0` of the SharePoint framework is the only version that can be used. SharePoint 2019 on-premises uses SharePoint framework `v1.4.0` and therefore should be fine to use with these controls. ## Getting started diff --git a/package-lock.json b/package-lock.json index aea7ecb3f..5bc72f187 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@pnp/spfx-controls-react", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -31,9 +31,9 @@ } }, "@fluentui/date-time-utilities": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-7.7.0.tgz", - "integrity": "sha512-rgtGX5x1AeYUfilfkgP6ag+ZKx41BJcUs16k6iSxXxd/mt00DAPOGY8ODGikKFpjGKcUwjKfYBssyKkVHDucfA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-7.8.0.tgz", + "integrity": "sha512-qzlTp3t+PghebJsLK9JwZr91qBRZ/fOml8TQCIjdtsEn4mH6/ciCwir7Fj8iOEkwwTC0iKsEr1jfsITtJKWSmA==", "dev": true, "requires": { "@uifabric/set-version": "^7.0.22", @@ -66,9 +66,9 @@ } }, "@fluentui/react-focus": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-7.15.0.tgz", - "integrity": "sha512-xbxB0cbyEoUfQZ19pAqBeWCYJ/4IOu1FG4bhVjDimqSD7qKwJbLlJSDNwmHr05SWprdhmqJe23KOwsHMgyvnrw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-7.16.0.tgz", + "integrity": "sha512-TwB4Av7ID70ejisDIGkCZGKOxlquSazr6W+9Jv1JQAvsBLuj5XOspFJH4/Igjniw1LeO9QmAvFZeh/XRShiObw==", "dev": true, "requires": { "@fluentui/keyboard-key": "^0.2.11", @@ -135,7 +135,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-0.3.0.tgz", "integrity": "sha512-zHeH1PAmoFB3OkgU8f51E3oGHrL/CjuvdPBlb1SGpByUGNihAgH/CwvJohV9z0yPDkq+chfNUmxWA/oDVpbh6Q==", - "dev": true, "requires": { "@uifabric/set-version": "^7.0.22", "tslib": "^1.10.0" @@ -144,8 +143,7 @@ "tslib": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" } } }, @@ -1238,9 +1236,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -1548,9 +1546,9 @@ } }, "@microsoft/load-themed-styles": { - "version": "1.10.82", - "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.82.tgz", - "integrity": "sha512-p92TRErd5xpYkSy7TjNDs+0LmxDBSusmLSgnWCv7xZf9DGXZCW08ZiUVlbsaj3e49kGskOaWQvarMDejm2b+FQ==" + "version": "1.10.90", + "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.90.tgz", + "integrity": "sha512-nJaQ6Yij68+GeaSt5ZgK70l5dn2aNGlc9EeES2B054anZTmmBhfaGpciIoSyPZrOg6PSAJjGWTXwd1ovMKOk1w==" }, "@microsoft/loader-cased-file": { "version": "1.11.0", @@ -2822,9 +2820,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.29.tgz", - "integrity": "sha512-zLo9rjUeQ5+QVhOufDwrb3XKyso31fJBJnk9wUUQIBDExF/O4LryvpOfozfUaxgqifTnlt7FyqsAPXUq5yFZSA==", + "version": "10.17.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.32.tgz", + "integrity": "sha512-EUq+cjH/3KCzQHikGnNbWAGe548IFLSm93Vl8xA7EuYEEATiyOVDyEVuGkowL7c9V69FF/RiZSAOCFPApMs/ig==", "dev": true }, "minimist": { @@ -2856,9 +2854,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.29.tgz", - "integrity": "sha512-zLo9rjUeQ5+QVhOufDwrb3XKyso31fJBJnk9wUUQIBDExF/O4LryvpOfozfUaxgqifTnlt7FyqsAPXUq5yFZSA==", + "version": "10.17.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.32.tgz", + "integrity": "sha512-EUq+cjH/3KCzQHikGnNbWAGe548IFLSm93Vl8xA7EuYEEATiyOVDyEVuGkowL7c9V69FF/RiZSAOCFPApMs/ig==", "dev": true } } @@ -3440,9 +3438,9 @@ }, "dependencies": { "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" } } }, @@ -3463,10 +3461,11 @@ } }, "@uifabric/react-hooks": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@uifabric/react-hooks/-/react-hooks-7.11.0.tgz", - "integrity": "sha512-iU7c+JR+rY5kBTPmrF8F6iJBQw309MX/MvOx6ElhmNceBaa8BqDuqR9+TVfkH+Bxp37bmZnCaQF5w4+QWHZ81g==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@uifabric/react-hooks/-/react-hooks-7.13.0.tgz", + "integrity": "sha512-A7K0YFHHr10hB/txsqpPX6PhNhHEv8U7JpY3O81oqlZwSsHroJklQdd897JkAYJUUR+gWe2kQyXkkcaMDdqXjg==", "requires": { + "@fluentui/react-window-provider": "^0.3.0", "@uifabric/set-version": "^7.0.22", "@uifabric/utilities": "^7.31.0", "tslib": "^1.10.0" @@ -3589,20 +3588,20 @@ } }, "office-ui-fabric-react": { - "version": "7.134.1", - "resolved": "https://registry.npmjs.org/office-ui-fabric-react/-/office-ui-fabric-react-7.134.1.tgz", - "integrity": "sha512-yQhPdt5kQfzI/MQnqQMu9lf2mgdHSogEfVIYgfOjbvfMJoUzqA/hH3X2Z7RbncdJ/ca2H+GXVp5GvSgahCOs6g==", + "version": "7.137.1", + "resolved": "https://registry.npmjs.org/office-ui-fabric-react/-/office-ui-fabric-react-7.137.1.tgz", + "integrity": "sha512-6m1M9m5psaJqhWwroVp1L0G8q66scLMsQRi+gQ/fY3f75ipGSABGeQ86d4P0ilKaYcLVYIzosocPIZKLbBVpnQ==", "dev": true, "requires": { - "@fluentui/date-time-utilities": "^7.7.0", - "@fluentui/react-focus": "^7.15.0", + "@fluentui/date-time-utilities": "^7.8.0", + "@fluentui/react-focus": "^7.16.0", "@fluentui/react-icons": "^0.3.0", "@fluentui/react-window-provider": "^0.3.0", "@microsoft/load-themed-styles": "^1.10.26", "@uifabric/foundation": "^7.9.0", "@uifabric/icons": "^7.5.0", "@uifabric/merge-styles": "^7.18.0", - "@uifabric/react-hooks": "^7.11.0", + "@uifabric/react-hooks": "^7.13.0", "@uifabric/set-version": "^7.0.22", "@uifabric/styling": "^7.16.0", "@uifabric/utilities": "^7.31.0", @@ -4891,9 +4890,9 @@ } }, "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", "dev": true, "requires": { "readable-stream": "^2.3.5", @@ -5141,15 +5140,15 @@ } }, "browserslist": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz", - "integrity": "sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz", + "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001111", - "electron-to-chromium": "^1.3.523", + "caniuse-lite": "^1.0.30001125", + "electron-to-chromium": "^1.3.564", "escalade": "^3.0.2", - "node-releases": "^1.1.60" + "node-releases": "^1.1.61" } }, "bser": { @@ -5424,9 +5423,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001122", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001122.tgz", - "integrity": "sha512-pxjw28CThdrqfz06nJkpAc5SXM404TXB/h5f4UJX+rrXJKE/1bu/KAILc2AY+O6cQIFtRjV9qOR2vaEp9LDGUA==", + "version": "1.0.30001129", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001129.tgz", + "integrity": "sha512-9945fTVKS810DZITpsAbuhQG7Lam0tEfVbZlsBaCFZaszepbryrArS05PWmJSBQ6mta+v9iz0pUIAbW1eBILIg==", "dev": true }, "capture-exit": { @@ -6236,9 +6235,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -6623,9 +6622,9 @@ }, "dependencies": { "abab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.4.tgz", - "integrity": "sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, "tr46": { @@ -7080,9 +7079,9 @@ }, "dependencies": { "domelementtype": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", "dev": true } } @@ -7136,9 +7135,9 @@ } }, "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", - "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, "requires": { "is-obj": "^2.0.0" @@ -7272,9 +7271,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.558", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.558.tgz", - "integrity": "sha512-r6th6b/TU2udqVoUDGWHF/z2ACJVnEei0wvWZf/nt+Qql1Vxh60ZYPhQP46j4D73T/Jou7hl4TqQfxben+qJTg==", + "version": "1.3.567", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.567.tgz", + "integrity": "sha512-1aKkw0Hha1Bw9JA5K5PT5eFXC/TXbkJvUfNSNEciPUMgSIsRJZM1hF2GUEAGZpAbgvd8En21EA+Lv820KOhvqA==", "dev": true }, "elliptic": { @@ -9472,9 +9471,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -10434,9 +10433,9 @@ "dev": true }, "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==" }, "is-ci": { "version": "1.2.1", @@ -10580,6 +10579,11 @@ "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", "dev": true }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -13492,9 +13496,9 @@ } }, "moment": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", - "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.28.0.tgz", + "integrity": "sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw==" }, "move-concurrently": { "version": "1.0.1", @@ -13758,9 +13762,9 @@ } }, "node-releases": { - "version": "1.1.60", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", - "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "version": "1.1.61", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.61.tgz", + "integrity": "sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g==", "dev": true }, "node-sass": { @@ -14036,14 +14040,35 @@ } }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "object.defaults": { @@ -15011,9 +15036,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -16464,9 +16489,9 @@ } }, "rxjs": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", - "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -16578,9 +16603,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -17591,9 +17616,9 @@ "dev": true }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", "dev": true } } @@ -17656,9 +17681,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -18270,14 +18295,14 @@ "dev": true }, "ua-parser-js": { - "version": "0.7.21", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", - "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==" + "version": "0.7.22", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz", + "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==" }, "uglify-js": { - "version": "3.10.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.3.tgz", - "integrity": "sha512-Lh00i69Uf6G74mvYpHCI9KVVXLcHW/xu79YTvH7Mkc9zyKUeSPz0owW0dguj0Scavns3ZOh3wY63J0Zb97Za2g==", + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.4.tgz", + "integrity": "sha512-kBFT3U4Dcj4/pJ52vfjCSfyLyvG9VYYuGYPmrPvAxRw/i7xHiT4VvCev+uiEMcEEiu6UNB6KgWmGtSUYIWScbw==", "dev": true, "optional": true }, @@ -18983,9 +19008,9 @@ "dev": true }, "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -19120,9 +19145,9 @@ } }, "whatwg-fetch": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.0.tgz", - "integrity": "sha512-rsum2ulz2iuZH08mJkT0Yi6JnKhwdw4oeyMjokgxd+mmqYSd9cPpOQf01TIWgjxG/U4+QR+AwKq6lSbXVxkyoQ==" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz", + "integrity": "sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ==" }, "whatwg-mimetype": { "version": "2.3.0", diff --git a/package.json b/package.json index 31995c175..5aacc437b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@pnp/spfx-controls-react", "description": "Reusable React controls for SharePoint Framework solutions", - "version": "2.0.0", + "version": "2.1.0", "engines": { "node": ">=10" }, @@ -9,6 +9,7 @@ "build": "gulp build", "clean": "gulp clean", "test": "gulp test", + "serve": "gulp serve", "prepublishOnly": "gulp", "versionUpdater": "gulp versionUpdater", "karma": "karma start --circle true", @@ -28,6 +29,7 @@ "@microsoft/sp-webpart-base": "1.11.0", "@pnp/sp": "2.0.6", "@pnp/telemetry-js": "2.0.0", + "@uifabric/icons": "7.3.0", "chart.js": "2.7.3", "color": "3.1.2", "lodash": "4.17.13", @@ -92,5 +94,10 @@ "Rodrigues, Joel <>", "Struyf, Elio ", "Terentiev, Alex " - ] + ], + "husky": { + "hooks": { + "pre-commit": "npm run changelog" + } + } } diff --git a/src/common/telemetry/version.ts b/src/common/telemetry/version.ts index ff33a1842..8dd1e757d 100644 --- a/src/common/telemetry/version.ts +++ b/src/common/telemetry/version.ts @@ -1 +1 @@ -export const version: string = "2.0.0"; \ No newline at end of file +export const version: string = "2.1.0"; \ No newline at end of file diff --git a/src/controls/carousel/Carousel.module.scss b/src/controls/carousel/Carousel.module.scss index 427ed0743..861be2816 100644 --- a/src/controls/carousel/Carousel.module.scss +++ b/src/controls/carousel/Carousel.module.scss @@ -1,259 +1,288 @@ @import "~office-ui-fabric-react/dist/sass/References.scss"; @keyframes slideleft { - 0% { - left: 0; - right: 0; - } - 100% { - left: -100%; - right: 100%; - } + 0% { + left: 0; + right: 0; + } + 100% { + left: -100%; + right: 100%; + } } @keyframes slideright { - 0% { - left: 0; - right: 0; - } - 100% { - left: 100%; - right: -100%; - } + 0% { + left: 0; + right: 0; + } + 100% { + left: 100%; + right: -100%; + } } @keyframes slidefromright { - 0% { - left: 100%; - right: -100%; - } - 100% { - left: 0; - right: 0; - } + 0% { + left: 100%; + right: -100%; + } + 100% { + left: 0; + right: 0; + } } @keyframes slidefromleft { - 0% { - left: -100%; - right: 100%; - } - 100% { - left: 0; - right: 0; - } + 0% { + left: -100%; + right: 100%; + } + 100% { + left: 0; + right: 0; + } +} + +.root { + display: flex; + flex-direction: column; + flex-grow: 2; +} + +.indicatorsContainer { + align-items: center; + + .indicators { + @extend .indicators; + + & > li { + background-color: "[theme: black, default: #000]"; + } + } +} + +.indicators { + z-index: 10; + display: flex; + justify-content: center; + list-style: none; + padding-inline-start: 0; + margin-block-start: 0.5em; + margin-block-end: 0.5em; + + &.rectangle > li { + width: 25px; + height: 5px; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + } + + &.square > li { + width: 10px; + height: 10px; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + } + + &.circle > li { + width: 10px; + height: 10px; + border-radius: 50%; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + } + + & > li { + flex: 0 1 auto; + text-indent: -999px; + cursor: pointer; + opacity: 0.5; + transition: opacity 0.5 ease; + margin: 0 3px; + box-sizing: content-box; + background-clip: padding-box; + + &.active { + opacity: 1; + } + } } .container { - display: flex; - - // Styles for elements container - .contentContainer { - flex-grow: 2; - position: relative; - overflow: hidden; - - .slideWrapper { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - - &.left { - left: -100%; - right: 100%; - } - - &.right { - left: 100%; - right: -100%; - } - - &.slideLeft { - animation: slideleft linear 0.6s; - } - &.slideRight { - animation: slideright linear 0.6s; - } - &.slideFromRight { - animation: slidefromright linear 0.6s; - } - &.slideFromLeft { - animation: slidefromleft linear 0.6s; - } - } - - .carouselImage { - overflow: hidden; - width: 100%; - height: 100%; - position: relative; - - .image { - width: 100%; - height: 100%; - } - - &.staticDetails { - .details { - top: 60%; - } - } - - .details { - background-color: rgba(0, 0, 0, 0.8); - box-sizing: border-box; - color: white; - height: 40%; - left: 0; - padding: 15px; - position: absolute; - right: 0; - top: 100%; - transition: all 0.5s ease; - - .title { - display: block; - @include ms-fontSize-l; - padding-bottom: 5px; - } - } - } - - &:hover { - .carouselImage.dynamicDetails { - .details { - top: 60%; - } - } - } - } - - .indicators { - position: absolute; - right: 0; - bottom: 0; - left: 0; - z-index: 10; - display: flex; - justify-content: center; - list-style: none; - - &.rectangle > li { - width: 25px; - height: 5px; - border-top: 10px solid transparent; - border-bottom: 10px solid transparent; - } - - &.square > li { - width: 10px; - height: 10px; - border-top: 10px solid transparent; - border-bottom: 10px solid transparent; - } - - &.circle > li { - width: 10px; - height: 10px; - border-radius: 50%; - border-top: 10px solid transparent; - border-bottom: 10px solid transparent; - } - - & > li { - flex: 0 1 auto; - text-indent: -999px; - cursor: pointer; - background-color: "[theme:white, default: #fff]"; - opacity: 0.5; - transition: opacity 0.5 ease; - margin: 0 3px; - box-sizing: content-box; - background-clip: padding-box; - - &.active { - opacity: 1; - } - } - } - - .loadingComponent { - margin: auto; - } - - // Bottons containers - .buttonLocations { - cursor: pointer; - flex-direction: column; - } - - .centralButtonsContainer { - @extend .buttonLocations; - justify-content: center; - } - .topButtonsContainer { - @extend .buttonLocations; - justify-content: left; - } - .bottomButtonsContainer { - @extend .buttonLocations; - justify-content: left; - flex-direction: column-reverse; - } - - // ButtonContainer display mode - .buttonsOnlyPrevButton { - position: absolute; - left: 0; - z-index: 1; - } - .buttonsOnlyPrevButton:hover { - cursor: pointer; - } - - // Buttons styles - .buttonsOnlyNextButton { - position: absolute; - left: -32px; - z-index: 1; - } - .buttonsOnlyNextButton:hover { - cursor: pointer; - } - - .buttonsContainer { - display: flex; - align-items: center; - background-color: transparent; - cursor: pointer; - } - .buttonsOnlyContainer { - @extend .buttonsContainer; - position: relative; - width: 0px; - } - - .blockButtonsContainer { - @extend .buttonsContainer; - min-height: 100%; - min-width: 32px; - } - .blockButtonsContainer:hover { - @extend .buttonsContainer; - background-color: #f4f4f4; - opacity: 0.5; - } - - .hiddenButtonsContainer { - @extend .buttonsContainer; - min-height: 100%; - min-width: 32px; - opacity: 0; - } - .hiddenButtonsContainer:hover { - opacity: 0.5; - background-color: #f4f4f4; - } + display: flex; + + // Styles for elements container + .contentContainer { + flex-grow: 2; + position: relative; + overflow: hidden; + + .slideWrapper { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + + &.left { + left: -100%; + right: 100%; + } + + &.right { + left: 100%; + right: -100%; + } + + &.slideLeft { + animation: slideleft linear 0.6s; + } + &.slideRight { + animation: slideright linear 0.6s; + } + &.slideFromRight { + animation: slidefromright linear 0.6s; + } + &.slideFromLeft { + animation: slidefromleft linear 0.6s; + } + } + + .carouselImage { + overflow: hidden; + width: 100%; + height: 100%; + position: relative; + + .image { + width: 100%; + height: 100%; + } + + &.staticDetails { + .details { + top: 60%; + } + } + + .details { + background-color: rgba(0, 0, 0, 0.8); + box-sizing: border-box; + color: white; + height: 40%; + left: 0; + padding: 15px; + position: absolute; + right: 0; + top: 100%; + transition: all 0.5s ease; + + .title { + display: block; + @include ms-fontSize-l; + padding-bottom: 5px; + } + } + } + + .indicators { + @extend .indicators; + + position: absolute; + right: 0; + bottom: 0; + left: 0; + + & > li { + background-color: "[theme:white, default: #fff]"; + } + } + + &:hover { + .carouselImage.dynamicDetails { + .details { + top: 60%; + } + } + } + } + + .loadingComponent { + margin: auto; + } + + // Bottons containers + .buttonLocations { + cursor: pointer; + flex-direction: column; + } + + .centralButtonsContainer { + @extend .buttonLocations; + justify-content: center; + } + .topButtonsContainer { + @extend .buttonLocations; + justify-content: left; + } + .bottomButtonsContainer { + @extend .buttonLocations; + justify-content: left; + flex-direction: column-reverse; + } + + // ButtonContainer display mode + .buttonsOnlyPrevButton { + position: absolute; + left: 0; + z-index: 1; + } + .buttonsOnlyPrevButton:hover { + cursor: pointer; + } + + // Buttons styles + .buttonsOnlyNextButton { + position: absolute; + left: -32px; + z-index: 1; + } + .buttonsOnlyNextButton:hover { + cursor: pointer; + } + + .buttonsContainer { + display: flex; + align-items: center; + background-color: transparent; + cursor: pointer; + } + .buttonsOnlyContainer { + @extend .buttonsContainer; + position: relative; + width: 0px; + } + + .blockButtonsContainer { + @extend .buttonsContainer; + min-height: 100%; + min-width: 32px; + } + .blockButtonsContainer:hover { + @extend .buttonsContainer; + background-color: #f4f4f4; + opacity: 0.5; + } + + .hiddenButtonsContainer { + @extend .buttonsContainer; + min-height: 100%; + min-width: 32px; + opacity: 0; + } + .hiddenButtonsContainer:hover { + opacity: 0.5; + background-color: #f4f4f4; + } } diff --git a/src/controls/carousel/Carousel.tsx b/src/controls/carousel/Carousel.tsx index 5c080c593..2f5436c61 100644 --- a/src/controls/carousel/Carousel.tsx +++ b/src/controls/carousel/Carousel.tsx @@ -12,6 +12,7 @@ import { Spinner } from "office-ui-fabric-react/lib/Spinner"; import { isArray } from "@pnp/common"; import * as telemetry from '../../common/telemetry'; import CarouselImage from "./CarouselImage"; +import { CarouselIndicatorsDisplay } from "./ICarouselProps"; export class Carousel extends React.Component { private _intervalId: number | undefined; @@ -67,7 +68,10 @@ export class Carousel extends React.Component { nextButtonIconName = 'ChevronRight', loadingComponent = , pauseOnHover, - interval + interval, + indicatorsDisplay, + rootStyles, + indicatorsContainerStyles } = this.props; const processing = processingState === ProcessingState.processing; @@ -78,43 +82,48 @@ export class Carousel extends React.Component { const element = this.getElementToDisplay(currentIndex); return ( -
-
{ if (!prevButtonDisabled) { this.onCarouselButtonClicked(false); } }} > - { this.onCarouselButtonClicked(false); }} /> -
- -
- { - processing && -
- {loadingComponent} -
- } - - { - !processing && this.renderSlide(element) - } - {this.getIndicatorsElement()} -
- -
{ if (!nextButtonDisabled) { this.onCarouselButtonClicked(true); } }}> - { this.onCarouselButtonClicked(true); }} /> +
+
+
{ if (!prevButtonDisabled) { this.onCarouselButtonClicked(false); } }} > + { this.onCarouselButtonClicked(false); }} /> +
+
+ { + processing && +
+ {loadingComponent} +
+ } + + { + !processing && this.renderSlide(element) + } + {indicatorsDisplay !== CarouselIndicatorsDisplay.block && this.getIndicatorsElement()} +
+ +
{ if (!nextButtonDisabled) { this.onCarouselButtonClicked(true); } }}> + { this.onCarouselButtonClicked(true); }} /> +
+ {indicatorsDisplay === CarouselIndicatorsDisplay.block && +
+ {this.getIndicatorsElement()} +
}
); } @@ -342,7 +351,7 @@ export class Carousel extends React.Component { if (nextButtonClicked && this.props.onMoveNextClicked) { this.props.onMoveNextClicked(nextIndex); } - else if(this.props.onMovePrevClicked) { + else if (this.props.onMovePrevClicked) { this.props.onMovePrevClicked(nextIndex); } } diff --git a/src/controls/carousel/ICarouselProps.ts b/src/controls/carousel/ICarouselProps.ts index 3d06a780d..560721c9b 100644 --- a/src/controls/carousel/ICarouselProps.ts +++ b/src/controls/carousel/ICarouselProps.ts @@ -46,6 +46,20 @@ export enum CarouselIndicatorShape { rectangle } +/** + * Provides options for carousel indicators display mode + */ +export enum CarouselIndicatorsDisplay { + /** + * Indicators are displayed on top of the carousel content + */ + overlap = 1, + /** + * Reserves space for indicators + */ + block +} + export interface ICarouselProps { /** * Specifies the initial index of the element to be displayed. @@ -183,4 +197,19 @@ export interface ICarouselProps { */ onRenderIndicator?: (index: number, onClick: (e: React.MouseEvent | React.TouchEvent, selectedIndex: number) => void) => JSX.Element; + /** + * Specifies display mode of the indicators + */ + indicatorsDisplay?: CarouselIndicatorsDisplay; + + /** + * Allows to specify own styles for root element. + */ + rootStyles?: ICssInput; + + /** + * Allows to specify own styles for indicators container when indicatorsDisplay is set to "block". + */ + indicatorsContainerStyles?: ICssInput; + } diff --git a/src/controls/filePicker/FilePicker.module.scss b/src/controls/filePicker/FilePicker.module.scss index e57e2715b..1bf84195b 100644 --- a/src/controls/filePicker/FilePicker.module.scss +++ b/src/controls/filePicker/FilePicker.module.scss @@ -28,13 +28,6 @@ margin: 0; } -.filePicker - :global(.ms-Panel-main) - :global(.ms-Panel-contentInner) - :global(.ms-Panel-content) { - height: 100%; -} - .filePicker :global(.ms-Nav-link) { position: relative; -webkit-font-smoothing: antialiased; @@ -59,11 +52,11 @@ outline: transparent; border-width: initial; border-style: none; - border-color: initial; border-image: initial; text-decoration: none; border-radius: 0px; overflow: hidden; + border-color: transparent; } .filePicker :global(.is-selected) :global(.ms-Nav-link) { @@ -90,8 +83,6 @@ outline: transparent; border-width: initial; border-style: none; - border-color: initial; - border-image: initial; text-decoration: none; border-radius: 0px; overflow: hidden; @@ -125,6 +116,7 @@ } .nav { + position: absolute; height: 100%; color: $ms-color-neutralLighter; } @@ -154,27 +146,33 @@ .breadcrumbNav { margin-top: 0px; + padding: 22px 32px; } .breadcrumbNavItem { color: $ms-color-neutralPrimary; - font-size: 28px; - font-weight: 100; - padding: 22px 10px 20px 32px; + font-size: 24px; + font-weight: 600; + padding: 22px 8px 20px 0; +} + +.breadcrumbNav :global(.ms-Breadcrumb-listItem:last-child .ms-Breadcrumb-itemLink) { + font-weight: 600; } .tab { - padding: 0 32px; overflow-y: auto; - -webkit-box-flex: 2; - -ms-flex-positive: 2; flex-grow: 2; } + +.tabOffset { + padding: 0 32px; +} + .tabFiles { overflow-y: hidden; overflow-x: hidden; - -webkit-box-flex: 2; - -ms-flex-positive: 2; flex-grow: 2; + padding: 0 32px; } .scrollablePaneWrapper { height: 75vh; @@ -236,21 +234,17 @@ .tabHeader { color: $ms-color-neutralPrimary; margin: 0; - font-size: 28px; - font-weight: 100; + font-size: 24px; + font-weight: 600; padding: 22px 0 20px 32px; } .tabContainer { height: 100%; - -webkit-box-sizing: border-box; box-sizing: border-box; display: -webkit-box; display: -ms-flexbox; display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; flex-direction: column; } @@ -292,6 +286,10 @@ background-color: red; } +.itemPickerTopBar :global(.ms-CommandBarItem-link) { + border-color: transparent; +} + .commandBarNoChevron :global(.ms-CommandBarItem-chevronDown) { display: none; } diff --git a/src/controls/filePicker/LinkFilePickerTab/LinkFilePickerTab.tsx b/src/controls/filePicker/LinkFilePickerTab/LinkFilePickerTab.tsx index 4503da6d8..8a4a15269 100644 --- a/src/controls/filePicker/LinkFilePickerTab/LinkFilePickerTab.tsx +++ b/src/controls/filePicker/LinkFilePickerTab/LinkFilePickerTab.tsx @@ -5,6 +5,7 @@ import { GeneralHelper } from '../../../Utilities'; import { IFilePickerResult } from '../FilePicker.types'; import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/components/Button'; import { TextField } from 'office-ui-fabric-react/lib/TextField'; +import { css } from '@uifabric/utilities/lib/css'; import * as strings from 'ControlStrings'; import styles from './LinkFilePickerTab.module.scss'; @@ -23,7 +24,7 @@ export default class LinkFilePickerTab extends React.Component

{strings.LinkHeader}

-
+
- +
{this.state.libraryAbsolutePath !== undefined && diff --git a/src/controls/filePicker/RecentFilesTab/RecentFilesTab.tsx b/src/controls/filePicker/RecentFilesTab/RecentFilesTab.tsx index b30a2aa86..1b336be2d 100644 --- a/src/controls/filePicker/RecentFilesTab/RecentFilesTab.tsx +++ b/src/controls/filePicker/RecentFilesTab/RecentFilesTab.tsx @@ -5,7 +5,7 @@ import { Spinner } from 'office-ui-fabric-react/lib/Spinner'; import { FocusZone } from 'office-ui-fabric-react/lib/FocusZone'; import { List } from 'office-ui-fabric-react/lib/List'; import { IRectangle } from 'office-ui-fabric-react/lib/Utilities'; -import { css } from "@uifabric/utilities/lib/css"; +import { css } from '@uifabric/utilities/lib/css'; import { Selection, SelectionMode, SelectionZone } from 'office-ui-fabric-react/lib/Selection'; import { Image, ImageFit } from 'office-ui-fabric-react/lib/Image'; import { Check } from 'office-ui-fabric-react/lib/Check'; @@ -26,7 +26,7 @@ const ROWS_PER_PAGE = 3; /** * Maximum row height */ -const MAX_ROW_HEIGHT = 250; +const MAX_ROW_HEIGHT = 175; export default class RecentFilesTab extends React.Component { private _columnCount: number; @@ -71,27 +71,27 @@ export default class RecentFilesTab extends React.Component - +
+

{strings.RecentDocumentsHeader}

- - +
+
{isLoading ? this._renderSpinner() : results === undefined || results.length < 1 ? this._renderPlaceholder() : this._renderGridList() } - - - +
+
+
this._handleSave()} className={styles.actionButton} >{strings.OpenButtonLabel} this._handleClose()} className={styles.actionButton}>{strings.CancelButtonLabel} - - - +
+
+
); } diff --git a/src/controls/filePicker/SiteFilePickerTab/SiteFilePickerTab.tsx b/src/controls/filePicker/SiteFilePickerTab/SiteFilePickerTab.tsx index c8a063617..ad15cfb37 100644 --- a/src/controls/filePicker/SiteFilePickerTab/SiteFilePickerTab.tsx +++ b/src/controls/filePicker/SiteFilePickerTab/SiteFilePickerTab.tsx @@ -37,7 +37,7 @@ export default class SiteFilePickerTab extends React.Component
- +
{this.state.libraryAbsolutePath === undefined && diff --git a/src/controls/filePicker/StockImagesTab/StockImages.module.scss b/src/controls/filePicker/StockImagesTab/StockImages.module.scss index a705e7dee..57bd178a6 100644 --- a/src/controls/filePicker/StockImagesTab/StockImages.module.scss +++ b/src/controls/filePicker/StockImagesTab/StockImages.module.scss @@ -13,6 +13,6 @@ padding: 0px; overflow: hidden; - margin-top:-30px; - margin-left: -35px; -} \ No newline at end of file + //margin-top:-30px; + //margin-left: -35px; +} diff --git a/src/controls/filePicker/UploadFilePickerTab/UploadFilePickerTab.tsx b/src/controls/filePicker/UploadFilePickerTab/UploadFilePickerTab.tsx index b80a11ca9..5ebbe6bdc 100644 --- a/src/controls/filePicker/UploadFilePickerTab/UploadFilePickerTab.tsx +++ b/src/controls/filePicker/UploadFilePickerTab/UploadFilePickerTab.tsx @@ -4,6 +4,7 @@ import { IUploadFilePickerTabProps, IUploadFilePickerTabState } from '.'; import { IFilePickerResult } from '../FilePicker.types'; import { GeneralHelper } from '../../../common/utilities'; import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/components/Button'; +import { css } from '@uifabric/utilities/lib/css'; import * as strings from 'ControlStrings'; import styles from './UploadFilePickerTab.module.scss'; @@ -28,7 +29,7 @@ export default class UploadFilePickerTab extends React.Component

{strings.UploadFileHeader}

-
+
- -

{strings.WebSearchLinkLabel}

- - {this.props.bingSearchService && this._renderSearchBox()} +

{strings.WebSearchLinkLabel}

-
- { !query && this._renderSearchSuggestions() } - { query && results && this._renderSearchResults() } + {this.props.bingSearchService && this._renderSearchBox()} +
+ {!query && this._renderSearchSuggestions()} + {query && results && this._renderSearchResults()}
{ diff --git a/src/controls/filePicker/controls/DocumentLibraryBrowser/DocumentLibraryBrowser.module.scss b/src/controls/filePicker/controls/DocumentLibraryBrowser/DocumentLibraryBrowser.module.scss index 96ca7d85a..d17ed7ce7 100644 --- a/src/controls/filePicker/controls/DocumentLibraryBrowser/DocumentLibraryBrowser.module.scss +++ b/src/controls/filePicker/controls/DocumentLibraryBrowser/DocumentLibraryBrowser.module.scss @@ -92,5 +92,5 @@ } .documentLibraryBrowserContainer { - padding: 0 32px; + padding: 0; } diff --git a/src/controls/iconPicker/IconPicker.tsx b/src/controls/iconPicker/IconPicker.tsx index e2e517b8c..67d858470 100644 --- a/src/controls/iconPicker/IconPicker.tsx +++ b/src/controls/iconPicker/IconPicker.tsx @@ -13,10 +13,13 @@ import { IIconPickerState } from './IIconPickerState'; import * as telemetry from '../../common/telemetry'; import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react/lib/Dialog'; import { initializeIcons } from 'office-ui-fabric-react/lib/Icons'; +import { FluentIconsService } from '../../services/FluentIconsService'; export class IconPicker extends React.Component { private radioIdBase: string = getId("radio"); + private readonly _fluentIconsService: FluentIconsService; + constructor(props: IIconPickerProps) { super(props); @@ -25,8 +28,10 @@ export class IconPicker extends React.Component { this.setState({ isPanelOpen: true, - items: IconNames.Icons + items: this._fluentIconsService.getAll() //IconNames.Icons }); } @@ -126,17 +131,19 @@ export class IconPicker extends React.Component { - this.setState({ items: IconNames.Icons }); + this.setState({ + items: this._fluentIconsService.getAll() //IconNames.Icons + }); } private onChange = (newValue?: string): void => { let items: string[]; if (newValue && newValue.trim().length > 2) { - items = IconNames.Icons.filter(item => { + items = this._fluentIconsService.search(newValue); /*IconNames.Icons.filter(item => { return item.toLocaleLowerCase().indexOf(newValue.toLocaleLowerCase()) !== -1; - }); + });*/ } else { - items = IconNames.Icons; + items = this._fluentIconsService.getAll();//IconNames.Icons; } this.setState({ items: items diff --git a/src/controls/listItemPicker/ComboBoxListItemPicker.tsx b/src/controls/listItemPicker/ComboBoxListItemPicker.tsx index 44688f39e..059927920 100644 --- a/src/controls/listItemPicker/ComboBoxListItemPicker.tsx +++ b/src/controls/listItemPicker/ComboBoxListItemPicker.tsx @@ -31,10 +31,10 @@ export class ComboBoxListItemPicker extends React.Component { + protected async loadOptions(props: IComboBoxListItemPickerProps, isInitialLoad?: boolean): Promise { const { filter, keyColumnInternalName, @@ -44,7 +44,7 @@ export class ComboBoxListItemPicker extends React.Component { + if (nextProps.listId !== this.props.listId) { + await this.loadOptions(nextProps, false); this.selectedItems = []; } } + /*public componentDidUpdate(prevProps: IComboBoxListItemPickerProps, prevState: IComboBoxListItemPickerState): void { + if (this.props.listId !== prevProps.listId) { + + } + }*/ + /** * Render the field */ diff --git a/src/controls/listView/IListView.ts b/src/controls/listView/IListView.ts index 29ba45bd4..03941e5d7 100644 --- a/src/controls/listView/IListView.ts +++ b/src/controls/listView/IListView.ts @@ -9,6 +9,14 @@ export enum GroupOrder { } export interface IListViewProps { + /** + * Specify if drag and drop option is selected. + **/ + dragDropFiles?: boolean; + /** + * Handler to return the files from drag and drop. + **/ + onDrop?: any; /** * Specify the name of the file URL path which will be used to show the file icon. */ @@ -55,6 +63,11 @@ export interface IListViewProps { * Specify the initial filter to be applied to the list. */ defaultFilter?: string; + /** + * Boolean value to create a fixed/sticky header. + * Set to false by default + */ + stickyHeader?: boolean; } export interface IListViewState { @@ -73,6 +86,9 @@ export interface IListViewState { columns?: IColumn[]; groups?: IGroup[]; + + dragStatus?: boolean; + } export interface IGrouping { diff --git a/src/controls/listView/ListView.DragDrop.module.scss b/src/controls/listView/ListView.DragDrop.module.scss new file mode 100644 index 000000000..53b79831d --- /dev/null +++ b/src/controls/listView/ListView.DragDrop.module.scss @@ -0,0 +1,25 @@ +.DragDropArea { + position: relative; + min-height: 150px; +} + +.DragDropAreaBorder { + border: dashed grey 1px; + background-color: rgba(255,255,255,.6); + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 1; +} + +.DragDropAreaZone { + position: absolute; + top: 35%; + right: 0; + left: 0; + text-align: center; + color: grey; + font-size: 34px; +} diff --git a/src/controls/listView/ListView.stickyHeader.module.scss b/src/controls/listView/ListView.stickyHeader.module.scss new file mode 100644 index 000000000..61a94b9d6 --- /dev/null +++ b/src/controls/listView/ListView.stickyHeader.module.scss @@ -0,0 +1,10 @@ +.StickyHeader { + :global(.ms-FocusZone) { + max-height: 40vh; + overflow-y: overlay; + overflow-x: hidden; + } + :global(.ms-DetailsHeader) { + overflow-y: hidden; + } +} diff --git a/src/controls/listView/ListView.tsx b/src/controls/listView/ListView.tsx index bdad99afb..b32e36562 100644 --- a/src/controls/listView/ListView.tsx +++ b/src/controls/listView/ListView.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; -import { DetailsList, DetailsListLayoutMode, Selection, SelectionMode, IGroup } from 'office-ui-fabric-react/lib/DetailsList'; +import styles from './ListView.DragDrop.module.scss'; +import stickyHeaderstyles from './ListView.stickyHeader.module.scss'; +import { DetailsList, DetailsListLayoutMode, Selection, SelectionMode, IGroup, IDetailsHeaderProps } from 'office-ui-fabric-react/lib/DetailsList'; import { IListViewProps, IListViewState, IViewField, IGrouping, GroupOrder } from './IListView'; import { IColumn, IGroupRenderProps, IObjectWithKey } from 'office-ui-fabric-react/lib/components/DetailsList'; import { findIndex, has, sortBy, isEqual, cloneDeep } from '@microsoft/sp-lodash-subset'; @@ -7,11 +9,13 @@ import { FileTypeIcon, IconType } from '../fileTypeIcon/index'; import * as strings from 'ControlStrings'; import { IGroupsItems } from './IListView'; import * as telemetry from '../../common/telemetry'; +import { Icon } from 'office-ui-fabric-react/lib/Icon'; import filter from 'lodash/filter'; import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox'; import { Guid } from '@microsoft/sp-core-library'; + /** * File type icon component */ @@ -20,6 +24,8 @@ export class ListView extends React.Component { private originalItems: any[]; private originalGroups: IGroup[]; private originalColumns: IColumn[]; + private dragCounter = 0; + private dropRef = React.createRef(); constructor(props: IListViewProps) { super(props); @@ -35,7 +41,8 @@ export class ListView extends React.Component { // Initialize state this.state = { items: [], - filterValue: this.props.defaultFilter + filterValue: this.props.defaultFilter, + dragStatus: false }; if (this.props.selection) { @@ -54,6 +61,17 @@ export class ListView extends React.Component { this._processProperties(); } + public componentWillUnmount(): void { + const { dragDropFiles } = this.props; + if (dragDropFiles) { + let divDropArea = this.dropRef.current; + divDropArea.removeEventListener('dragenter', this.handleonDragEnter); + divDropArea.removeEventListener('dragleave', this.handleonDragLeave); + divDropArea.removeEventListener('dragover', this.handleonDragOver); + divDropArea.removeEventListener('drop', this.handleonDrop); + } + } + /** * Lifecycle hook when component did update after state or property changes * @param prevProps @@ -175,7 +193,7 @@ export class ListView extends React.Component { * Process all the component properties */ private _processProperties() { - const { items, iconFieldName, viewFields, groupByFields, showFilter } = this.props; + const { dragDropFiles, items, iconFieldName, viewFields, groupByFields, showFilter } = this.props; let tempState: IListViewState = cloneDeep(this.state); let columns: IColumn[] = null; @@ -226,6 +244,15 @@ export class ListView extends React.Component { // Update the current component state with the new values this.setState(tempState); } + + // Add EventListeners for drag zone area + if (dragDropFiles) { + let divDropArea = this.dropRef.current; + divDropArea.addEventListener('dragenter', this.handleonDragEnter); + divDropArea.addEventListener('dragleave', this.handleonDragLeave); + divDropArea.addEventListener('dragover', this.handleonDragOver); + divDropArea.addEventListener('drop', this.handleonDrop); + } } /** @@ -491,14 +518,60 @@ export class ListView extends React.Component { return result; } + /** + * Stop listeners from onDragOver event. + * @param e + */ + private handleonDragOver = (e) => { + e.preventDefault(); + e.stopPropagation(); + } + /** + * Stop listeners from onDragEnter event, enable drag and drop view. + * @param e + */ + private handleonDragEnter = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter++; + if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { + this.setState({ dragStatus: true }); + } + } + /** + * Stop listeners from ondragenter event, disable drag and drop view. + * @param e + */ + private handleonDragLeave = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter--; + if (this.dragCounter === 0) { + this.setState({ dragStatus: false }); + } + } + /** + * Stop listeners from onDrop event and load files to property onDrop. + * @param e + */ + private handleonDrop = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.setState({ dragStatus: false }); + if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { + this.props.onDrop(e.dataTransfer.files); + e.dataTransfer.clearData(); + this.dragCounter = 0; + } + } /** * Default React component render method */ public render(): React.ReactElement { let groupProps: IGroupRenderProps = {}; - let { showFilter, filterPlaceHolder } = this.props; - let { filterValue, items } = this.state; + let { showFilter, filterPlaceHolder, dragDropFiles, stickyHeader, selectionMode, compact } = this.props; + let { filterValue, items, dragStatus, columns, groups } = this.state; // Check if selection mode is single selection, // if that is the case, disable the selection on grouping headers @@ -512,22 +585,37 @@ export class ListView extends React.Component { } return ( -
- { - showFilter && +
+ {(dragStatus && dragDropFiles) && +
+
+ +
{strings.UploadFileHeader}
+
+
} - + { + showFilter && + + } +
); } diff --git a/src/controls/richText/RichText.tsx b/src/controls/richText/RichText.tsx index 535540556..9b14cd6e0 100644 --- a/src/controls/richText/RichText.tsx +++ b/src/controls/richText/RichText.tsx @@ -368,7 +368,7 @@ export class RichText extends React.Component { }} /> { if (newValue !== this.state.insertUrl) { this.setState({ @@ -384,7 +384,7 @@ export class RichText extends React.Component { {strings.RemoveLinkLabel} ) } - +
@@ -568,7 +568,7 @@ id="DropDownStyles" @@ -689,7 +689,7 @@ id="DropDownStyles" } if (cursorPosition > -1) { - const textToInsert: string = this.state.insertUrlText !== undefined ? this.state.insertUrlText : this.state.insertUrl; + const textToInsert: string = (this.state.insertUrlText !== undefined && this.state.insertUrlText !== "") ? this.state.insertUrlText : this.state.insertUrl; const urlToInsert: string = this.state.insertUrl; quill.insertText(cursorPosition, textToInsert); quill.setSelection(cursorPosition, textToInsert.length); @@ -703,6 +703,17 @@ id="DropDownStyles" }); } + /** + * Disable Save-button if hyperlink is undefined or empty + * This prevents the user of adding an empty hyperlink + */ + private checkLinkUrl = () => { + if (this.state.insertUrl !== undefined && this.state.insertUrl != "") { + return false; + } + return true; + } + /** * Applies a format to the selection * @param name format name diff --git a/src/controls/taxonomyPicker/TaxonomyPicker.tsx b/src/controls/taxonomyPicker/TaxonomyPicker.tsx index 31a2c6e5c..c7fa6aade 100644 --- a/src/controls/taxonomyPicker/TaxonomyPicker.tsx +++ b/src/controls/taxonomyPicker/TaxonomyPicker.tsx @@ -74,24 +74,25 @@ export class TaxonomyPicker extends React.Component { + public componentWillReceiveProps(nextProps: ITaxonomyPickerProps) { let newState: ITaxonomyPickerState | undefined; // Check if the initial values objects are not equal, if that is the case, data can be refreshed - if (!isEqual(this.props.initialValues, prevProps.initialValues)) { + if (!isEqual(this.props.initialValues, nextProps.initialValues)) { newState = { - activeNodes: this.props.initialValues || [] + activeNodes: nextProps.initialValues || [] }; } - if (this.props.errorMessage) { + if (nextProps.errorMessage) { if (!newState) { newState = {}; } - newState.errorMessage = this.props.errorMessage; + newState.errorMessage = nextProps.errorMessage; + } + + if (newState) { + this.setState(newState); } } diff --git a/src/controls/treeView/ITreeViewProps.ts b/src/controls/treeView/ITreeViewProps.ts index 45445fe8a..2e72fae7c 100644 --- a/src/controls/treeView/ITreeViewProps.ts +++ b/src/controls/treeView/ITreeViewProps.ts @@ -67,4 +67,9 @@ export interface ITreeViewProps { * @argument item The tree item. */ onRenderItem?: (item: ITreeItem) => JSX.Element; + /** + * Default expand / collapse behavior for the child nodes. + * By default this is set to true. + */ + defaultExpandedChildren?: boolean; } diff --git a/src/controls/treeView/TreeItem.tsx b/src/controls/treeView/TreeItem.tsx index 87096d83f..55559dec7 100644 --- a/src/controls/treeView/TreeItem.tsx +++ b/src/controls/treeView/TreeItem.tsx @@ -61,6 +61,10 @@ export interface ITreeItemProps { onRenderItem?: (item: ITreeItem) => JSX.Element; nodesToExpand: any[]; + /** + * Specifies whether current tree item's children should be rendered as expanded. + */ + defaultExpandedChildren?: boolean; } @@ -217,14 +221,18 @@ export default class TreeItem extends React.Component { return ( { onRenderItem, showCheckboxes, treeItemActionsDisplayMode, - defaultExpanded + defaultExpanded, + defaultExpandedChildren } = this.props; return ( @@ -215,6 +216,7 @@ export class TreeView extends React.Component { leftOffset={20} isFirstRender={true} defaultExpanded={defaultExpanded} + defaultExpandedChildren={defaultExpandedChildren !== undefined ? defaultExpandedChildren : true} selectionMode={selectionMode} activeItems={this.state.activeItems} parentCallbackExpandCollapse={this.handleTreeExpandCollapse} diff --git a/src/services/FluentIconsService.ts b/src/services/FluentIconsService.ts new file mode 100644 index 000000000..69f4174c5 --- /dev/null +++ b/src/services/FluentIconsService.ts @@ -0,0 +1,27 @@ +import Icons from '@uifabric/icons/lib/data/AllIconNames.json'; + +interface IFluentIcon { + name: string; + unicode: string; +} + +const icons: IFluentIcon[] = Icons.slice(1) as IFluentIcon[]; + +export class FluentIconsService { + private _iconNames: string[]; + + constructor() { + this._iconNames = icons.map(icon => icon.name).sort(); + } + + public getAll = (): string[] => { + return this._iconNames; + } + + public search = (query: string, startsWith?: boolean): string[] => { + const lowerCasedQuery = query.toLowerCase(); + return this._iconNames.filter(name => startsWith === false ? name.toLowerCase().indexOf(lowerCasedQuery) !== -1 : name.toLowerCase().indexOf(query) === 0); + } +} + + diff --git a/src/services/FolderExplorerService.ts b/src/services/FolderExplorerService.ts index 0d5a58ccc..823e1aa01 100644 --- a/src/services/FolderExplorerService.ts +++ b/src/services/FolderExplorerService.ts @@ -72,7 +72,7 @@ export class FolderExplorerService implements IFolderExplorerService { try { const web = Web(webAbsoluteUrl); folderRelativeUrl = folderRelativeUrl.replace(/\'/ig, "''"); - let foldersResult: IFolder[] = await web.getFolderByServerRelativeUrl(folderRelativeUrl).folders.select('Name', 'ServerRelativeUrl').orderBy('Name').get(); + let foldersResult: IFolder[] = await web.getFolderByServerRelativePath(encodeURIComponent(folderRelativeUrl)).folders.select('Name', 'ServerRelativeUrl').orderBy('Name').get(); results = foldersResult.filter(f => f.Name != "Forms"); } catch (error) { console.error('Error loading folders', error); @@ -100,7 +100,8 @@ export class FolderExplorerService implements IFolderExplorerService { let folder: IFolder = null; try { const web = Web(webAbsoluteUrl); - let folderAddResult: IFolderAddResult = await web.getFolderByServerRelativeUrl(folderRelativeUrl).folders.add(name); + folderRelativeUrl = folderRelativeUrl.replace(/\'/ig, "''"); + let folderAddResult: IFolderAddResult = await web.getFolderByServerRelativePath(encodeURIComponent(folderRelativeUrl)).folders.addUsingPath(encodeURIComponent(name)); if (folderAddResult && folderAddResult.data) { folder = { Name: folderAddResult.data.Name, diff --git a/src/services/OrgAssetsService.ts b/src/services/OrgAssetsService.ts index e5e7d4259..1bc9cf1e9 100644 --- a/src/services/OrgAssetsService.ts +++ b/src/services/OrgAssetsService.ts @@ -48,19 +48,19 @@ export class OrgAssetsService extends FileBrowserService { public getSiteMediaLibraries = async (includePageLibraries: boolean = false): Promise => { try { - const restApi = `${this.context.pageContext.web.absoluteUrl}/_api/Microsoft.Online.SharePoint.TenantManagement.Office365Tenant/GetOrgAssets`; + const restApi = `${this.context.pageContext.web.absoluteUrl}/_api/SP.Publishing.SitePageService.FilePickerTabOptions`; const orgAssetsResult = await this.context.spHttpClient.get(restApi, SPHttpClient.configurations.v1); if (!orgAssetsResult || !orgAssetsResult.ok) { throw new Error(`Something went wrong when executing request. Status='${orgAssetsResult.status}'`); } const orgAssetsData = await orgAssetsResult.json(); - if (!orgAssetsData || !orgAssetsData.OrgAssetsLibraries || !orgAssetsData.OrgAssetsLibraries.Items || orgAssetsData.OrgAssetsLibraries.Items.length <= 0) { + if (!orgAssetsData || !orgAssetsData.OrgAssets || !orgAssetsData.OrgAssets.OrgAssetsLibraries || !orgAssetsData.OrgAssets.OrgAssetsLibraries.Items || orgAssetsData.OrgAssets.OrgAssetsLibraries.Items.length <= 0) { return null; } - this._orgAssetsLibraryServerRelativeSiteUrl = orgAssetsData ? orgAssetsData.Url.DecodedUrl : null; - const libs: ILibrary[] = orgAssetsData ? orgAssetsData.OrgAssetsLibraries.Items.map((libItem) => { return this._parseOrgAssetsLibraryItem(libItem); }) : []; + this._orgAssetsLibraryServerRelativeSiteUrl = orgAssetsData ? orgAssetsData.OrgAssets.Url.DecodedUrl : null; + const libs: ILibrary[] = orgAssetsData && orgAssetsData.OrgAssets ? orgAssetsData.OrgAssets.OrgAssetsLibraries.Items.map((libItem) => { return this._parseOrgAssetsLibraryItem(libItem); }) : []; return libs; } catch (error) { console.error(`[OrgAssetsService.getOrganisationAssetsLibraries]: Err='${error.message}'`); diff --git a/src/webparts/controlsTest/components/ControlsTest.tsx b/src/webparts/controlsTest/components/ControlsTest.tsx index 02d6d39dd..514cc1de7 100644 --- a/src/webparts/controlsTest/components/ControlsTest.tsx +++ b/src/webparts/controlsTest/components/ControlsTest.tsx @@ -33,7 +33,7 @@ import { TermLabelAction, TermActionsDisplayMode } from '../../../controls/taxon import { ListItemAttachments } from '../../../ListItemAttachments'; import { RichText } from '../../../RichText'; import { Link } from 'office-ui-fabric-react/lib/components/Link'; -import { Carousel, CarouselButtonsLocation, CarouselButtonsDisplay, CarouselIndicatorShape } from '../../../controls/carousel'; +import { Carousel, CarouselButtonsLocation, CarouselButtonsDisplay, CarouselIndicatorShape, CarouselIndicatorsDisplay } from '../../../controls/carousel'; import { TimeDisplayControlType } from '../../../controls/dateTimePicker/TimeDisplayControlType'; import { GridLayout } from '../../../GridLayout'; import { ComboBoxListItemPicker } from '../../../controls/listItemPicker/ComboBoxListItemPicker'; @@ -61,6 +61,7 @@ import { Pagination } from '../../../controls/pagination'; import CarouselImage from '../../../controls/carousel/CarouselImage'; import { FieldCollectionData, CustomCollectionFieldType } from '../../../FieldCollectionData'; import { Accordion } from '../../..'; +import { mergeStyles } from 'office-ui-fabric-react/lib/Styling'; /** * The sample data below was randomly generated (except for the title). It is used by the grid layout @@ -270,7 +271,13 @@ export default class ControlsTest extends React.Component { + for (var i = 0; i < files.length; i++) { + console.log(files[i].name); + } + } + /** * *Method that retrieves the selected terms from the taxonomy picker and sets state @@ -520,6 +538,7 @@ export default class ControlsTest extends React.Component @@ -1085,7 +1107,7 @@ export default class ControlsTest extends React.ComponentComboBoxListItemPicker: - + { this.setState({ + comboBoxListItemPickerListId: '71210430-8436-4962-a14d-5525475abd6b' + }); }} /> +
iframe dialog tester: @@ -1107,7 +1133,15 @@ export default class ControlsTest extends React.Component
@@ -1236,7 +1274,7 @@ export default class ControlsTest extends React.Component { this.setState({ filePickerResult }); }} context={this.props.context} - hideRecentTab={true} + hideRecentTab={false} /> { this.state.filePickerResult && @@ -1298,6 +1336,7 @@ export default class ControlsTest extends React.Component diff --git a/src/webparts/controlsTest/components/ControlsTest_SingleComponent.tsx b/src/webparts/controlsTest/components/ControlsTest_SingleComponent.tsx index 2e09b4d5c..4be61bf09 100644 --- a/src/webparts/controlsTest/components/ControlsTest_SingleComponent.tsx +++ b/src/webparts/controlsTest/components/ControlsTest_SingleComponent.tsx @@ -131,7 +131,8 @@ export default class ControlsTest extends React.Component