diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5a2b714d..a8d69ec1c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
# Releases
+## 1.4.0
+
+**New Controls**
+
+- `SecurityTrimmedControl` control got added [#74](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/74)
+
+**Enhancements**
+
+- Allow the `TaxonomyPicker` to also be used in Application Customizer [#77](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/77)
+- Add `npm postinstall` script to automatically add the locale config [#78](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/78)
+
+**Fixes**
+
+- Icon not showing up in the `Placeholder` control [#76](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/76)
+
## 1.3.0
**New Controls**
diff --git a/docs/documentation/docs/about/release-notes.md b/docs/documentation/docs/about/release-notes.md
index b5a2b714d..a8d69ec1c 100644
--- a/docs/documentation/docs/about/release-notes.md
+++ b/docs/documentation/docs/about/release-notes.md
@@ -1,5 +1,20 @@
# Releases
+## 1.4.0
+
+**New Controls**
+
+- `SecurityTrimmedControl` control got added [#74](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/74)
+
+**Enhancements**
+
+- Allow the `TaxonomyPicker` to also be used in Application Customizer [#77](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/77)
+- Add `npm postinstall` script to automatically add the locale config [#78](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/78)
+
+**Fixes**
+
+- Icon not showing up in the `Placeholder` control [#76](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/76)
+
## 1.3.0
**New Controls**
diff --git a/docs/documentation/docs/assets/ListPicker-initial.png b/docs/documentation/docs/assets/ListPicker-initial.png
new file mode 100644
index 000000000..dc54fda35
Binary files /dev/null and b/docs/documentation/docs/assets/ListPicker-initial.png differ
diff --git a/docs/documentation/docs/assets/ListPicker-multi.png b/docs/documentation/docs/assets/ListPicker-multi.png
new file mode 100644
index 000000000..f0b06ac7d
Binary files /dev/null and b/docs/documentation/docs/assets/ListPicker-multi.png differ
diff --git a/docs/documentation/docs/assets/ListPicker-single.png b/docs/documentation/docs/assets/ListPicker-single.png
new file mode 100644
index 000000000..06d8afddb
Binary files /dev/null and b/docs/documentation/docs/assets/ListPicker-single.png differ
diff --git a/docs/documentation/docs/assets/TermPicker-selection.png b/docs/documentation/docs/assets/termPicker-tree-selection.png
similarity index 100%
rename from docs/documentation/docs/assets/TermPicker-selection.png
rename to docs/documentation/docs/assets/termPicker-tree-selection.png
diff --git a/docs/documentation/docs/assets/TermPicker-autocomplete.png b/docs/documentation/docs/assets/termpicker-input-autocomplete.png
similarity index 100%
rename from docs/documentation/docs/assets/TermPicker-autocomplete.png
rename to docs/documentation/docs/assets/termpicker-input-autocomplete.png
diff --git a/docs/documentation/docs/controls/ListPicker.md b/docs/documentation/docs/controls/ListPicker.md
new file mode 100644
index 000000000..51982ff98
--- /dev/null
+++ b/docs/documentation/docs/controls/ListPicker.md
@@ -0,0 +1,71 @@
+# ListPicker control
+
+This control allows you to select one or multiple available lists/libraries of the current site.
+
+Here is an example of the control:
+
+![ListPicker initial](../assets/ListPicker-initial.png)
+
+`ListPicker` single selection mode:
+
+![ListPicker single selection](../assets/ListPicker-single.png)
+
+`ListPicker` multi-selection mode
+
+![ListPicker multi selection](../assets/ListPicker-multi.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.
+- Import the control into your component:
+
+```TypeScript
+import { ListPicker } from "@pnp/spfx-controls-react/lib/ListPicker";
+```
+
+- Use the `ListPicker` control in your code as follows:
+
+```TypeScript
+
+```
+
+- The `onSelectionChanged` change event returns the list(s) and can be implemented as follows:
+
+```TypeScript
+private onListPickerChange (lists: string | string[]) {
+ console.log("Lists:", lists);
+}
+```
+
+## Implementation
+
+The `ListPicker` control can be configured with the following properties:
+
+| Property | Type | Required | Description |
+| ---- | ---- | ---- | ---- |
+| context | WebPartContext OR ApplicationCustomizerContext | yes | The context object of the SPFx loaded webpart or customizer. |
+| className | string | no | If provided, additional class name to provide on the dropdown element. |
+| disabled | boolean | no | Whether or not the control is disabled. |
+| baseTemplate | number | no | The SharePoint BaseTemplate ID to filter the list options by. |
+| includeHidden | boolean | no | Whether or not to include hidden lists. Default is `true`. |
+| orderBy | LibsOrderBy | no | How to order the lists retrieved from SharePoint. |
+| selectedList | string OR string[] | no | Keys of the selected item(s). If you provide this, you must maintain selection state by observing onSelectionChanged events and passing a new value in when changed. |
+| multiSelect | boolean | no | Optional mode indicates if multi-choice selections is allowed. Default to `false`. |
+| label | string | no | Label to use for the control. |
+| placeholder | string | no | Placeholder label to show in the dropdown. |
+| onSelectionChanged | (newValue: string OR string[]): void | no | Callback function when the selected option changes. |
+
+Enum `LibsOrderBy`
+
+| Value |
+| ---- |
+| Id |
+| Title |
+
+![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/wiki/controls/ListPicker)
diff --git a/docs/documentation/docs/controls/SecurityTrimmedControl.md b/docs/documentation/docs/controls/SecurityTrimmedControl.md
new file mode 100644
index 000000000..a40bed0b5
--- /dev/null
+++ b/docs/documentation/docs/controls/SecurityTrimmedControl.md
@@ -0,0 +1,72 @@
+# SecurityTrimmedControl
+
+This control is intended to be used when you want to show or hide components based on the user its permissions. The control can be used to check the user’s permissions on the current site / list were the solution is loaded, or on a remote site / list.
+
+## 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.
+- Import the following modules to your component:
+
+```TypeScript
+import { SecurityTrimmedControl } from "@pnp/spfx-controls-react/lib/SecurityTrimmedControl";
+```
+
+- You can use the `SecurityTrimmedControl` as follows in your solutions:
+
+**Checking permissions on the current site**
+
+```jsx
+
+ {/* Specify the components to load when user has the required permissions */}
+
+```
+
+**Checking permissions on the current list**
+
+```jsx
+
+ {/* Specify the components to load when user has the required permissions */}
+
+```
+
+**Checking permissions on remote site**
+
+```jsx
+
+ {/* Specify the components to load when user has the required permissions */}
+
+```
+
+**Checking permissions on remote list / library**
+
+```jsx
+
+ {/* Specify the components to load when user has the required permissions */}
+
+```
+
+## Implementation
+
+The `SecurityTrimmedControl` can be configured with the following properties:
+
+| Property | Type | Required | Description |
+| ---- | ---- | ---- | ---- |
+| context | WebPartContext or ApplicationCustomizerContext or FieldCustomizerContext or ListViewCommandSetContext | yes | Context of the web part, application customizer, field customizer, or list view command set. |
+| permissions | SPPermission[] | yes | The permissions to check for the user. |
+| level | PermissionLevel | yes | Specify where to check the user permissions: current site or list / remote site or list. |
+| remoteSiteUrl | string | no | The URL of the remote site. Required when you want to check permissions on remote site or list. |
+| relativeLibOrListUrl | string | no | The relative URL of the list or library. Required when you want to check permissions on remote list. |
+
+
+![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/wiki/controls/SecurityTrimmedControl)
diff --git a/docs/documentation/docs/controls/TaxonomyPicker.md b/docs/documentation/docs/controls/TaxonomyPicker.md
index 8244b5204..50092626e 100644
--- a/docs/documentation/docs/controls/TaxonomyPicker.md
+++ b/docs/documentation/docs/controls/TaxonomyPicker.md
@@ -1,6 +1,6 @@
# Taxonomy Picker
-This control Allows you to select one or more Terms from a TermSet via its name or TermSet ID. You can also configure the control to select the child terms from a specific term in the TermSet by setting the AnchorId.
+This control allows you to select one or more Terms from a TermSet via its name or TermSet ID. You can also configure the control to select the child terms from a specific term in the TermSet by setting the AnchorId.
!!! note "Disclaimer"
This control makes use of the `ProcessQuery` API end-points to retrieve the managed metadata information. This will get changed once the APIs for managing managed metadata will become available.
@@ -11,7 +11,7 @@ This control Allows you to select one or more Terms from a TermSet via its name
**Selecting terms**
-![Selecting terms](../assets/termpicker-selection.png)
+![Selecting terms](../assets/termPicker-tree-selection.png)
**Selected terms in picker**
@@ -19,7 +19,7 @@ This control Allows you to select one or more Terms from a TermSet via its name
**Term picker: Auto Complete**
-![Selected terms in the input](../assets/termpicker-autocomplete.png)
+![Selected terms in the input](../assets/termpicker-input-autocomplete.png)
## How to use this control in your solutions
@@ -36,7 +36,7 @@ import { TaxonomyPicker, IPickerTerms } from "@pnp/spfx-controls-react/lib/Taxon
```TypeScript
=0.10.0"
},
@@ -12,7 +12,8 @@
"prepublishOnly": "gulp",
"versionUpdater": "gulp versionUpdater",
"karma": "karma start --circle true",
- "changelog": "node scripts/sync-changelogs.js"
+ "changelog": "node scripts/sync-changelogs.js",
+ "postinstall": "node postinstall/install.js"
},
"dependencies": {
"@pnp/common": "^1.0.1",
diff --git a/postinstall/install.js b/postinstall/install.js
new file mode 100755
index 000000000..b99f1a825
--- /dev/null
+++ b/postinstall/install.js
@@ -0,0 +1,57 @@
+#!/usr/bin/env node
+
+const fs = require('fs');
+const path = require('path');
+
+console.log("INFO: Adding the required localized resource configuration to the config.json file.");
+
+// Get the current directory
+const crntDir = path.resolve(__dirname);
+// Split the whole directory path
+let nesting = crntDir.split("/");
+// Windows split
+if (nesting.length <= 1) {
+ nesting = crntDir.split("\\");
+}
+// Check if correctly splitted
+if (nesting.length > 0) {
+ // Find the first node_modules folder index
+ let idx = nesting.indexOf("node_modules");
+ // Check if index of the folder was found
+ if (idx !== -1) {
+ // Slice unnecessary nodes
+ const nest = nesting.slice(idx);
+ if (nest && nest.length > 0) {
+ const paths = nest.map(m => "..");
+ // Get the path of the projects root location
+ const rootDir = path.resolve(path.join(__dirname, paths.join('/')));
+ const fileLoc = `${rootDir}/config/config.json`;
+ // Check if config.json file exists
+ if (fs.existsSync(fileLoc)) {
+ // Get the config file
+ const config = fs.readFileSync(fileLoc, "utf8");
+ if (config && typeof config === "string") {
+ const contents = JSON.parse(config);
+ if (contents && contents.localizedResources && !contents.localizedResources.ControlStrings) {
+ contents.localizedResources["ControlStrings"] = "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js";
+ // Update the file
+ fs.writeFileSync(fileLoc, JSON.stringify(contents, null, 2));
+ console.log("INFO: Localized resource added.");
+ } else {
+ console.warn(`WARNING: it seems something is wrong with the config.json file or the "ControlStrings" reference was already set.`);
+ }
+ } else {
+ console.warn("WARNING: the config.json file was not correctly retrieved.");
+ }
+ } else {
+ console.warn("WARNING: the config.json file does not exist.");
+ }
+ } else {
+ console.warn("WARNING: something is wrong with the installation path.");
+ }
+ } else {
+ console.warn("WARNING: something when wrong during with retrieving the project its root location.");
+ }
+} else {
+ console.warn("WARNING: something is wrong with the installation path.");
+}
diff --git a/src/SecurityTrimmedControl.ts b/src/SecurityTrimmedControl.ts
new file mode 100644
index 000000000..2083f23e4
--- /dev/null
+++ b/src/SecurityTrimmedControl.ts
@@ -0,0 +1 @@
+export * from './controls/securityTrimmedControl';
diff --git a/src/controls/fields/fieldUserRenderer/FieldUserRenderer.tsx b/src/controls/fields/fieldUserRenderer/FieldUserRenderer.tsx
index a9bd7ee8b..b897036f9 100644
--- a/src/controls/fields/fieldUserRenderer/FieldUserRenderer.tsx
+++ b/src/controls/fields/fieldUserRenderer/FieldUserRenderer.tsx
@@ -171,7 +171,7 @@ export class FieldUserRenderer extends React.Component
-
{strings.Contact}
+
{strings.Contact}
{user.email}
diff --git a/src/controls/placeholder/PlaceholderComponent.tsx b/src/controls/placeholder/PlaceholderComponent.tsx
index 8225bc5ce..6456a09a6 100644
--- a/src/controls/placeholder/PlaceholderComponent.tsx
+++ b/src/controls/placeholder/PlaceholderComponent.tsx
@@ -4,6 +4,7 @@ import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import styles from './PlaceholderComponent.module.scss';
import * as appInsights from '../../common/appInsights';
import { IPlaceholderState } from '.';
+import { Icon } from 'office-ui-fabric-react/lib/components/Icon';
/**
* Placeholder component
@@ -83,15 +84,13 @@ export class Placeholder extends React.Component {
- const iconName = typeof this.props.iconName !== 'undefined' && this.props.iconName !== null ? `ms-Icon--${this.props.iconName}` : '';
-
return (